|
@ -3,14 +3,14 @@ dist: xenial
|
|||
group: edge
|
||||
|
||||
language: node_js
|
||||
node_js: stable
|
||||
node_js: 11
|
||||
|
||||
before_cache:
|
||||
- rm -rf $HOME/.cache/electron-builder/wine
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.npm
|
||||
- $HOME/.cache/electron
|
||||
- $HOME/.cache/electron-builder
|
||||
|
||||
|
|
|
@ -11,15 +11,15 @@ EXPOSE 35729
|
|||
# Port 53703 is the Chrome dev logger port.
|
||||
EXPOSE 53703
|
||||
|
||||
# MoodleMobile uses Cordova, Ionic, and Gulp.
|
||||
RUN npm install -g cordova ionic gulp && rm -rf /root/.npm
|
||||
# MoodleMobile uses Ionic and Gulp.
|
||||
RUN npm i -g ionic gulp && rm -rf /root/.npm
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . /app
|
||||
|
||||
# The setup script will handle npm installation, cordova setup, and gulp setup.
|
||||
RUN npm run setup && rm -rf /root/.npm
|
||||
# Install npm libraries and run gulp to initialize the project.
|
||||
RUN npm install && gulp && rm -rf /root/.npm
|
||||
|
||||
# Provide a Healthcheck command for easier use in CI.
|
||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=30s CMD curl -f http://localhost:8100 || exit 1
|
||||
|
|
21
config.xml
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="com.moodle.moodlemobile" version="3.6.1" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<widget id="com.moodle.moodlemobile" version="3.7.0" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>Moodle</name>
|
||||
<description>Moodle official app</description>
|
||||
<author email="mobile@moodle.com" href="http://moodle.com">Moodle Mobile team</author>
|
||||
|
@ -37,6 +37,7 @@
|
|||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="LoadUrlTimeoutValue" value="60000" />
|
||||
<preference name="CustomURLSchemePluginClearsAndroidIntent" value="true" />
|
||||
<feature name="StatusBar">
|
||||
<param name="ios-package" onload="true" value="CDVStatusBar" />
|
||||
</feature>
|
||||
|
@ -112,14 +113,14 @@
|
|||
<icon height="1024" src="resources/ios/icon/icon-1024.png" width="1024" />
|
||||
<splash height="2732" src="resources/ios/splash/Default@2x~universal~anyany.png" width="2732" />
|
||||
</platform>
|
||||
<plugin name="com-darryncampbell-cordova-plugin-intent" spec="1.1.5" />
|
||||
<plugin name="cordova-android-support-gradle-release" spec="2.0.1">
|
||||
<plugin name="com-darryncampbell-cordova-plugin-intent" spec="1.1.7" />
|
||||
<plugin name="cordova-android-support-gradle-release" spec="3.0.0">
|
||||
<variable name="ANDROID_SUPPORT_VERSION" value="27.1.0" />
|
||||
</plugin>
|
||||
<plugin name="cordova-clipboard" spec="1.2.1" />
|
||||
<plugin name="cordova-plugin-badge" spec="0.8.8" />
|
||||
<plugin name="cordova-plugin-camera" spec="4.0.3" />
|
||||
<plugin name="cordova-plugin-customurlscheme" spec="4.3.0">
|
||||
<plugin name="cordova-plugin-customurlscheme" spec="4.4.0">
|
||||
<variable name="URL_SCHEME" value="moodlemobile" />
|
||||
</plugin>
|
||||
<plugin name="cordova-plugin-device" spec="2.0.2" />
|
||||
|
@ -129,7 +130,7 @@
|
|||
<plugin name="cordova-plugin-globalization" spec="1.11.0" />
|
||||
<plugin name="cordova-plugin-inappbrowser" spec="3.0.0" />
|
||||
<plugin name="cordova-plugin-ionic-keyboard" spec="2.1.3" />
|
||||
<plugin name="cordova-plugin-local-notification" spec="0.9.0-beta.3" />
|
||||
<plugin name="cordova-plugin-local-notification" spec="https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle" />
|
||||
<plugin name="cordova-plugin-media-capture" spec="3.0.2" />
|
||||
<plugin name="cordova-plugin-network-information" spec="2.0.1" />
|
||||
<plugin name="cordova-plugin-screen-orientation" spec="3.0.1" />
|
||||
|
@ -139,13 +140,19 @@
|
|||
<plugin name="cordova-plugin-zip" spec="3.1.0" />
|
||||
<plugin name="cordova-sqlite-storage" spec="2.6.0" />
|
||||
<plugin name="nl.kingsquare.cordova.background-audio" spec="1.0.1" />
|
||||
<plugin name="phonegap-plugin-push" spec="https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v2">
|
||||
<plugin name="phonegap-plugin-push" spec="https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3">
|
||||
<variable name="ANDROID_SUPPORT_V13_VERSION" value="27.+" />
|
||||
<variable name="FCM_VERSION" value="17.0.+" />
|
||||
<variable name="FCM_VERSION" value="17.5.+" />
|
||||
</plugin>
|
||||
<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application/activity[@android:name='MainActivity']">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|screenLayout|smallestScreenSize" android:debuggable="true" />
|
||||
</edit-config>
|
||||
<config-file parent="/manifest/application" target="AndroidManifest.xml">
|
||||
<meta-data android:name="firebase_analytics_collection_deactivated" android:value="true" />
|
||||
</config-file>
|
||||
<config-file parent="FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED" target="*-Info.plist">
|
||||
<string>YES</string>
|
||||
</config-file>
|
||||
<engine name="android" spec="7.1.2" />
|
||||
<engine name="ios" spec="4.5.5" />
|
||||
</widget>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<Identity Name="3312ADB7.MoodleDesktop"
|
||||
ProcessorArchitecture="x64"
|
||||
Publisher="CN=33CDCDF6-1EB5-4827-9897-ED25C91A32F6"
|
||||
Version="3.6.1.0" />
|
||||
Version="3.7.0.0" />
|
||||
<Properties>
|
||||
<DisplayName>Moodle Desktop</DisplayName>
|
||||
<PublisherDisplayName>Moodle Pty Ltd.</PublisherDisplayName>
|
||||
|
|
|
@ -6,6 +6,7 @@ const url = require('url');
|
|||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const userAgent = 'MoodleMobile';
|
||||
const isMac = os.platform().indexOf('darwin') != -1;
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
|
@ -68,6 +69,14 @@ function createWindow() {
|
|||
|
||||
// Append some text to the user agent.
|
||||
mainWindow.webContents.setUserAgent(mainWindow.webContents.getUserAgent() + ' ' + userAgent);
|
||||
|
||||
// Add shortcut to open dev tools: Cmd + Option + I in MacOS, Ctrl + Shift + I in Windows/Linux.
|
||||
mainWindow.webContents.on('before-input-event', function(e, input) {
|
||||
if (input.type == 'keyDown' && !input.isAutoRepeat && input.code == 'KeyI' &&
|
||||
((isMac && input.alt && input.meta) || (!isMac && input.shift && input.control))) {
|
||||
mainWindow.webContents.toggleDevTools();
|
||||
}
|
||||
}, true)
|
||||
}
|
||||
|
||||
// Make sure that only a single instance of the app is running.
|
||||
|
@ -75,7 +84,7 @@ function createWindow() {
|
|||
// See https://github.com/electron/electron/issues/15958
|
||||
var gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
if (!gotTheLock && os.platform().indexOf('darwin') == -1) {
|
||||
if (!gotTheLock && !isMac) {
|
||||
// It's not the main instance of the app, kill it.
|
||||
app.exit();
|
||||
return;
|
||||
|
@ -221,22 +230,18 @@ function setAppMenu() {
|
|||
submenu: [
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'CmdOrCtrl+X',
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'CmdOrCtrl+C',
|
||||
role: 'copy'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'CmdOrCtrl+V',
|
||||
role: 'paste'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'CmdOrCtrl+A',
|
||||
role: 'selectall'
|
||||
}
|
||||
]
|
||||
|
|
132
gulpfile.js
|
@ -8,6 +8,8 @@ var gulp = require('gulp'),
|
|||
gutil = require('gulp-util'),
|
||||
flatten = require('gulp-flatten'),
|
||||
npmPath = require('path'),
|
||||
concat = require('gulp-concat'),
|
||||
bufferFrom = require('buffer-from')
|
||||
File = gutil.File,
|
||||
exec = require('child_process').exec,
|
||||
license = '' +
|
||||
|
@ -113,7 +115,7 @@ function treatMergedData(data) {
|
|||
mergedOrdered[k] = merged[k];
|
||||
});
|
||||
|
||||
return new Buffer(JSON.stringify(mergedOrdered, null, 4));
|
||||
return bufferFrom(JSON.stringify(mergedOrdered, null, 4));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,7 +259,7 @@ gulp.task('config', function(done) {
|
|||
|
||||
contents += '}\n';
|
||||
|
||||
file.contents = new Buffer(contents);
|
||||
file.contents = bufferFrom(contents);
|
||||
this.emit('data', file);
|
||||
}))
|
||||
.pipe(rename('configconstants.ts'))
|
||||
|
@ -296,3 +298,129 @@ gulp.task('copy-component-templates', function(done) {
|
|||
.on('end', done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the file and returns its content.
|
||||
*
|
||||
* @param {string} capture Import file path.
|
||||
* @param {string} baseDir Directory where the file was found.
|
||||
* @param {string} paths Alternative paths where to find the imports.
|
||||
* @param {Array} parsedFiles Yet parsed files to reduce size of the result.
|
||||
* @return {string} Partially combined scss.
|
||||
*/
|
||||
function getReplace(capture, baseDir, paths, parsedFiles) {
|
||||
var parse = path.parse(path.resolve(baseDir, capture + '.scss'));
|
||||
var file = parse.dir + '/' + parse.name;
|
||||
|
||||
|
||||
if (!fs.existsSync(file + '.scss')) {
|
||||
// File not found, might be a partial file.
|
||||
file = parse.dir + '/_' + parse.name;
|
||||
}
|
||||
|
||||
// If file still not found, try to find the file in the alternative paths.
|
||||
var x = 0;
|
||||
while (!fs.existsSync(file + '.scss') && paths.length > x) {
|
||||
parse = path.parse(path.resolve(paths[x], capture + '.scss'));
|
||||
file = parse.dir + '/' + parse.name;
|
||||
|
||||
x++;
|
||||
}
|
||||
|
||||
file = file + '.scss';
|
||||
|
||||
if (!fs.existsSync(file)) {
|
||||
// File not found. Leave the import there.
|
||||
console.log('File "' + capture + '" not found');
|
||||
return '@import "' + capture + '";';
|
||||
}
|
||||
|
||||
if (parsedFiles.indexOf(file) >= 0) {
|
||||
console.log('File "' + capture + '" already parsed');
|
||||
// File was already parsed, leave the import commented.
|
||||
return '// @import "' + capture + '";';
|
||||
}
|
||||
|
||||
parsedFiles.push(file);
|
||||
var text = fs.readFileSync(file);
|
||||
|
||||
// Recursive call.
|
||||
return scssCombine(text, parse.dir, paths, parsedFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine scss files with its imports
|
||||
*
|
||||
* @param {string} content Scss string to read.
|
||||
* @param {string} baseDir Directory where the file was found.
|
||||
* @param {string} paths Alternative paths where to find the imports.
|
||||
* @param {Array} parsedFiles Yet parsed files to reduce size of the result.
|
||||
* @return {string} Scss string with the replaces done.
|
||||
*/
|
||||
function scssCombine(content, baseDir, paths, parsedFiles) {
|
||||
|
||||
// Content is a Buffer, convert to string.
|
||||
if (typeof content != "string") {
|
||||
content = content.toString();
|
||||
}
|
||||
|
||||
// Search of single imports.
|
||||
var regex = /@import[ ]*['"](.*)['"][ ]*;/g;
|
||||
|
||||
if (regex.test(content)) {
|
||||
return content.replace(regex, function(m, capture) {
|
||||
if (capture == "bmma") {
|
||||
return m;
|
||||
}
|
||||
|
||||
return getReplace(capture, baseDir, paths, parsedFiles);
|
||||
});
|
||||
}
|
||||
|
||||
// Search of multiple imports.
|
||||
regex = /@import(?:[ \n]+['"](.*)['"][,]?[ \n]*)+;/gm;
|
||||
if (regex.test(content)) {
|
||||
return content.replace(regex, function(m, capture) {
|
||||
var text = "";
|
||||
|
||||
// Divide the import into multiple files.
|
||||
regex = /['"]([^'"]*)['"]/g;
|
||||
var captures = m.match(regex);
|
||||
for (var x in captures) {
|
||||
text += getReplace(captures[x].replace(/['"]+/g, ''), baseDir, paths, parsedFiles) + "\n";
|
||||
}
|
||||
|
||||
return text;
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
gulp.task('combine-scss', function(done) {
|
||||
var paths = [
|
||||
'node_modules/ionic-angular/themes/',
|
||||
'node_modules/font-awesome/scss/',
|
||||
'node_modules/ionicons/dist/scss/'
|
||||
];
|
||||
|
||||
var parsedFiles = [];
|
||||
|
||||
gulp.src([
|
||||
'./src/theme/variables.scss',
|
||||
'./node_modules/ionic-angular/themes/ionic.globals.*.scss',
|
||||
'./node_modules/ionic-angular/themes/ionic.components.scss',
|
||||
'./src/**/*.scss']) // define a source files
|
||||
.pipe(through(function(file, encoding, callback) {
|
||||
if (file.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parsedFiles.push(file);
|
||||
file.contents = bufferFrom(scssCombine(file.contents, path.dirname(file.path), paths, parsedFiles));
|
||||
|
||||
this.emit('data', file);
|
||||
})) // combine them based on @import and save it to stream
|
||||
.pipe(concat('combined.scss')) // concat the stream output in single file
|
||||
.pipe(gulp.dest('.')) // save file to destination.
|
||||
.on('end', done);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "moodlemobile",
|
||||
"version": "3.6.1",
|
||||
"version": "3.7.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -2473,9 +2473,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"com-darryncampbell-cordova-plugin-intent": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/com-darryncampbell-cordova-plugin-intent/-/com-darryncampbell-cordova-plugin-intent-1.1.1.tgz",
|
||||
"integrity": "sha512-h+V54+qCFY1h5csX8lAKTxBn5DdbP/8/sm7vS6X0WZPI+OTKycxeoJC+oGtPHhlvTh4gSEVW5/MkDqANRcmaug=="
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/com-darryncampbell-cordova-plugin-intent/-/com-darryncampbell-cordova-plugin-intent-1.1.7.tgz",
|
||||
"integrity": "sha512-e+CIaOTpZ7r178tmCijZcm/o5nJIWVnQaUrwm5xwX1zc5zutVCtz1oH3xqq6gzNk05C9i7n96xdenODHMYpiMw=="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.6",
|
||||
|
@ -2521,6 +2521,15 @@
|
|||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"concat-with-sourcemaps": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
|
||||
"integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
|
||||
|
@ -2808,18 +2817,18 @@
|
|||
}
|
||||
},
|
||||
"cordova-android-support-gradle-release": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cordova-android-support-gradle-release/-/cordova-android-support-gradle-release-2.0.1.tgz",
|
||||
"integrity": "sha512-HlX75PN8b9y3LIlAFLQspSbO7dr7hTRi2/n4A2Hz4AHb7NxiVt6VU+6j+JcseDveVdddh1sKMZd0xPtFMVNjXA==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cordova-android-support-gradle-release/-/cordova-android-support-gradle-release-3.0.0.tgz",
|
||||
"integrity": "sha512-vyiqQ6N9Qb+4xRizWSpUX/LyJ1HaDN0piWc8xoS9Hx9YodIS3vyi1UpQyfLQmCixoeLVcRieKXjuSMXnUrv1dw==",
|
||||
"requires": {
|
||||
"semver": "5.1.0",
|
||||
"xml2js": "~0.4.19"
|
||||
"q": "^1.4.1",
|
||||
"semver": "5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "http://registry.npmjs.org/semver/-/semver-5.1.0.tgz",
|
||||
"integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU="
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3173,9 +3182,8 @@
|
|||
"integrity": "sha512-6ucQ6FdlLdBm8kJfFnzozmBTjru/0xekHP/dAhjoCZggkGRlgs8TsUJFkxa/bV+qi7Dlo50JjmpE4UMWAO+aOQ=="
|
||||
},
|
||||
"cordova-plugin-local-notification": {
|
||||
"version": "0.9.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-local-notification/-/cordova-plugin-local-notification-0.9.0-beta.3.tgz",
|
||||
"integrity": "sha512-L3Z1velxrkm9nHFcvLnMgBPZjKFt6hwM6hn1lA+JFwIR26Yw6UF72z+/lRMBclAcOxBIDYCqeaLgvezmajjuEg=="
|
||||
"version": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#5b2f3073a1c1fb39cad3566be792445c343db2c6",
|
||||
"from": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle"
|
||||
},
|
||||
"cordova-plugin-media-capture": {
|
||||
"version": "3.0.2",
|
||||
|
@ -4082,9 +4090,9 @@
|
|||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"esrecurse": {
|
||||
|
@ -5253,9 +5261,9 @@
|
|||
}
|
||||
},
|
||||
"fstream": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
|
||||
"integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
|
||||
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
|
@ -5870,6 +5878,17 @@
|
|||
"through2": "~2.0.1"
|
||||
}
|
||||
},
|
||||
"gulp-concat": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
|
||||
"integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"concat-with-sourcemaps": "^1.0.0",
|
||||
"through2": "^2.0.0",
|
||||
"vinyl": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"gulp-flatten": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-flatten/-/gulp-flatten-0.4.0.tgz",
|
||||
|
@ -6672,9 +6691,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
|
@ -8560,7 +8579,7 @@
|
|||
},
|
||||
"pegjs": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "http://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
|
||||
"integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0="
|
||||
},
|
||||
"performance-now": {
|
||||
|
@ -8575,8 +8594,8 @@
|
|||
"integrity": "sha512-1wvc3iQOQpEBaQbXgLxA2JUiLSQ2azdF/bF29ghXDiQJWSpQ1BF8gSuqttM8WZoj081Ps8OKL0gYxdDBkFNPqA=="
|
||||
},
|
||||
"phonegap-plugin-push": {
|
||||
"version": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#9b1d9fe575d1f21b517327c480e7fe0f73280e7a",
|
||||
"from": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v2",
|
||||
"version": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#cf8101e86adb774ae1d7ad6b65fb9d8802673f4b",
|
||||
"from": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3",
|
||||
"requires": {
|
||||
"babel-plugin-add-header-comment": "^1.0.3",
|
||||
"install": "^0.8.2"
|
||||
|
@ -8796,6 +8815,11 @@
|
|||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
},
|
||||
"q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
|
@ -9588,7 +9612,8 @@
|
|||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"scss-tokenizer": {
|
||||
"version": "0.2.3",
|
||||
|
@ -10179,14 +10204,28 @@
|
|||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
|
||||
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
|
||||
"integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"block-stream": "*",
|
||||
"fstream": "^1.0.2",
|
||||
"fstream": "^1.0.12",
|
||||
"inherits": "2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fstream": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
|
||||
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"inherits": "~2.0.0",
|
||||
"mkdirp": ">=0.5 0",
|
||||
"rimraf": "2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"temp-file": {
|
||||
|
@ -12174,6 +12213,7 @@
|
|||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
|
@ -12182,7 +12222,8 @@
|
|||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
|
||||
"dev": true
|
||||
},
|
||||
"xmldom": {
|
||||
"version": "0.1.27",
|
||||
|
|
15
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "moodlemobile",
|
||||
"version": "3.6.1",
|
||||
"version": "3.7.0",
|
||||
"description": "The official app for Moodle.",
|
||||
"author": {
|
||||
"name": "Moodle Pty Ltd.",
|
||||
|
@ -28,6 +28,7 @@
|
|||
"build": "ionic-app-scripts build",
|
||||
"lint": "ionic-app-scripts lint",
|
||||
"ionic:build": "node --max-old-space-size=16384 ./node_modules/@ionic/app-scripts/bin/ionic-app-scripts.js build",
|
||||
"ionic:serve:before": "gulp",
|
||||
"ionic:serve": "gulp watch | ionic-app-scripts serve",
|
||||
"ionic:build:before": "gulp",
|
||||
"ionic:watch:before": "gulp",
|
||||
|
@ -78,9 +79,9 @@
|
|||
"@types/node": "8.10.19",
|
||||
"@types/promise.prototype.finally": "2.0.2",
|
||||
"chart.js": "2.7.2",
|
||||
"com-darryncampbell-cordova-plugin-intent": "1.1.1",
|
||||
"com-darryncampbell-cordova-plugin-intent": "1.1.7",
|
||||
"cordova-android": "7.1.2",
|
||||
"cordova-android-support-gradle-release": "2.0.1",
|
||||
"cordova-android-support-gradle-release": "3.0.0",
|
||||
"cordova-clipboard": "1.2.1",
|
||||
"cordova-ios": "4.5.5",
|
||||
"cordova-plugin-badge": "0.8.8",
|
||||
|
@ -93,7 +94,7 @@
|
|||
"cordova-plugin-globalization": "1.11.0",
|
||||
"cordova-plugin-inappbrowser": "3.0.0",
|
||||
"cordova-plugin-ionic-keyboard": "2.1.3",
|
||||
"cordova-plugin-local-notification": "0.9.0-beta.3",
|
||||
"cordova-plugin-local-notification": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle",
|
||||
"cordova-plugin-media-capture": "3.0.2",
|
||||
"cordova-plugin-network-information": "2.0.1",
|
||||
"cordova-plugin-screen-orientation": "3.0.1",
|
||||
|
@ -111,7 +112,7 @@
|
|||
"moment": "2.22.2",
|
||||
"nl.kingsquare.cordova.background-audio": "1.0.1",
|
||||
"phonegap-plugin-multidex": "1.0.0",
|
||||
"phonegap-plugin-push": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v2",
|
||||
"phonegap-plugin-push": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3",
|
||||
"promise.prototype.finally": "3.1.0",
|
||||
"rxjs": "5.5.11",
|
||||
"sw-toolbox": "3.6.0",
|
||||
|
@ -125,6 +126,7 @@
|
|||
"electron-rebuild": "1.8.1",
|
||||
"gulp": "4.0.0",
|
||||
"gulp-clip-empty-files": "0.1.2",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-flatten": "0.4.0",
|
||||
"gulp-rename": "1.3.0",
|
||||
"gulp-slash": "1.1.3",
|
||||
|
@ -227,6 +229,9 @@
|
|||
},
|
||||
"snap": {
|
||||
"confinement": "classic"
|
||||
},
|
||||
"nsis": {
|
||||
"deleteAppDataOnUninstall": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1 +1 @@
|
|||
35bf4a4bbe8ec8e40270338abd041adc
|
||||
5e8ac0ef8768e0fad3284434d24064f8
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 932 B |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 18 KiB |
|
@ -1 +1 @@
|
|||
3ac2bf0bded2c5da7d213095c12ead29
|
||||
5225afcaf865b3e218501903bef688e0
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 55 KiB |
|
@ -1 +1 @@
|
|||
32dca3a9cd3c8e9d241f68a0850d2ace
|
||||
4d2128e5cc9659b321956c1178057980
|
|
@ -6,7 +6,7 @@ if [ $TRAVIS_BRANCH == 'integration' ] || [ $TRAVIS_BRANCH == 'master' ] || [ $T
|
|||
./build_lang.sh
|
||||
cd ..
|
||||
|
||||
if [ $TRAVIS_BRANCH == 'master' ] && [ ! -z $GIT_TOKEN ] ; then
|
||||
if [ "$TRAVIS_BRANCH" == 'master' ] && [ ! -z $GIT_TOKEN ] ; then
|
||||
git remote set-url origin https://$GIT_TOKEN@github.com/$TRAVIS_REPO_SLUG.git
|
||||
git fetch -q origin
|
||||
git add src/assets/lang
|
||||
|
@ -17,7 +17,7 @@ if [ $TRAVIS_BRANCH == 'integration' ] || [ $TRAVIS_BRANCH == 'master' ] || [ $T
|
|||
version=`grep versionname src/config.json| cut -d: -f2|cut -d'"' -f2`
|
||||
date=`date +%Y%m%d`'00'
|
||||
|
||||
pushd ../../moodle-local_moodlemobileapp
|
||||
pushd ../moodle-local_moodlemobileapp
|
||||
sed -ie "s/release[ ]*=[ ]*'[^']*';/release = '$version';/1" version.php
|
||||
sed -ie "s/version[ ]*=[ ]*[0-9]*;/version = $date;/1" version.php
|
||||
rm version.phpe
|
||||
|
|
|
@ -111,9 +111,11 @@
|
|||
"addon.competency.myplans": "tool_lp",
|
||||
"addon.competency.noactivities": "tool_lp",
|
||||
"addon.competency.nocompetencies": "local_moodlemobileapp",
|
||||
"addon.competency.nocompetenciesincourse": "tool_lp",
|
||||
"addon.competency.nocrossreferencedcompetencies": "tool_lp",
|
||||
"addon.competency.noevidence": "tool_lp",
|
||||
"addon.competency.noplanswerecreated": "tool_lp",
|
||||
"addon.competency.nouserplanswithcompetency": "competency",
|
||||
"addon.competency.path": "tool_lp",
|
||||
"addon.competency.planstatusactive": "competency",
|
||||
"addon.competency.planstatuscomplete": "competency",
|
||||
|
@ -126,6 +128,7 @@
|
|||
"addon.competency.reviewstatus": "tool_lp",
|
||||
"addon.competency.status": "tool_lp",
|
||||
"addon.competency.template": "tool_lp",
|
||||
"addon.competency.uponcoursecompletion": "tool_lp",
|
||||
"addon.competency.usercompetencystatus_idle": "competency",
|
||||
"addon.competency.usercompetencystatus_inreview": "competency",
|
||||
"addon.competency.usercompetencystatus_waitingforreview": "competency",
|
||||
|
@ -177,9 +180,12 @@
|
|||
"addon.messages.contactname": "local_moodlemobileapp",
|
||||
"addon.messages.contactrequestsent": "message",
|
||||
"addon.messages.contacts": "message",
|
||||
"addon.messages.conversationactions": "message",
|
||||
"addon.messages.decline": "message",
|
||||
"addon.messages.deleteallconfirm": "message",
|
||||
"addon.messages.deleteallselfconfirm": "message",
|
||||
"addon.messages.deleteconversation": "message",
|
||||
"addon.messages.deleteforeveryone": "message",
|
||||
"addon.messages.deletemessage": "local_moodlemobileapp",
|
||||
"addon.messages.deletemessageconfirmation": "local_moodlemobileapp",
|
||||
"addon.messages.errordeletemessage": "local_moodlemobileapp",
|
||||
|
@ -196,6 +202,8 @@
|
|||
"addon.messages.messagenotsent": "local_moodlemobileapp",
|
||||
"addon.messages.messagepreferences": "message",
|
||||
"addon.messages.messages": "message",
|
||||
"addon.messages.muteconversation": "message",
|
||||
"addon.messages.mutedconversation": "message",
|
||||
"addon.messages.newmessage": "message",
|
||||
"addon.messages.newmessages": "local_moodlemobileapp",
|
||||
"addon.messages.nocontactrequests": "message",
|
||||
|
@ -214,9 +222,8 @@
|
|||
"addon.messages.requests": "moodle",
|
||||
"addon.messages.requirecontacttomessage": "message",
|
||||
"addon.messages.searchcombined": "message",
|
||||
"addon.messages.searchnocontactsfound": "message",
|
||||
"addon.messages.searchnomessagesfound": "message",
|
||||
"addon.messages.searchnononcontactsfound": "message",
|
||||
"addon.messages.selfconversation": "message",
|
||||
"addon.messages.selfconversationdefaultmessage": "message",
|
||||
"addon.messages.sendcontactrequest": "message",
|
||||
"addon.messages.showdeletemessages": "local_moodlemobileapp",
|
||||
"addon.messages.type_blocked": "local_moodlemobileapp",
|
||||
|
@ -227,6 +234,7 @@
|
|||
"addon.messages.unabletomessage": "message",
|
||||
"addon.messages.unblockuser": "message",
|
||||
"addon.messages.unblockuserconfirm": "message",
|
||||
"addon.messages.unmuteconversation": "message",
|
||||
"addon.messages.useentertosend": "message",
|
||||
"addon.messages.useentertosenddescdesktop": "local_moodlemobileapp",
|
||||
"addon.messages.useentertosenddescmac": "local_moodlemobileapp",
|
||||
|
@ -448,6 +456,8 @@
|
|||
"addon.mod_feedback.feedbackclose": "feedback",
|
||||
"addon.mod_feedback.feedbackopen": "feedback",
|
||||
"addon.mod_feedback.mapcourses": "feedback",
|
||||
"addon.mod_feedback.maximal": "feedback",
|
||||
"addon.mod_feedback.minimal": "feedback",
|
||||
"addon.mod_feedback.mode": "feedback",
|
||||
"addon.mod_feedback.modulenameplural": "feedback",
|
||||
"addon.mod_feedback.next_page": "feedback",
|
||||
|
@ -474,11 +484,20 @@
|
|||
"addon.mod_forum.addanewdiscussion": "forum",
|
||||
"addon.mod_forum.addanewquestion": "forum",
|
||||
"addon.mod_forum.addanewtopic": "forum",
|
||||
"addon.mod_forum.addtofavourites": "forum",
|
||||
"addon.mod_forum.advanced": "moodle",
|
||||
"addon.mod_forum.cannotadddiscussion": "forum",
|
||||
"addon.mod_forum.cannotadddiscussionall": "forum",
|
||||
"addon.mod_forum.cannotcreatediscussion": "forum",
|
||||
"addon.mod_forum.couldnotadd": "forum",
|
||||
"addon.mod_forum.cutoffdatereached": "forum",
|
||||
"addon.mod_forum.discussion": "forum",
|
||||
"addon.mod_forum.discussionlistsortbycreatedasc": "forum",
|
||||
"addon.mod_forum.discussionlistsortbycreateddesc": "forum",
|
||||
"addon.mod_forum.discussionlistsortbylastpostasc": "forum",
|
||||
"addon.mod_forum.discussionlistsortbylastpostdesc": "forum",
|
||||
"addon.mod_forum.discussionlistsortbyrepliesasc": "forum",
|
||||
"addon.mod_forum.discussionlistsortbyrepliesdesc": "forum",
|
||||
"addon.mod_forum.discussionlocked": "forum",
|
||||
"addon.mod_forum.discussionpinned": "forum",
|
||||
"addon.mod_forum.discussionsubscription": "forum",
|
||||
|
@ -487,8 +506,12 @@
|
|||
"addon.mod_forum.erroremptysubject": "forum",
|
||||
"addon.mod_forum.errorgetforum": "local_moodlemobileapp",
|
||||
"addon.mod_forum.errorgetgroups": "local_moodlemobileapp",
|
||||
"addon.mod_forum.errorposttoallgroups": "local_moodlemobileapp",
|
||||
"addon.mod_forum.favouriteupdated": "forum",
|
||||
"addon.mod_forum.forumnodiscussionsyet": "local_moodlemobileapp",
|
||||
"addon.mod_forum.group": "local_moodlemobileapp",
|
||||
"addon.mod_forum.lockdiscussion": "forum",
|
||||
"addon.mod_forum.lockupdated": "forum",
|
||||
"addon.mod_forum.message": "forum",
|
||||
"addon.mod_forum.modeflatnewestfirst": "forum",
|
||||
"addon.mod_forum.modeflatoldestfirst": "forum",
|
||||
|
@ -496,12 +519,23 @@
|
|||
"addon.mod_forum.modulenameplural": "forum",
|
||||
"addon.mod_forum.numdiscussions": "local_moodlemobileapp",
|
||||
"addon.mod_forum.numreplies": "local_moodlemobileapp",
|
||||
"addon.mod_forum.pindiscussion": "forum",
|
||||
"addon.mod_forum.pinupdated": "forum",
|
||||
"addon.mod_forum.postisprivatereply": "forum",
|
||||
"addon.mod_forum.posttoforum": "forum",
|
||||
"addon.mod_forum.posttomygroups": "forum",
|
||||
"addon.mod_forum.privatereply": "forum",
|
||||
"addon.mod_forum.re": "forum",
|
||||
"addon.mod_forum.refreshdiscussions": "local_moodlemobileapp",
|
||||
"addon.mod_forum.refreshposts": "local_moodlemobileapp",
|
||||
"addon.mod_forum.removefromfavourites": "forum",
|
||||
"addon.mod_forum.reply": "forum",
|
||||
"addon.mod_forum.replyplaceholder": "forum",
|
||||
"addon.mod_forum.subject": "forum",
|
||||
"addon.mod_forum.thisforumhasduedate": "forum",
|
||||
"addon.mod_forum.thisforumisdue": "forum",
|
||||
"addon.mod_forum.unlockdiscussion": "forum",
|
||||
"addon.mod_forum.unpindiscussion": "forum",
|
||||
"addon.mod_forum.unread": "forum",
|
||||
"addon.mod_forum.unreadpostsnumber": "forum",
|
||||
"addon.mod_glossary.addentry": "glossary",
|
||||
|
@ -632,6 +666,7 @@
|
|||
"addon.mod_quiz.attemptquiznow": "quiz",
|
||||
"addon.mod_quiz.attemptstate": "quiz",
|
||||
"addon.mod_quiz.cannotsubmitquizdueto": "local_moodlemobileapp",
|
||||
"addon.mod_quiz.clearchoice": "qtype_multichoice",
|
||||
"addon.mod_quiz.comment": "quiz",
|
||||
"addon.mod_quiz.completedon": "quiz",
|
||||
"addon.mod_quiz.confirmclose": "quiz",
|
||||
|
@ -878,6 +913,11 @@
|
|||
"addon.notifications.notifications": "local_moodlemobileapp",
|
||||
"addon.notifications.playsound": "local_moodlemobileapp",
|
||||
"addon.notifications.therearentnotificationsyet": "local_moodlemobileapp",
|
||||
"addon.storagemanager.deletecourse": "local_moodlemobileapp",
|
||||
"addon.storagemanager.deletedatafrom": "local_moodlemobileapp",
|
||||
"addon.storagemanager.info": "local_moodlemobileapp",
|
||||
"addon.storagemanager.managestorage": "local_moodlemobileapp",
|
||||
"addon.storagemanager.storageused": "local_moodlemobileapp",
|
||||
"assets.countries.AD": "countries",
|
||||
"assets.countries.AE": "countries",
|
||||
"assets.countries.AF": "countries",
|
||||
|
@ -1184,6 +1224,7 @@
|
|||
"core.agelocationverification": "moodle",
|
||||
"core.ago": "message",
|
||||
"core.all": "moodle",
|
||||
"core.allgroups": "moodle",
|
||||
"core.allparticipants": "moodle",
|
||||
"core.android": "local_moodlemobileapp",
|
||||
"core.answer": "moodle",
|
||||
|
@ -1229,6 +1270,7 @@
|
|||
"core.contentlinks.confirmurlothersite": "local_moodlemobileapp",
|
||||
"core.contentlinks.errornoactions": "local_moodlemobileapp",
|
||||
"core.contentlinks.errornosites": "local_moodlemobileapp",
|
||||
"core.contentlinks.errorredirectothersite": "local_moodlemobileapp",
|
||||
"core.continue": "moodle",
|
||||
"core.copiedtoclipboard": "local_moodlemobileapp",
|
||||
"core.course": "moodle",
|
||||
|
@ -1237,9 +1279,11 @@
|
|||
"core.course.activitynotyetviewablesiteupgradeneeded": "local_moodlemobileapp",
|
||||
"core.course.allsections": "local_moodlemobileapp",
|
||||
"core.course.askadmintosupport": "local_moodlemobileapp",
|
||||
"core.course.availablespace": "local_moodlemobileapp",
|
||||
"core.course.confirmdeletemodulefiles": "local_moodlemobileapp",
|
||||
"core.course.confirmdownload": "local_moodlemobileapp",
|
||||
"core.course.confirmdownloadunknownsize": "local_moodlemobileapp",
|
||||
"core.course.confirmlimiteddownload": "local_moodlemobileapp",
|
||||
"core.course.confirmpartialdownloadsize": "local_moodlemobileapp",
|
||||
"core.course.contents": "local_moodlemobileapp",
|
||||
"core.course.couldnotloadsectioncontent": "local_moodlemobileapp",
|
||||
|
@ -1251,6 +1295,8 @@
|
|||
"core.course.errorgetmodule": "local_moodlemobileapp",
|
||||
"core.course.hiddenfromstudents": "moodle",
|
||||
"core.course.hiddenoncoursepage": "moodle",
|
||||
"core.course.insufficientavailablequota": "local_moodlemobileapp",
|
||||
"core.course.insufficientavailablespace": "local_moodlemobileapp",
|
||||
"core.course.manualcompletionnotsynced": "local_moodlemobileapp",
|
||||
"core.course.nocontentavailable": "local_moodlemobileapp",
|
||||
"core.course.overriddennotice": "grades",
|
||||
|
@ -1319,6 +1365,7 @@
|
|||
"core.dismiss": "local_moodlemobileapp",
|
||||
"core.done": "survey",
|
||||
"core.download": "moodle",
|
||||
"core.downloaded": "local_moodlemobileapp",
|
||||
"core.downloading": "local_moodlemobileapp",
|
||||
"core.edit": "moodle",
|
||||
"core.emptysplit": "local_moodlemobileapp",
|
||||
|
@ -1342,6 +1389,7 @@
|
|||
"core.favourites": "moodle",
|
||||
"core.filename": "repository",
|
||||
"core.filenameexist": "local_moodlemobileapp",
|
||||
"core.filenotfound": "resource",
|
||||
"core.fileuploader.addfiletext": "repository",
|
||||
"core.fileuploader.audio": "local_moodlemobileapp",
|
||||
"core.fileuploader.camera": "local_moodlemobileapp",
|
||||
|
@ -1555,6 +1603,7 @@
|
|||
"core.nopermissions": "error",
|
||||
"core.noresults": "moodle",
|
||||
"core.notapplicable": "local_moodlemobileapp",
|
||||
"core.notenrolledprofile": "moodle",
|
||||
"core.notice": "moodle",
|
||||
"core.notingroup": "moodle",
|
||||
"core.notsent": "local_moodlemobileapp",
|
||||
|
@ -1596,14 +1645,14 @@
|
|||
"core.question.questionno": "question",
|
||||
"core.question.requiresgrading": "question",
|
||||
"core.quotausage": "moodle",
|
||||
"core.rating.aggregateavg": "moodle",
|
||||
"core.rating.aggregatecount": "moodle",
|
||||
"core.rating.aggregatemax": "moodle",
|
||||
"core.rating.aggregatemin": "moodle",
|
||||
"core.rating.aggregatesum": "moodle",
|
||||
"core.rating.noratings": "moodle",
|
||||
"core.rating.rating": "moodle",
|
||||
"core.rating.ratings": "moodle",
|
||||
"core.rating.aggregateavg": "rating",
|
||||
"core.rating.aggregatecount": "rating",
|
||||
"core.rating.aggregatemax": "rating",
|
||||
"core.rating.aggregatemin": "rating",
|
||||
"core.rating.aggregatesum": "rating",
|
||||
"core.rating.noratings": "rating",
|
||||
"core.rating.rating": "rating",
|
||||
"core.rating.ratings": "rating",
|
||||
"core.redirectingtosite": "local_moodlemobileapp",
|
||||
"core.refresh": "moodle",
|
||||
"core.remove": "moodle",
|
||||
|
@ -1612,6 +1661,7 @@
|
|||
"core.resourcedisplayopen": "moodle",
|
||||
"core.resources": "moodle",
|
||||
"core.restore": "moodle",
|
||||
"core.restricted": "moodle",
|
||||
"core.retry": "local_moodlemobileapp",
|
||||
"core.save": "moodle",
|
||||
"core.search": "moodle",
|
||||
|
@ -1648,6 +1698,7 @@
|
|||
"core.settings.enablerichtexteditor": "local_moodlemobileapp",
|
||||
"core.settings.enablerichtexteditordescription": "local_moodlemobileapp",
|
||||
"core.settings.enablesyncwifi": "local_moodlemobileapp",
|
||||
"core.settings.entriesincache": "local_moodlemobileapp",
|
||||
"core.settings.errordeletesitefiles": "local_moodlemobileapp",
|
||||
"core.settings.errorsyncsite": "local_moodlemobileapp",
|
||||
"core.settings.estimatedfreespace": "local_moodlemobileapp",
|
||||
|
@ -1698,6 +1749,7 @@
|
|||
"core.sizemb": "moodle",
|
||||
"core.sizetb": "local_moodlemobileapp",
|
||||
"core.sorry": "local_moodlemobileapp",
|
||||
"core.sort": "moodle",
|
||||
"core.sortby": "moodle",
|
||||
"core.start": "grouptool",
|
||||
"core.strftimedate": "langconfig",
|
||||
|
|
|
@ -28,6 +28,10 @@ if [ ! -z $GIT_ORG_PRIVATE ] && [ ! -z $GIT_TOKEN ] ; then
|
|||
mv Moodle*.AppImage linux-x64.AppImage
|
||||
ls
|
||||
|
||||
tar -czvf MoodleDesktop32.tar.gz linux-ia32.AppImage
|
||||
tar -czvf MoodleDesktop64.tar.gz linux-x64.AppImage
|
||||
rm *.AppImage
|
||||
|
||||
git add .
|
||||
git commit -m "Linux desktop versions from Travis build $TRAVIS_BUILD_NUMBER"
|
||||
git push
|
||||
|
|
|
@ -34,9 +34,11 @@ $config_langs = array_keys(get_object_vars($config['languages']));
|
|||
// Set languages to do. If script is called using a language it will be used as unique.
|
||||
if (isset($argv[1]) && !empty($argv[1])) {
|
||||
$forcedetect = false;
|
||||
define('TOTRANSLATE', true);
|
||||
$languages = explode(',', $argv[1]);
|
||||
} else {
|
||||
$forcedetect = true;
|
||||
define('TOTRANSLATE', false);
|
||||
$languages = $config_langs;
|
||||
}
|
||||
|
||||
|
@ -160,16 +162,19 @@ function build_lang($lang, $keys, $total) {
|
|||
$file = LANGPACKSFOLDER.'/'.$langfoldername.'/'.$value->file.'.php';
|
||||
// Apply translations.
|
||||
if (!file_exists($file)) {
|
||||
if (TOTRANSLATE) {
|
||||
echo "\n\t\To translate $value->string on $value->file";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$string = [];
|
||||
include($file);
|
||||
|
||||
if (!isset($string[$value->string])) {
|
||||
if (!isset($string[$value->string]) || ($lang == 'en' && $value->file == 'local_moodlemobileapp')) {
|
||||
// Not yet translated. Do not override.
|
||||
if (!$langFile) {
|
||||
// Load lang fils just once.
|
||||
// Load lang files just once.
|
||||
$langFile = file_get_contents(ASSETSPATH.$lang.'.json');
|
||||
$langFile = (array) json_decode($langFile);
|
||||
}
|
||||
|
@ -177,6 +182,9 @@ function build_lang($lang, $keys, $total) {
|
|||
$translations[$key] = $langFile[$key];
|
||||
$local++;
|
||||
}
|
||||
if (TOTRANSLATE) {
|
||||
echo "\n\t\tTo translate $value->string on $value->file";
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
$text = $string[$value->string];
|
||||
|
|
|
@ -17,8 +17,10 @@ import { AddonBadgesProvider } from './providers/badges';
|
|||
import { AddonBadgesUserHandler } from './providers/user-handler';
|
||||
import { AddonBadgesMyBadgesLinkHandler } from './providers/mybadges-link-handler';
|
||||
import { AddonBadgesBadgeLinkHandler } from './providers/badge-link-handler';
|
||||
import { AddonBadgesPushClickHandler } from './providers/push-click-handler';
|
||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreUserDelegate } from '@core/user/providers/user-delegate';
|
||||
import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate';
|
||||
|
||||
// List of providers (without handlers).
|
||||
export const ADDON_BADGES_PROVIDERS: any[] = [
|
||||
|
@ -34,16 +36,19 @@ export const ADDON_BADGES_PROVIDERS: any[] = [
|
|||
AddonBadgesProvider,
|
||||
AddonBadgesUserHandler,
|
||||
AddonBadgesMyBadgesLinkHandler,
|
||||
AddonBadgesBadgeLinkHandler
|
||||
AddonBadgesBadgeLinkHandler,
|
||||
AddonBadgesPushClickHandler
|
||||
]
|
||||
})
|
||||
export class AddonBadgesModule {
|
||||
constructor(userDelegate: CoreUserDelegate, userHandler: AddonBadgesUserHandler,
|
||||
contentLinksDelegate: CoreContentLinksDelegate, myBadgesLinkHandler: AddonBadgesMyBadgesLinkHandler,
|
||||
badgeLinkHandler: AddonBadgesBadgeLinkHandler) {
|
||||
badgeLinkHandler: AddonBadgesBadgeLinkHandler,
|
||||
pushNotificationsDelegate: CorePushNotificationsDelegate, pushClickHandler: AddonBadgesPushClickHandler) {
|
||||
|
||||
userDelegate.registerHandler(userHandler);
|
||||
contentLinksDelegate.registerHandler(myBadgesLinkHandler);
|
||||
contentLinksDelegate.registerHandler(badgeLinkHandler);
|
||||
pushNotificationsDelegate.registerClickHandler(pushClickHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSite } from '@classes/site';
|
||||
|
||||
/**
|
||||
* Service to handle badges.
|
||||
|
@ -79,11 +80,12 @@ export class AddonBadgesProvider {
|
|||
courseid : courseId,
|
||||
userid : userId
|
||||
},
|
||||
presets = {
|
||||
cacheKey: this.getBadgesCacheKey(courseId, userId)
|
||||
preSets = {
|
||||
cacheKey: this.getBadgesCacheKey(courseId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
return site.read('core_badges_get_user_badges', data, presets).then((response) => {
|
||||
return site.read('core_badges_get_user_badges', data, preSets).then((response) => {
|
||||
if (response && response.badges) {
|
||||
return response.badges;
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// (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.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CorePushNotificationsClickHandler } from '@core/pushnotifications/providers/delegate';
|
||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||
import { AddonBadgesProvider } from './badges';
|
||||
|
||||
/**
|
||||
* Handler for badges push notifications clicks.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBadgesPushClickHandler implements CorePushNotificationsClickHandler {
|
||||
name = 'AddonBadgesPushClickHandler';
|
||||
priority = 200;
|
||||
featureName = 'CoreUserDelegate_AddonBadges';
|
||||
|
||||
constructor(private utils: CoreUtilsProvider, private badgesProvider: AddonBadgesProvider,
|
||||
private loginHelper: CoreLoginHelperProvider) {}
|
||||
|
||||
/**
|
||||
* Check if a notification click is handled by this handler.
|
||||
*
|
||||
* @param {any} notification The notification to check.
|
||||
* @return {boolean} Whether the notification click is handled by this handler
|
||||
*/
|
||||
handles(notification: any): boolean | Promise<boolean> {
|
||||
const data = notification.customdata || {};
|
||||
|
||||
if (this.utils.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'moodle' &&
|
||||
(notification.name == 'badgerecipientnotice' || (notification.name == 'badgecreatornotice' && data.hash))) {
|
||||
return this.badgesProvider.isPluginEnabled(notification.site);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the notification click.
|
||||
*
|
||||
* @param {any} notification The notification to check.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
handleClick(notification: any): Promise<any> {
|
||||
const data = notification.customdata || {};
|
||||
|
||||
if (data.hash) {
|
||||
// We have the hash, open the badge directly.
|
||||
return this.loginHelper.redirect('AddonBadgesIssuedBadgePage', {courseId: 0, badgeHash: data.hash}, notification.site);
|
||||
}
|
||||
|
||||
// No hash, open the list of user badges.
|
||||
return this.badgesProvider.invalidateUserBadges(0, Number(notification.usertoid), notification.site).catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
return this.loginHelper.redirect('AddonBadgesUserBadgesPage', {}, notification.site);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<ion-item-divider>
|
||||
<h2>{{ 'addon.block_myoverview.pluginname' | translate }}</h2>
|
||||
<!-- Download all courses. -->
|
||||
<div *ngIf="downloadEnabled && courses[selectedFilter] && courses[selectedFilter].length > 1 && !showFilter" class="core-button-spinner" item-end>
|
||||
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses[selectedFilter] && courses[selectedFilter].length > 1 && !showFilter" class="core-button-spinner" item-end>
|
||||
<button *ngIf="prefetchCoursesData[selectedFilter].icon && prefetchCoursesData[selectedFilter].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
|
||||
<core-icon [name]="prefetchCoursesData[selectedFilter].icon"></core-icon>
|
||||
</button>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<ion-grid no-padding>
|
||||
<ion-row no-padding>
|
||||
<ion-col *ngFor="let course of filteredCourses" no-padding col-12 col-sm-6 col-md-6 col-lg-4 col-xl-4 align-self-stretch>
|
||||
<core-courses-course-progress [course]="course" class="core-courseoverview" showAll="true" [showDownload]="downloadEnabled"></core-courses-course-progress>
|
||||
<core-courses-course-progress [course]="course" class="core-courseoverview" showAll="true" [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
|
|
@ -62,11 +62,14 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
showHidden = false;
|
||||
showSelectorFilter = false;
|
||||
showSortFilter = false;
|
||||
downloadCourseEnabled: boolean;
|
||||
downloadCoursesEnabled: boolean;
|
||||
|
||||
protected prefetchIconsInitialized = false;
|
||||
protected isDestroyed;
|
||||
protected downloadButtonObserver;
|
||||
protected coursesObserver;
|
||||
protected updateSiteObserver;
|
||||
protected courseIds = [];
|
||||
protected fetchContentDefaultError = 'Error getting my overview data.';
|
||||
|
||||
|
@ -96,6 +99,16 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
}
|
||||
});
|
||||
|
||||
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||
|
||||
// Refresh the enabled flags if site is updated.
|
||||
this.updateSiteObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||
|
||||
}, this.sitesProvider.getCurrentSiteId());
|
||||
|
||||
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
|
||||
this.refreshContent();
|
||||
}, this.sitesProvider.getCurrentSiteId());
|
||||
|
@ -336,6 +349,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
this.coursesObserver && this.coursesObserver.off();
|
||||
this.updateSiteObserver && this.updateSiteObserver.off();
|
||||
this.downloadButtonObserver && this.downloadButtonObserver.off();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent impl
|
|||
*/
|
||||
protected fetchContent(): Promise<any> {
|
||||
return this.courseProvider.getSections(this.siteHomeId, false, true).then((sections) => {
|
||||
this.block = sections[0];
|
||||
this.block = sections.find((section) => section.section == 0);
|
||||
|
||||
if (this.block) {
|
||||
this.block.hasContent = this.courseHelper.sectionHasContent(this.block);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreCoursesDashboardProvider } from '@core/courses/providers/dashboard';
|
||||
import * as moment from 'moment';
|
||||
|
||||
/**
|
||||
|
@ -26,7 +27,7 @@ export class AddonBlockTimelineProvider {
|
|||
// Cache key was maintained when moving the functions to this file. It comes from core myoverview.
|
||||
protected ROOT_CACHE_KEY = 'myoverview:';
|
||||
|
||||
constructor(private sitesProvider: CoreSitesProvider) { }
|
||||
constructor(private sitesProvider: CoreSitesProvider, private dashboardProvider: CoreCoursesDashboardProvider) { }
|
||||
|
||||
/**
|
||||
* Get calendar action events for the given course.
|
||||
|
@ -218,6 +219,11 @@ export class AddonBlockTimelineProvider {
|
|||
*/
|
||||
isAvailable(siteId?: string): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
// First check if dashboard is disabled.
|
||||
if (this.dashboardProvider.isDisabledInSite(site)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return site.wsAvailable('core_calendar_get_action_events_by_courses') &&
|
||||
site.wsAvailable('core_calendar_get_action_events_by_timesort');
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</ion-item>
|
||||
<ion-card-content>
|
||||
<core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id"></core-format-text>
|
||||
<ion-item>
|
||||
<ion-item *ngIf="commentsEnabled">
|
||||
<core-comments [component]="this.component" [itemId]="entry.id" area="format_blog" [instanceId]="entry.userid" contextLevel="user"></core-comments>
|
||||
</ion-item>
|
||||
<core-file *ngFor="let file of entry.attachmentfiles" [file]="file" [component]="this.component" [componentId]="entry.id"></core-file>
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { AddonBlogProvider } from '../../providers/blog';
|
||||
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
||||
|
||||
/**
|
||||
* Component that displays the blog entries.
|
||||
|
@ -47,9 +48,11 @@ export class AddonBlogEntriesComponent implements OnInit {
|
|||
showMyIssuesToggle = false;
|
||||
onlyMyEntries = false;
|
||||
component = AddonBlogProvider.COMPONENT;
|
||||
commentsEnabled: boolean;
|
||||
|
||||
constructor(protected blogProvider: AddonBlogProvider, protected domUtils: CoreDomUtilsProvider,
|
||||
protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider) {
|
||||
protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider,
|
||||
protected commentsProvider: CoreCommentsProvider) {
|
||||
this.currentUserId = sitesProvider.getCurrentSiteUserId();
|
||||
}
|
||||
|
||||
|
@ -81,6 +84,8 @@ export class AddonBlogEntriesComponent implements OnInit {
|
|||
this.filter['tagid'] = this.tagId;
|
||||
}
|
||||
|
||||
this.commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite();
|
||||
|
||||
this.fetchEntries().then(() => {
|
||||
this.blogProvider.logView(this.filter).catch(() => {
|
||||
// Ignore errors.
|
||||
|
|
|
@ -16,6 +16,8 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||
import { CoreSite } from '@classes/site';
|
||||
|
||||
/**
|
||||
* Service to handle blog entries.
|
||||
|
@ -27,7 +29,8 @@ export class AddonBlogProvider {
|
|||
protected ROOT_CACHE_KEY = 'addonBlog:';
|
||||
protected logger;
|
||||
|
||||
constructor(logger: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, protected utils: CoreUtilsProvider) {
|
||||
constructor(logger: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider, protected utils: CoreUtilsProvider,
|
||||
protected pushNotificationsProvider: CorePushNotificationsProvider) {
|
||||
this.logger = logger.getInstance('AddonBlogProvider');
|
||||
}
|
||||
|
||||
|
@ -74,7 +77,8 @@ export class AddonBlogProvider {
|
|||
};
|
||||
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesCacheKey(filter)
|
||||
cacheKey: this.getEntriesCacheKey(filter),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
return site.read('core_blog_get_entries', data, preSets);
|
||||
|
@ -102,6 +106,8 @@ export class AddonBlogProvider {
|
|||
* @return {Promise<any>} Promise to be resolved when done.
|
||||
*/
|
||||
logView(filter: any = {}, siteId?: string): Promise<any> {
|
||||
this.pushNotificationsProvider.logViewListEvent('blog', 'core_blog_view_entries', filter, siteId);
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const data = {
|
||||
filters: this.utils.objectToArrayOfObjects(filter, 'name', 'value')
|
||||
|
|
|
@ -24,7 +24,7 @@ import { AddonBlogProvider } from './blog';
|
|||
@Injectable()
|
||||
export class AddonBlogIndexLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonBlogIndexLinkHandler';
|
||||
featureName = 'CoreUserDelegate_AddonBlog';
|
||||
featureName = 'CoreUserDelegate_AddonBlog:blogs';
|
||||
pattern = /\/blog\/index\.php/;
|
||||
|
||||
constructor(private blogProvider: AddonBlogProvider, private loginHelper: CoreLoginHelperProvider) {
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<h2>{{ 'addon.calendar.reminders' | translate }}</h2>
|
||||
</ion-item>
|
||||
<ng-container *ngFor="let reminder of reminders">
|
||||
<ion-item *ngIf="reminder.time > 0 || defaultTime > 0" [class.item-dimmed]="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) <= currentTime" >
|
||||
<ion-item text-wrap *ngIf="reminder.time > 0 || defaultTime > 0" [class.item-dimmed]="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) <= currentTime" >
|
||||
<p *ngIf="reminder.time == -1">{{ 'core.defaultvalue' | translate :{$a: ((event.timestart - defaultTime) * 1000) | coreFormatDate } }}</p>
|
||||
<p *ngIf="reminder.time > 0">{{ reminder.time * 1000 | coreFormatDate }}</p>
|
||||
<button ion-button icon-only clear="true" (click)="cancelNotification(reminder.id, $event)" [attr.aria-label]=" 'core.delete' | translate" item-end *ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime">
|
||||
|
@ -68,11 +68,11 @@
|
|||
|
||||
<ng-container *ngIf="event.timestart + event.timeduration > currentTime">
|
||||
<ion-item>
|
||||
<ion-label stacked>{{ 'addon.calendar.setnewreminder' | translate }}</ion-label>
|
||||
<ion-label stacked><h2>{{ 'addon.calendar.setnewreminder' | translate }}</h2></ion-label>
|
||||
<ion-datetime [(ngModel)]="notificationTimeText" [placeholder]="'core.choosedots' | translate" [displayFormat]="notificationFormat" [min]="notificationMin" [max]="notificationMax"></ion-datetime>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<button ion-button block color="primary" (click)="addNotificationTime($event)" [disabled]="!notificationTimeText">{{ 'addon.calendar.setnewreminder' | translate }}</button>
|
||||
<button ion-button block color="primary" (click)="addNotificationTime($event)" [disabled]="!notificationTimeText">{{ 'core.save' | translate }}</button>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-card>
|
||||
|
|
|
@ -292,7 +292,8 @@ export class AddonCalendarProvider {
|
|||
getEvent(id: number, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const preSets = {
|
||||
cacheKey: this.getEventCacheKey(id)
|
||||
cacheKey: this.getEventCacheKey(id),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
},
|
||||
data = {
|
||||
options: {
|
||||
|
@ -329,7 +330,8 @@ export class AddonCalendarProvider {
|
|||
getEventById(id: number, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const preSets = {
|
||||
cacheKey: this.getEventCacheKey(id)
|
||||
cacheKey: this.getEventCacheKey(id),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
},
|
||||
data = {
|
||||
eventid: id
|
||||
|
@ -469,7 +471,8 @@ export class AddonCalendarProvider {
|
|||
// We need to retrieve cached data using cache key because we have timestamp in the params.
|
||||
const preSets = {
|
||||
cacheKey: this.getEventsListCacheKey(daysToStart, daysInterval),
|
||||
getCacheUsingCacheKey: true
|
||||
getCacheUsingCacheKey: true,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
return site.read('core_calendar_get_calendar_events', data, preSets).then((response) => {
|
||||
|
@ -646,6 +649,7 @@ export class AddonCalendarProvider {
|
|||
id: reminderId,
|
||||
title: event.name,
|
||||
text: this.timeUtils.userDate(event.timestart * 1000, 'core.strftimedaydatetime', true),
|
||||
icon: 'file://assets/img/icons/calendar.png',
|
||||
trigger: {
|
||||
at: new Date(time)
|
||||
},
|
||||
|
|
|
@ -18,10 +18,17 @@ import { AddonCompetencyHelperProvider } from './providers/helper';
|
|||
import { AddonCompetencyCourseOptionHandler } from './providers/course-option-handler';
|
||||
import { AddonCompetencyMainMenuHandler } from './providers/mainmenu-handler';
|
||||
import { AddonCompetencyUserHandler } from './providers/user-handler';
|
||||
import { AddonCompetencyCompetencyLinkHandler } from './providers/competency-link-handler';
|
||||
import { AddonCompetencyPlanLinkHandler } from './providers/plan-link-handler';
|
||||
import { AddonCompetencyPlansLinkHandler } from './providers/plans-link-handler';
|
||||
import { AddonCompetencyUserCompetencyLinkHandler } from './providers/user-competency-link-handler';
|
||||
import { AddonCompetencyPushClickHandler } from './providers/push-click-handler';
|
||||
import { AddonCompetencyComponentsModule } from './components/components.module';
|
||||
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
|
||||
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
|
||||
import { CoreUserDelegate } from '@core/user/providers/user-delegate';
|
||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
||||
import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate';
|
||||
|
||||
// List of providers (without handlers).
|
||||
export const ADDON_COMPETENCY_PROVIDERS: any[] = [
|
||||
|
@ -40,16 +47,30 @@ export const ADDON_COMPETENCY_PROVIDERS: any[] = [
|
|||
AddonCompetencyHelperProvider,
|
||||
AddonCompetencyCourseOptionHandler,
|
||||
AddonCompetencyMainMenuHandler,
|
||||
AddonCompetencyUserHandler
|
||||
AddonCompetencyUserHandler,
|
||||
AddonCompetencyCompetencyLinkHandler,
|
||||
AddonCompetencyPlanLinkHandler,
|
||||
AddonCompetencyPlansLinkHandler,
|
||||
AddonCompetencyUserCompetencyLinkHandler,
|
||||
AddonCompetencyPushClickHandler
|
||||
]
|
||||
})
|
||||
export class AddonCompetencyModule {
|
||||
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: AddonCompetencyMainMenuHandler,
|
||||
courseOptionsDelegate: CoreCourseOptionsDelegate, courseOptionHandler: AddonCompetencyCourseOptionHandler,
|
||||
userDelegate: CoreUserDelegate, userHandler: AddonCompetencyUserHandler) {
|
||||
userDelegate: CoreUserDelegate, userHandler: AddonCompetencyUserHandler,
|
||||
contentLinksDelegate: CoreContentLinksDelegate, competencyLinkHandler: AddonCompetencyCompetencyLinkHandler,
|
||||
planLinkHandler: AddonCompetencyPlanLinkHandler, plansLinkHandler: AddonCompetencyPlansLinkHandler,
|
||||
userComptencyLinkHandler: AddonCompetencyUserCompetencyLinkHandler,
|
||||
pushNotificationsDelegate: CorePushNotificationsDelegate, pushClickHandler: AddonCompetencyPushClickHandler) {
|
||||
|
||||
mainMenuDelegate.registerHandler(mainMenuHandler);
|
||||
courseOptionsDelegate.registerHandler(courseOptionHandler);
|
||||
userDelegate.registerHandler(userHandler);
|
||||
contentLinksDelegate.registerHandler(competencyLinkHandler);
|
||||
contentLinksDelegate.registerHandler(planLinkHandler);
|
||||
contentLinksDelegate.registerHandler(plansLinkHandler);
|
||||
contentLinksDelegate.registerHandler(userComptencyLinkHandler);
|
||||
pushNotificationsDelegate.registerClickHandler(pushClickHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,19 @@
|
|||
</ion-refresher>
|
||||
<core-loading [hideUntil]="competenciesLoaded">
|
||||
<ion-card *ngIf="!user && competencies && competencies.statistics.competencycount > 0">
|
||||
<ng-container *ngIf="competencies.cangradecompetencies">
|
||||
<ion-item text-wrap *ngIf="competencies.settings.pushratingstouserplans">
|
||||
{{ 'addon.competency.coursecompetencyratingsarepushedtouserplans' | translate }}
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="!competencies.settings.pushratingstouserplans">
|
||||
<ion-item text-wrap *ngIf="!competencies.settings.pushratingstouserplans" color="danger">
|
||||
{{ 'addon.competency.coursecompetencyratingsarenotpushedtouserplans' | translate }}
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<strong>{{ 'addon.competency.progress' | translate }}</strong>:
|
||||
{{ 'addon.competency.xcompetenciesproficientoutofyincourse' | translate:{$a: {x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} } }} ({{ competencies.statistics.proficientcompetencypercentageformatted }}%)
|
||||
</ng-container>
|
||||
<ion-item text-wrap *ngIf="competencies.statistics.canbegradedincourse">
|
||||
{{ 'addon.competency.xcompetenciesproficientoutofyincourse' | translate:{$a: {x: competencies.statistics.proficientcompetencycount, y: competencies.statistics.competencycount} } }}
|
||||
<core-progress-bar [progress]="competencies.statistics.proficientcompetencypercentage"></core-progress-bar>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="competencies.statistics.leastproficientcount > 0">
|
||||
<ion-item text-wrap *ngIf="competencies.statistics.canmanagecoursecompetencies && competencies.statistics.leastproficientcount > 0">
|
||||
<strong>{{ 'addon.competency.competenciesmostoftennotproficientincourse' | translate }}</strong>:
|
||||
<p *ngFor="let comp of competencies.statistics.leastproficient">
|
||||
<a (click)="openCompetencySummary(comp.id)">
|
||||
|
@ -25,42 +26,63 @@
|
|||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<h3 margin-horizontal *ngIf="competencies && competencies.statistics.competencycount > 0">{{ 'addon.competency.competencies' | translate }}</h3>
|
||||
<h3 margin-horizontal *ngIf="competencies && competencies.statistics.competencycount > 0">{{ 'addon.competency.coursecompetencies' | translate }}</h3>
|
||||
<ion-card *ngIf="user">
|
||||
<ion-item text-wrap>
|
||||
<ion-avatar core-user-avatar [user]="user" item-start></ion-avatar>
|
||||
<h2><core-format-text [text]="user.fullname"></core-format-text></h2>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
<core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" icon="ribbon" message="{{ 'addon.competency.nocompetencies' | translate }}"></core-empty-box>
|
||||
<core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" icon="ribbon" message="{{ 'addon.competency.nocompetenciesincourse' | translate }}"></core-empty-box>
|
||||
|
||||
<div *ngIf="competencies">
|
||||
<ion-card *ngFor="let competency of competencies.competencies">
|
||||
<a ion-item text-wrap (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
|
||||
{{competency.competency.shortname}} <small>{{competency.competency.idnumber}}</small>
|
||||
<ion-item text-wrap (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname" detail-push>
|
||||
<h2><strong>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></strong></h2>
|
||||
<ion-badge item-end *ngIf="competency.usercompetencycourse && competency.usercompetencycourse.gradename" [color]="competency.usercompetencycourse.proficiency ? 'success' : 'danger'">{{ competency.usercompetencycourse.gradename }}</ion-badge>
|
||||
</a>
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<div *ngIf="competency.competency.description">
|
||||
<p *ngIf="competency.competency.description">
|
||||
<core-format-text [text]=" competency.competency.description "></core-format-text>
|
||||
</div>
|
||||
</p>
|
||||
<div>
|
||||
<strong>{{ 'addon.competency.path' | translate }}</strong>
|
||||
{{ competency.comppath.framework.name }}
|
||||
<a *ngIf="competency.comppath.showlinks" [href]="competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + competency.comppath.framework.id + '&pagecontextid=' + competency.comppath.pagecontextid" core-link [title]="competency.comppath.framework.name">{{ competency.comppath.framework.name }}</a>
|
||||
<ng-container *ngIf="!competency.comppath.showlinks">{{ competency.comppath.framework.name }}</ng-container>
|
||||
/
|
||||
<span *ngFor="let ancestor of competency.comppath.ancestors">
|
||||
/ <a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
|
||||
<a *ngIf="competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
|
||||
<ng-container *ngIf="!competency.comppath.showlinks">{{ ancestor.name }}</ng-container>
|
||||
<ng-container *ngIf="!ancestor.last"> / </ng-container>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ 'addon.competency.activities' | translate }}</strong>:
|
||||
<span *ngIf="competency.coursemodules.length == 0">
|
||||
{{ 'addon.competency.noactivities' | translate }}
|
||||
<div *ngIf="competencies.statistics.canmanagecoursecompetencies">
|
||||
<strong>{{ 'addon.competency.uponcoursecompletion' | translate }}</strong>
|
||||
<ng-container *ngFor="let ruleoutcome of competency.ruleoutcomeoptions">
|
||||
<span *ngIf="ruleoutcome.selected">
|
||||
<core-format-text [text]="ruleoutcome.text"></core-format-text>
|
||||
</span>
|
||||
<a ion-item text-wrap *ngFor="let activity of competency.coursemodules" [href]="activity.url" [title]="activity.name" core-link capture="true">
|
||||
</ng-container>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ 'addon.competency.activities' | translate }}</strong>
|
||||
<p *ngIf="competency.coursemodules.length == 0">
|
||||
{{ 'addon.competency.noactivities' | translate }}
|
||||
</p>
|
||||
<a ion-item text-wrap *ngFor="let activity of competency.coursemodules" [href]="activity.url" [title]="activity.name" core-link capture="true" class="core-course-module-handler item-media">
|
||||
<img item-start [src]="activity.iconurl" core-external-content alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon">
|
||||
<core-format-text [text]="activity.name"></core-format-text>
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="competency.plans">
|
||||
<strong>{{ 'addon.competency.userplans' | translate }}</strong>
|
||||
<p *ngIf="competency.plans.length == 0">
|
||||
{{ 'addon.competency.nouserplanswithcompetency' | translate }}
|
||||
</p>
|
||||
<a ion-item text-wrap *ngFor="let plan of competency.plans" [href]="plan.url" [title]="plan.name" core-link capture="true">
|
||||
<core-format-text [text]="plan.name"></core-format-text>
|
||||
</a>
|
||||
</div>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
</div>
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
"myplans": "My learning plans",
|
||||
"noactivities": "No activities",
|
||||
"nocompetencies": "No competencies",
|
||||
"nocompetenciesincourse": "No competencies have been linked to this course.",
|
||||
"nocrossreferencedcompetencies": "No other competencies have been cross-referenced to this competency.",
|
||||
"noevidence": "No evidence",
|
||||
"noplanswerecreated": "No learning plans were created.",
|
||||
"nouserplanswithcompetency": "No learning plans contain this competency.",
|
||||
"path": "Path:",
|
||||
"planstatusactive": "Active",
|
||||
"planstatuscomplete": "Complete",
|
||||
|
@ -38,6 +40,7 @@
|
|||
"reviewstatus": "Review status",
|
||||
"status": "Status",
|
||||
"template": "Learning plan template",
|
||||
"uponcoursecompletion": "Upon course completion:",
|
||||
"usercompetencystatus_idle": "Idle",
|
||||
"usercompetencystatus_inreview": "In review",
|
||||
"usercompetencystatus_waitingforreview": "Waiting for review",
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<core-loading [hideUntil]="competenciesLoaded">
|
||||
<ion-list>
|
||||
<a ion-item text-wrap *ngFor="let competency of competencies" [title]="competency.competency.shortname" (click)="openCompetency(competency.competency.id)" [class.core-split-item-selected]="competency.competency.id == competencyId">
|
||||
{{ competency.competency.shortname }} <small>{{competency.competency.idnumber}}</small>
|
||||
<h2>{{ competency.competency.shortname }} <em>{{competency.competency.idnumber}}</em></h2>
|
||||
<ion-badge item-end *ngIf="competency.usercompetency" [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
|
||||
<ion-badge item-end *ngIf="competency.usercompetencycourse" [color]="competency.usercompetencycourse.proficiency ? 'success' : 'danger'">{{ competency.usercompetencycourse.gradename }}</ion-badge>
|
||||
</a>
|
||||
|
|
|
@ -21,9 +21,13 @@
|
|||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<strong>{{ 'addon.competency.path' | translate }}</strong>
|
||||
{{ competency.competency.comppath.framework.name }}
|
||||
<a *ngIf="competency.competency.comppath.showlinks" [href]="competency.competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + competency.competency.comppath.framework.id + '&pagecontextid=' + competency.competency.comppath.pagecontextid" core-link [title]="competency.competency.comppath.framework.name">{{ competency.competency.comppath.framework.name }}</a>
|
||||
<ng-container *ngIf="!competency.competency.comppath.showlinks">{{ competency.competency.comppath.framework.name }}</ng-container>
|
||||
/
|
||||
<span *ngFor="let ancestor of competency.competency.comppath.ancestors">
|
||||
/ <a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
|
||||
<a *ngIf="competency.competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a>
|
||||
<ng-container *ngIf="!competency.competency.comppath.showlinks">{{ ancestor.name }}</ng-container>
|
||||
<ng-container *ngIf="!ancestor.last"> / </ng-container>
|
||||
</span>
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
|
@ -38,21 +42,21 @@
|
|||
</div>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="coursemodules">
|
||||
<strong>{{ 'addon.competency.activities' | translate }}</strong>:
|
||||
<span *ngIf="coursemodules.length == 0">
|
||||
<strong>{{ 'addon.competency.activities' | translate }}</strong>
|
||||
<p *ngIf="coursemodules.length == 0">
|
||||
{{ 'addon.competency.noactivities' | translate }}
|
||||
</span>
|
||||
</p>
|
||||
<a ion-item text-wrap *ngFor="let activity of coursemodules" [href]="activity.url" [title]="activity.name" core-link capture="true">
|
||||
<img item-start core-external-content [src]="activity.iconurl" alt="" role="presentation" *ngIf="activity.iconurl" class="core-module-icon">
|
||||
<core-format-text [text]="activity.name"></core-format-text>
|
||||
</a>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="competency.usercompetency.status">
|
||||
<strong>{{ 'addon.competency.reviewstatus' | translate }}</strong>:
|
||||
<strong>{{ 'addon.competency.reviewstatus' | translate }}</strong>
|
||||
{{ competency.usercompetency.statusname }}
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<strong>{{ 'addon.competency.proficient' | translate }}</strong>:
|
||||
<strong>{{ 'addon.competency.proficient' | translate }}</strong>
|
||||
<ion-badge color="success" *ngIf="competency.usercompetency.proficiency">
|
||||
{{ 'core.yes' | translate }}
|
||||
</ion-badge>
|
||||
|
@ -61,7 +65,7 @@
|
|||
</ion-badge>
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<strong>{{ 'addon.competency.rating' | translate }}</strong>:
|
||||
<strong>{{ 'addon.competency.rating' | translate }}</strong>
|
||||
<ion-badge color="dark">{{ competency.usercompetency.gradename }}</ion-badge>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
|
|
@ -55,13 +55,16 @@ export class AddonCompetencyCompetencyPage {
|
|||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchCompetency().then(() => {
|
||||
const name = this.competency && this.competency.competency && this.competency.competency.competency &&
|
||||
this.competency.competency.competency.shortname;
|
||||
|
||||
if (this.planId) {
|
||||
this.competencyProvider.logCompetencyInPlanView(this.planId, this.competencyId, this.planStatus, this.userId)
|
||||
.catch(() => {
|
||||
this.competencyProvider.logCompetencyInPlanView(this.planId, this.competencyId, this.planStatus, name,
|
||||
this.userId).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
} else {
|
||||
this.competencyProvider.logCompetencyInCourseView(this.courseId, this.competencyId, this.userId).catch(() => {
|
||||
this.competencyProvider.logCompetencyInCourseView(this.courseId, this.competencyId, name, this.userId).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
|
|
@ -41,7 +41,10 @@ export class AddonCompetencyCompetencySummaryPage {
|
|||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchCompetency().then(() => {
|
||||
this.competencyProvider.logCompetencyView(this.competencyId).catch(() => {
|
||||
const name = this.competency.competency && this.competency.competency.competency &&
|
||||
this.competency.competency.competency.shortname;
|
||||
|
||||
this.competencyProvider.logCompetencyView(this.competencyId, name).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}).finally(() => {
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
</ion-card>
|
||||
<ion-card *ngIf="plan">
|
||||
<ion-list>
|
||||
<ion-item text-wrap *ngIf="plan.plan.description">
|
||||
<core-format-text [text]="plan.plan.description"></core-format-text>
|
||||
</ion-item>
|
||||
<ion-item text-wrap>
|
||||
<strong>{{ 'addon.competency.status' | translate }}</strong>:
|
||||
{{ plan.plan.statusname }}
|
||||
|
@ -36,13 +39,13 @@
|
|||
</ion-list>
|
||||
</ion-card>
|
||||
<ion-card *ngIf="plan">
|
||||
<ion-card-header text-wrap>{{ 'addon.competency.learningplancompetencies' | translate }}</ion-card-header>
|
||||
<ion-card-header text-wrap><h2>{{ 'addon.competency.learningplancompetencies' | translate }}</h2></ion-card-header>
|
||||
<ion-list>
|
||||
<ion-item text-wrap *ngIf="plan.competencycount == 0">
|
||||
{{ 'addon.competency.nocompetencies' | translate }}
|
||||
</ion-item>
|
||||
<a ion-item text-wrap *ngFor="let competency of plan.competencies" (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
|
||||
{{competency.competency.shortname}} <small>{{competency.competency.idnumber}}</small>
|
||||
<h2>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></h2>
|
||||
<ion-badge item-end [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
|
||||
</a>
|
||||
</ion-list>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<a ion-item text-wrap *ngFor="let plan of plans" [title]="plan.name" (click)="openPlan(plan.id)" [class.core-split-item-selected]="plan.id == planId">
|
||||
<h2>{{ plan.name }}</h2>
|
||||
<p *ngIf="plan.duedate > 0">{{ 'addon.competency.duedate' | translate }}: {{ plan.duedate * 1000 | coreFormatDate :'strftimedatetimeshort' }}</p>
|
||||
<ion-badge text-wrap [color]="plan.statuscolor">{{ plan.statusname }}</ion-badge>
|
||||
<ion-badge item-end text-wrap [color]="plan.statuscolor">{{ plan.statusname }}</ion-badge>
|
||||
</a>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// (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.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||
import { AddonCompetencyProvider } from './competency';
|
||||
|
||||
/**
|
||||
* Handler to treat links to a competency in a plan or in a course.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonCompetencyCompetencyLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonCompetencyCompetencyLinkHandler';
|
||||
pattern = /\/admin\/tool\/lp\/(user_competency_in_course|user_competency_in_plan)\.php/;
|
||||
|
||||
constructor(private linkHelper: CoreContentLinksHelperProvider, private competencyProvider: AddonCompetencyProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
* @param {string[]} siteIds List of sites the URL belongs to.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
|
||||
*/
|
||||
getActions(siteIds: string[], url: string, params: any, courseId?: number):
|
||||
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||
courseId = courseId || params.courseid || params.cid;
|
||||
|
||||
return [{
|
||||
action: (siteId, navCtrl?): void => {
|
||||
this.linkHelper.goInSite(navCtrl, 'AddonCompetencyCompetencyPage', {
|
||||
planId: params.planid,
|
||||
competencyId: params.competencyid,
|
||||
courseId: courseId,
|
||||
userId: params.userid
|
||||
}, siteId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param {string} siteId The site ID.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||
// Handler is disabled if all competency features are disabled.
|
||||
return this.competencyProvider.allCompetenciesDisabled(siteId).then((disabled) => {
|
||||
return !disabled;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||
import { CoreSite } from '@classes/site';
|
||||
|
||||
/**
|
||||
* Service to handle caompetency learning plans.
|
||||
|
@ -38,10 +40,25 @@ export class AddonCompetencyProvider {
|
|||
|
||||
protected logger;
|
||||
|
||||
constructor(loggerProvider: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
|
||||
constructor(loggerProvider: CoreLoggerProvider, private sitesProvider: CoreSitesProvider,
|
||||
protected pushNotificationsProvider: CorePushNotificationsProvider) {
|
||||
this.logger = loggerProvider.getInstance('AddonCompetencyProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all competencies features are disabled.
|
||||
*
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<boolean>} Promise resolved with boolean: whether all competency features are disabled.
|
||||
*/
|
||||
allCompetenciesDisabled(siteId?: string): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.isFeatureDisabled('CoreMainMenuDelegate_AddonCompetency') &&
|
||||
site.isFeatureDisabled('CoreCourseOptionsDelegate_AddonCompetency') &&
|
||||
site.isFeatureDisabled('CoreUserDelegate_AddonCompetency');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for user learning plans data WS calls.
|
||||
*
|
||||
|
@ -140,7 +157,8 @@ export class AddonCompetencyProvider {
|
|||
userid: userId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getLearningPlansCacheKey(userId)
|
||||
cacheKey: this.getLearningPlansCacheKey(userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
return site.read('tool_lp_data_for_plans_page', params, preSets).then((response) => {
|
||||
|
@ -169,7 +187,8 @@ export class AddonCompetencyProvider {
|
|||
planid: planId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getLearningPlanCacheKey(planId)
|
||||
cacheKey: this.getLearningPlanCacheKey(planId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
return site.read('tool_lp_data_for_plan_page', params, preSets).then((response) => {
|
||||
|
@ -200,7 +219,8 @@ export class AddonCompetencyProvider {
|
|||
competencyid: competencyId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getCompetencyInPlanCacheKey(planId, competencyId)
|
||||
cacheKey: this.getCompetencyInPlanCacheKey(planId, competencyId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
return site.read('tool_lp_data_for_user_competency_summary_in_plan', params, preSets).then((response) => {
|
||||
|
@ -237,7 +257,8 @@ export class AddonCompetencyProvider {
|
|||
userid: userId
|
||||
},
|
||||
preSets: any = {
|
||||
cacheKey: this.getCompetencyInCourseCacheKey(courseId, competencyId, userId)
|
||||
cacheKey: this.getCompetencyInCourseCacheKey(courseId, competencyId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
|
@ -275,7 +296,8 @@ export class AddonCompetencyProvider {
|
|||
userid: userId
|
||||
},
|
||||
preSets: any = {
|
||||
cacheKey: this.getCompetencySummaryCacheKey(competencyId, userId)
|
||||
cacheKey: this.getCompetencySummaryCacheKey(competencyId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
|
@ -311,7 +333,8 @@ export class AddonCompetencyProvider {
|
|||
courseid: courseId
|
||||
},
|
||||
preSets: any = {
|
||||
cacheKey: this.getCourseCompetenciesCacheKey(courseId)
|
||||
cacheKey: this.getCourseCompetenciesCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
|
@ -457,13 +480,15 @@ export class AddonCompetencyProvider {
|
|||
* @param {number} planId ID of the plan.
|
||||
* @param {number} competencyId ID of the competency.
|
||||
* @param {number} planStatus Current plan Status to decide what action should be logged.
|
||||
* @param {string} [name] Name of the competency.
|
||||
* @param {number} [userId] User ID. If not defined, current user.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved when the WS call is successful.
|
||||
*/
|
||||
logCompetencyInPlanView(planId: number, competencyId: number, planStatus: number, userId?: number, siteId?: string)
|
||||
: Promise<any> {
|
||||
logCompetencyInPlanView(planId: number, competencyId: number, planStatus: number, name?: string, userId?: number,
|
||||
siteId?: string): Promise<any> {
|
||||
if (planId && competencyId) {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
|
||||
|
@ -474,13 +499,17 @@ export class AddonCompetencyProvider {
|
|||
},
|
||||
preSets = {
|
||||
typeExpected: 'boolean'
|
||||
};
|
||||
},
|
||||
wsName = planStatus == AddonCompetencyProvider.STATUS_COMPLETE ?
|
||||
'core_competency_user_competency_plan_viewed' : 'core_competency_user_competency_viewed_in_plan';
|
||||
|
||||
if (planStatus == AddonCompetencyProvider.STATUS_COMPLETE) {
|
||||
return site.write('core_competency_user_competency_plan_viewed', params, preSets);
|
||||
} else {
|
||||
return site.write('core_competency_user_competency_viewed_in_plan', params, preSets);
|
||||
}
|
||||
this.pushNotificationsProvider.logViewEvent(competencyId, name, 'competency', wsName, {
|
||||
planid: planId,
|
||||
planstatus: planStatus,
|
||||
userid: userId
|
||||
}, siteId);
|
||||
|
||||
return site.write(wsName, params, preSets);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -492,11 +521,14 @@ export class AddonCompetencyProvider {
|
|||
*
|
||||
* @param {number} courseId ID of the course.
|
||||
* @param {number} competencyId ID of the competency.
|
||||
* @param {string} [name] Name of the competency.
|
||||
* @param {number} [userId] User ID. If not defined, current user.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved when the WS call is successful.
|
||||
*/
|
||||
logCompetencyInCourseView(courseId: number, competencyId: number, userId?: number, siteId?: string): Promise<any> {
|
||||
logCompetencyInCourseView(courseId: number, competencyId: number, name?: string, userId?: number, siteId?: string)
|
||||
: Promise<any> {
|
||||
|
||||
if (courseId && competencyId) {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
|
@ -509,8 +541,14 @@ export class AddonCompetencyProvider {
|
|||
const preSets = {
|
||||
typeExpected: 'boolean'
|
||||
};
|
||||
const wsName = 'core_competency_user_competency_viewed_in_course';
|
||||
|
||||
return site.write('core_competency_user_competency_viewed_in_course', params, preSets);
|
||||
this.pushNotificationsProvider.logViewEvent(competencyId, name, 'competency', wsName, {
|
||||
courseid: courseId,
|
||||
userid: userId
|
||||
}, siteId);
|
||||
|
||||
return site.write(wsName, params, preSets);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -521,10 +559,11 @@ export class AddonCompetencyProvider {
|
|||
* Report the competency as being viewed.
|
||||
*
|
||||
* @param {number} competencyId ID of the competency.
|
||||
* @param {string} [name] Name of the competency.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved when the WS call is successful.
|
||||
*/
|
||||
logCompetencyView(competencyId: number, siteId?: string): Promise<any> {
|
||||
logCompetencyView(competencyId: number, name?: string, siteId?: string): Promise<any> {
|
||||
if (competencyId) {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
|
@ -533,6 +572,9 @@ export class AddonCompetencyProvider {
|
|||
const preSets = {
|
||||
typeExpected: 'boolean'
|
||||
};
|
||||
const wsName = 'core_competency_competency_viewed';
|
||||
|
||||
this.pushNotificationsProvider.logViewEvent(competencyId, name, 'competency', wsName, {}, siteId);
|
||||
|
||||
return site.write('core_competency_competency_viewed', params, preSets);
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||
import { AddonCompetencyProvider } from './competency';
|
||||
|
||||
/**
|
||||
* Handler to treat links to a plan.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonCompetencyPlanLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonCompetencyPlanLinkHandler';
|
||||
pattern = /\/admin\/tool\/lp\/plan\.php.*([\?\&]id=\d+)/;
|
||||
|
||||
constructor(private linkHelper: CoreContentLinksHelperProvider, private competencyProvider: AddonCompetencyProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
* @param {string[]} siteIds List of sites the URL belongs to.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
|
||||
*/
|
||||
getActions(siteIds: string[], url: string, params: any, courseId?: number):
|
||||
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||
|
||||
return [{
|
||||
action: (siteId, navCtrl?): void => {
|
||||
this.linkHelper.goInSite(navCtrl, 'AddonCompetencyPlanPage', { planId: params.id }, siteId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param {string} siteId The site ID.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||
// Handler is disabled if all competency features are disabled.
|
||||
return this.competencyProvider.allCompetenciesDisabled(siteId).then((disabled) => {
|
||||
return !disabled;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// (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.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||
import { AddonCompetencyProvider } from './competency';
|
||||
|
||||
/**
|
||||
* Handler to treat links to user plans.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonCompetencyPlansLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonCompetencyPlansLinkHandler';
|
||||
pattern = /\/admin\/tool\/lp\/plans\.php/;
|
||||
|
||||
constructor(private loginHelper: CoreLoginHelperProvider, private competencyProvider: AddonCompetencyProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
* @param {string[]} siteIds List of sites the URL belongs to.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {CoreContentLinksAction[]|Promise<CoreContentLinksAction[]>} List of (or promise resolved with list of) actions.
|
||||
*/
|
||||
getActions(siteIds: string[], url: string, params: any, courseId?: number):
|
||||
CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||
|
||||
return [{
|
||||
action: (siteId, navCtrl?): void => {
|
||||
// Always use redirect to make it the new history root (to avoid "loops" in history).
|
||||
this.loginHelper.redirect('AddonCompetencyPlanListPage', { userId: params.userid }, siteId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param {string} siteId The site ID.
|
||||
* @param {string} url The URL to treat.
|
||||
* @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param {number} [courseId] Course ID related to the URL. Optional but recommended.
|
||||
* @return {boolean|Promise<boolean>} Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||
// Handler is disabled if all competency features are disabled.
|
||||
return this.competencyProvider.allCompetenciesDisabled(siteId).then((disabled) => {
|
||||
return !disabled;
|
||||
});
|
||||
}
|
||||
}
|