commit
a362711864
|
@ -0,0 +1 @@
|
|||
*.js
|
|
@ -0,0 +1,301 @@
|
|||
const appConfig = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'header',
|
||||
'jsdoc',
|
||||
'prefer-arrow',
|
||||
'promise',
|
||||
],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'plugin:@angular-eslint/recommended',
|
||||
'plugin:promise/recommended',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
sourceType: 'module',
|
||||
},
|
||||
reportUnusedDisableDirectives: true,
|
||||
rules: {
|
||||
'@angular-eslint/component-class-suffix': ['error', { suffixes: ['Component', 'Page'] }],
|
||||
'@angular-eslint/no-output-on-prefix': 'off',
|
||||
'@typescript-eslint/adjacent-overload-signatures': 'error',
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
types: {
|
||||
Boolean: {
|
||||
message: 'Use \'boolean\' instead.',
|
||||
},
|
||||
Number: {
|
||||
message: 'Use \'number\' instead.',
|
||||
},
|
||||
String: {
|
||||
message: 'Use \'string\' instead.',
|
||||
},
|
||||
Object: {
|
||||
message: 'Use {} instead.',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'error',
|
||||
{
|
||||
accessibility: 'no-public',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/explicit-module-boundary-types': [
|
||||
'error',
|
||||
{
|
||||
allowArgumentsExplicitlyTypedAsAny: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/indent': [
|
||||
'error',
|
||||
4,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
ignoredNodes: [
|
||||
'ClassProperty *',
|
||||
],
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/lines-between-class-members': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
exceptAfterSingleLine: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/member-delimiter-style': [
|
||||
'error',
|
||||
{
|
||||
multiline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: true,
|
||||
},
|
||||
singleline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/member-ordering': [
|
||||
'error',
|
||||
{
|
||||
default:
|
||||
{
|
||||
order: 'as-written',
|
||||
},
|
||||
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'property',
|
||||
modifiers: ['readonly'],
|
||||
format: ['UPPER_CASE'],
|
||||
},
|
||||
{
|
||||
selector: 'property',
|
||||
format: ['camelCase'],
|
||||
},
|
||||
{
|
||||
selector: 'property',
|
||||
modifiers: ['private'],
|
||||
format: ['camelCase'],
|
||||
leadingUnderscore: 'allow',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-empty-function': 'error',
|
||||
'@typescript-eslint/no-empty-interface': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-inferrable-types': [
|
||||
'error',
|
||||
{
|
||||
ignoreParameters: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/quotes': [
|
||||
'error',
|
||||
'single',
|
||||
],
|
||||
'@typescript-eslint/semi': [
|
||||
'error',
|
||||
'always',
|
||||
],
|
||||
'@typescript-eslint/type-annotation-spacing': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'error',
|
||||
'header/header': [
|
||||
2,
|
||||
'line',
|
||||
[
|
||||
' (C) Copyright 2015 Moodle Pty Ltd.',
|
||||
'',
|
||||
' 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.',
|
||||
],
|
||||
1,
|
||||
],
|
||||
'promise/catch-or-return': [
|
||||
'warn',
|
||||
{
|
||||
allowFinally: true,
|
||||
terminationMethod: ['catch', 'finally'],
|
||||
},
|
||||
],
|
||||
'arrow-body-style': ['error', 'as-needed'],
|
||||
'array-bracket-spacing': ['error', 'never'],
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'constructor-super': 'error',
|
||||
'curly': 'error',
|
||||
'eol-last': 'error',
|
||||
'function-call-argument-newline': ['error', 'consistent'],
|
||||
'function-paren-newline': ['error', 'multiline-arguments'],
|
||||
'id-blacklist': [
|
||||
'error',
|
||||
'any',
|
||||
'Number',
|
||||
'number',
|
||||
'String',
|
||||
'string',
|
||||
'Boolean',
|
||||
'boolean',
|
||||
'Undefined',
|
||||
'undefined',
|
||||
],
|
||||
'id-match': 'error',
|
||||
'jsdoc/check-alignment': 'error',
|
||||
'jsdoc/newline-after-description': 'error',
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix',
|
||||
],
|
||||
'max-len': [
|
||||
'error',
|
||||
{
|
||||
code: 132,
|
||||
},
|
||||
],
|
||||
'new-parens': 'error',
|
||||
'no-bitwise': 'error',
|
||||
'no-cond-assign': 'error',
|
||||
'no-console': 'error',
|
||||
'no-debugger': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-empty': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-fallthrough': 'off',
|
||||
'no-invalid-this': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-multiple-empty-lines': ['error', { "max": 1 }],
|
||||
'no-new-wrappers': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-trailing-spaces': 'error',
|
||||
'no-unused-labels': 'error',
|
||||
'no-var': 'error',
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'one-var': ['error', 'never'],
|
||||
'padded-blocks': [
|
||||
'error',
|
||||
{
|
||||
classes: 'always',
|
||||
blocks: 'never',
|
||||
switches: 'never',
|
||||
},
|
||||
],
|
||||
'padding-line-between-statements': [
|
||||
'error',
|
||||
{
|
||||
blankLine: 'always',
|
||||
prev: '*',
|
||||
next: 'return',
|
||||
},
|
||||
],
|
||||
'prefer-arrow/prefer-arrow-functions': [
|
||||
'error',
|
||||
{
|
||||
singleReturnOnly: true,
|
||||
allowStandaloneDeclarations: true,
|
||||
},
|
||||
],
|
||||
'prefer-const': 'error',
|
||||
'prefer-spread': 'off',
|
||||
'quote-props': [
|
||||
'error',
|
||||
'consistent-as-needed',
|
||||
],
|
||||
'spaced-comment': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
markers: [
|
||||
'/',
|
||||
],
|
||||
},
|
||||
],
|
||||
'use-isnan': 'error',
|
||||
'yoda': 'error',
|
||||
},
|
||||
};
|
||||
|
||||
var testsConfig = Object.assign({}, appConfig);
|
||||
testsConfig['rules']['padded-blocks'] = [
|
||||
'error',
|
||||
{
|
||||
classes: 'always',
|
||||
switches: 'never',
|
||||
},
|
||||
];
|
||||
testsConfig['plugins'].push('jest');
|
||||
testsConfig['extends'].push('plugin:jest/recommended');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
overrides: [
|
||||
Object.assign({ files: ['*.ts'] }, appConfig),
|
||||
Object.assign({ files: ['*.test.ts'] }, testsConfig),
|
||||
{
|
||||
files: ['*.html'],
|
||||
extends: ['plugin:@angular-eslint/template/recommended'],
|
||||
rules: {
|
||||
'max-len': ['warn', { code: 140 }],
|
||||
'@angular-eslint/template/accessibility-valid-aria': 'warn',
|
||||
'@angular-eslint/template/accessibility-alt-text': 'error',
|
||||
'@angular-eslint/template/accessibility-elements-content': 'error',
|
||||
'@angular-eslint/template/accessibility-label-for': 'error',
|
||||
'@angular-eslint/template/no-positive-tabindex': 'error',
|
||||
'@angular-eslint/template/accessibility-table-scope': 'error',
|
||||
'@angular-eslint/template/accessibility-valid-aria': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['*.component.ts'],
|
||||
extends: ['plugin:@angular-eslint/template/process-inline-templates'],
|
||||
},
|
||||
],
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
# This file has been retrieved from angular repository.
|
||||
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# JS and TS files must always use LF for tools to work
|
||||
*.js eol=lf
|
||||
*.ts eol=lf
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
function check_success_exit {
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "$1"
|
||||
exit 1
|
||||
elif [ "$#" -gt 1 ]; then
|
||||
print_ok "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_success {
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "$1"
|
||||
elif [ "$#" -gt 1 ]; then
|
||||
print_ok "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
function print_success {
|
||||
if [ $? -ne 0 ]; then
|
||||
print_message "$1"
|
||||
$3=0
|
||||
else
|
||||
print_ok "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
function print_error {
|
||||
echo " ERROR: $1"
|
||||
}
|
||||
|
||||
function print_ok {
|
||||
echo " OK: $1"
|
||||
echo
|
||||
}
|
||||
|
||||
function print_message {
|
||||
echo "-------- $1"
|
||||
echo
|
||||
}
|
||||
|
||||
function print_title {
|
||||
stepnumber=$(($stepnumber + 1))
|
||||
echo
|
||||
echo "$stepnumber $1"
|
||||
echo '=================='
|
||||
}
|
||||
|
||||
function telegram_notify {
|
||||
if [ ! -z $TELEGRAM_APIKEY ] && [ ! -z $TELEGRAM_CHATID ] ; then
|
||||
MESSAGE="Travis error: $1%0ABranch: $TRAVIS_BRANCH%0ARepo: $TRAVIS_REPO_SLUG"
|
||||
URL="https://api.telegram.org/bot$TELEGRAM_APIKEY/sendMessage"
|
||||
|
||||
curl -s -X POST $URL -d chat_id=$TELEGRAM_CHATID -d text="$MESSAGE"
|
||||
fi
|
||||
}
|
||||
|
||||
function notify_on_error_exit {
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "$1"
|
||||
telegram_notify "$1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
source "./.github/scripts/functions.sh"
|
||||
BRANCH=${GITHUB_REF##*/}
|
||||
|
||||
if [ -z $GIT_TOKEN ] || [ -z $BRANCH ] || [ $GITHUB_REPOSITORY != 'moodlehq/moodleapp' ]; then
|
||||
print_error "Env vars not correctly defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git remote add mirror https://$GIT_TOKEN@github.com/moodlemobile/moodleapp.git
|
||||
git push -f mirror HEAD:$BRANCH
|
||||
notify_on_error_exit "MIRROR: Unsuccessful mirror, stopping..."
|
||||
git push -f mirror --tags
|
||||
notify_on_error_exit "MIRROR: Unsuccessful mirror tags, stopping..."
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
source "./.github/scripts/functions.sh"
|
||||
|
||||
if [ -z $GIT_TOKEN ] || [ $GITHUB_REPOSITORY != 'moodlemobile/moodleapp' ]; then
|
||||
print_error "Env vars not correctly defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_title "Run prepare scripts"
|
||||
# TODO Change branch name.
|
||||
git clone --depth 1 --single-branch --branch ionic5 https://$GIT_TOKEN@github.com/moodlemobile/apps-scripts.git ../scripts
|
||||
cp ../scripts/*.sh scripts/
|
||||
|
||||
if [ ! -f scripts/prepare.sh ]; then
|
||||
print_error "Prepare file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_title 'Prepare Build'
|
||||
./scripts/prepare.sh
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,19 @@
|
|||
name: Migration checks
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
checks:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- run: npm ci
|
||||
- run: result=$(find src -type f -iname '*.html' -exec sh -c 'cat {} | tr "\n" " " | grep -Eo "class=\"[^\"]+\"[^>]+class=\"" ' \; | wc -l); test $result -eq 0
|
||||
- run: npm install -D @ionic/v4-migration-tslint
|
||||
- run: npx tslint -c ionic-migration.json -p tsconfig.json
|
|
@ -0,0 +1,20 @@
|
|||
name: Mirror
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, integration ]
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
if: github.repository == 'moodlehq/moodleapp'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Mirror the branch and tags
|
||||
env:
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
run: ./.github/scripts/mirror.sh
|
|
@ -0,0 +1,20 @@
|
|||
name: Prepare
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, integration, freemium-master ]
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
if: github.repository == 'moodlemobile/moodleapp'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Prepare builds
|
||||
env:
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
run: ./.github/scripts/prepare.sh
|
|
@ -0,0 +1,59 @@
|
|||
name: Testing
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- name: Install npm packages
|
||||
run: npm ci
|
||||
- name: Check langindex
|
||||
run: |
|
||||
result=$(cat scripts/langindex.json | grep \"TBD\" | wc -l); test $result -eq 0
|
||||
if [ $result -ne 0 ]; then
|
||||
echo "There are lang strings to be decided on langindex.json"
|
||||
exit 1
|
||||
fi
|
||||
gulp
|
||||
langcount=`jq -r '. | length' src/assets/lang/en.json`
|
||||
freemiumcount=`jq 'keys' src/assets/lang/en.json | grep "freemium\." | wc -l | xargs`
|
||||
allcount=$(($langcount - $freemiumcount))
|
||||
langindexcount=`jq -r '. | length' scripts/langindex.json`
|
||||
if [ $allcount -ne $langindexcount ]; then
|
||||
echo "Lang file has $langcount ($freemiumcount) while langindex $langindexcount"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
langkeys=`jq -r 'keys[]' src/assets/lang/en.json | grep -v "freemium\."`
|
||||
langindex=`jq -r 'keys[]' scripts/langindex.json`
|
||||
found=0
|
||||
for i in $langkeys; do
|
||||
skip=
|
||||
for j in $langindex; do
|
||||
if [ "$i" == "$j" ]; then
|
||||
skip=1
|
||||
break;
|
||||
fi
|
||||
done
|
||||
[[ -n $skip ]] || { echo "$i key not found"; found=$(($found + 1)); }
|
||||
done
|
||||
if [ $found -ne 0 ]; then
|
||||
echo "Found $found missing langkeys"
|
||||
exit 1
|
||||
fi
|
||||
- name: Run Linter
|
||||
run: npm run lint
|
||||
- name: Run tests
|
||||
run: npm run test:ci
|
||||
- name: Production builds
|
||||
run: npm run build:prod
|
||||
- name: JavaScript code compatibility
|
||||
run: result=$(npx check-es-compat www/*.js 2> /dev/null | grep -v -E "Array\.prototype\.includes|Promise\.prototype\.finally|String\.prototype\.(matchAll|trimRight)|globalThis" | grep -Po "(?<=error).*?(?=\s+ecmascript)" | wc -l); test $result -eq 0
|
|
@ -3,47 +3,35 @@
|
|||
|
||||
*~
|
||||
*.sw[mnpcod]
|
||||
*.log
|
||||
.tmp
|
||||
*.tmp
|
||||
*.tmp.*
|
||||
log.txt
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.vscode/
|
||||
npm-debug.log*
|
||||
|
||||
.idea/
|
||||
.sourcemaps/
|
||||
.sass-cache/
|
||||
.tmp/
|
||||
.versions/
|
||||
coverage/
|
||||
dist/
|
||||
node_modules/
|
||||
tmp/
|
||||
temp/
|
||||
platforms/
|
||||
/plugins/
|
||||
/plugins/android.json
|
||||
/plugins/ios.json
|
||||
resources/android/icon
|
||||
resources/android/splash
|
||||
resources/ios/icon
|
||||
resources/ios/splash
|
||||
resources/windows/icon
|
||||
resources/windows/splash
|
||||
config.xml
|
||||
www/
|
||||
!www/README.md
|
||||
$RECYCLE.BIN/
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
UserInterfaceState.xcuserstate
|
||||
$RECYCLE.BIN/
|
||||
|
||||
e2e/build
|
||||
/desktop/*
|
||||
!/desktop/assets/
|
||||
!/desktop/electron.js
|
||||
src/configconstants.ts
|
||||
.moodleapp-dev-config
|
||||
*.log
|
||||
log.txt
|
||||
npm-debug.log*
|
||||
|
||||
/.idea
|
||||
/.ionic
|
||||
/.sass-cache
|
||||
/.sourcemaps
|
||||
/.versions
|
||||
/coverage
|
||||
/dist
|
||||
/node_modules
|
||||
/platforms
|
||||
/plugins
|
||||
/www
|
||||
/src/assets/lib
|
||||
|
||||
/moodle.config.*.json
|
||||
!/moodle.config.example.json
|
||||
|
||||
/src/assets/lang/*
|
||||
/src/assets/env.json
|
||||
|
|
85
.travis.yml
85
.travis.yml
|
@ -1,19 +1,6 @@
|
|||
os: linux
|
||||
dist: bionic
|
||||
group: edge
|
||||
language: node_js
|
||||
node_js: 11
|
||||
php: 7.1
|
||||
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-29.0.3
|
||||
- android-28
|
||||
- extra-google-google_play_services
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
dist: trusty
|
||||
node_js: 12
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
@ -23,42 +10,52 @@ before_cache:
|
|||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
||||
cache:
|
||||
npm: true
|
||||
directories:
|
||||
- $HOME/.npm
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
- $HOME/.android/build-cache
|
||||
|
||||
before_install:
|
||||
- nvm install 12
|
||||
- node --version
|
||||
- npm --version
|
||||
- nvm --version
|
||||
- npm ci
|
||||
- npm install npm@^6 -g
|
||||
|
||||
before_script:
|
||||
- npm install npm@latest -g
|
||||
- gulp
|
||||
- npx gulp
|
||||
|
||||
script:
|
||||
- scripts/build.sh
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: check
|
||||
if: NOT branch =~ /(master|integration|desktop)$/ AND env(DEPLOY) IS blank
|
||||
script: npm run build --bailOnLintError true --typeCheckOnLint true
|
||||
- stage: mirror
|
||||
if: branch IN (master, integration, desktop) AND repo = moodlehq/moodleapp AND type != cron
|
||||
script: scripts/mirror.sh
|
||||
- stage: prepare
|
||||
if: branch =~ /(master|^integration)$/ AND env(PREPARE) IS present AND env(PREPARE) = 1 AND type != cron AND tag IS blank
|
||||
script: scripts/aot.sh
|
||||
- stage: build
|
||||
name: "Build Android"
|
||||
if: env(DEPLOY) IS present AND type != cron AND ((env(DEPLOY) = 1 AND tag IS blank) OR (env(DEPLOY) = 2 AND tag IS present))
|
||||
dist: trusty
|
||||
if: env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank)
|
||||
language: android
|
||||
env:
|
||||
- BUILD_PLATFORM='android'
|
||||
before_install:
|
||||
- nvm install 11
|
||||
- node --version
|
||||
- npm --version
|
||||
- nvm --version
|
||||
- npm ci
|
||||
- npm install -g gulp
|
||||
script: scripts/aot.sh
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-29.0.3
|
||||
- android-29
|
||||
- extra-google-google_play_services
|
||||
- extra-google-m2repository
|
||||
- extra-android-m2repository
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libsecret-1-dev
|
||||
- stage: build
|
||||
name: "Build iOS"
|
||||
language: node_js
|
||||
if: env(BUILD_IOS) = 1 AND (env(DEPLOY) = 1 OR (env(DEPLOY) = 2 AND tag IS NOT blank))
|
||||
os: osx
|
||||
osx_image: xcode12.5
|
||||
- stage: test
|
||||
name: "End to end tests (mod_forum and mod_messages)"
|
||||
services:
|
||||
|
@ -66,20 +63,14 @@ jobs:
|
|||
if: type = cron
|
||||
script: scripts/test_e2e.sh "@app&&@mod_forum" "@app&&@mod_messages"
|
||||
- stage: test
|
||||
name: "End to end tests (mod_data and mod_survey)"
|
||||
name: "End to end tests (mod_course, core_course and mod_courses)"
|
||||
services:
|
||||
- docker
|
||||
if: type = cron
|
||||
script: scripts/test_e2e.sh "@app&&@mod_data" "@app&&@mod_survey"
|
||||
- stage: test
|
||||
name: "End to end tests (mod_comments, mod_course, core_course and mod_courses)"
|
||||
services:
|
||||
- docker
|
||||
if: type = cron
|
||||
script: scripts/test_e2e.sh "@app&&@mod_comments" "@app&&@mod_course" "@app&&@core_course" "@app&&@mod_courses"
|
||||
script: scripts/test_e2e.sh "@app&&@mod_course" "@app&&@core_course" "@app&&@mod_courses"
|
||||
- stage: test
|
||||
name: "End to end tests (others)"
|
||||
services:
|
||||
- docker
|
||||
if: type = cron
|
||||
script: scripts/test_e2e.sh "@app&&~@mod_forum&&~@mod_messages&&~@mod_comments&&~@mod_data&&~@mod_survey&&~@mod_course&&~@core_course&&~@mod_courses"
|
||||
script: scripts/test_e2e.sh "@app&&~@mod_forum&&~@mod_messages&&~@mod_course&&~@core_course&&~@mod_courses"
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Jest All",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"args": ["--runInBand"],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"windows": {
|
||||
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Jest Current File",
|
||||
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
||||
"args": [
|
||||
"${fileBasenameNoExtension}",
|
||||
"--config",
|
||||
"jest.config.js"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"disableOptimisticBPs": true,
|
||||
"windows": {
|
||||
"program": "${workspaceFolder}/node_modules/jest/bin/jest",
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"[Moodle] Component class": {
|
||||
"scope": "typescript",
|
||||
"prefix": "macomponent",
|
||||
"body": [
|
||||
"import { Component } from '@angular/core';",
|
||||
"",
|
||||
"@Component({",
|
||||
" selector: '$2${TM_FILENAME_BASE}',",
|
||||
" templateUrl: '$2${TM_FILENAME_BASE}.html',",
|
||||
"})",
|
||||
"export class ${1:${TM_FILENAME_BASE}}Component {",
|
||||
"",
|
||||
" $0",
|
||||
"",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Component class"
|
||||
},
|
||||
"[Moodle] Page class": {
|
||||
"scope": "typescript",
|
||||
"prefix": "mapage",
|
||||
"body": [
|
||||
"import { Component } from '@angular/core';",
|
||||
"",
|
||||
"@Component({",
|
||||
" selector: 'page-$2${TM_FILENAME_BASE}',",
|
||||
" templateUrl: '${TM_FILENAME_BASE}.html',",
|
||||
"})",
|
||||
"export class ${1:${TM_FILENAME_BASE}}Page {",
|
||||
"",
|
||||
" $0",
|
||||
"",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Page class"
|
||||
},
|
||||
"[Moodle] Module class": {
|
||||
"scope": "typescript",
|
||||
"prefix": "mamodule",
|
||||
"body": [
|
||||
"import { NgModule } from '@angular/core';",
|
||||
"",
|
||||
"@NgModule({",
|
||||
" $0",
|
||||
"})",
|
||||
"export class ${1}Module {}",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Module class"
|
||||
},
|
||||
"[Moodle] Lazy Module class": {
|
||||
"scope": "typescript",
|
||||
"prefix": "malazymodule",
|
||||
"body": [
|
||||
"import { NgModule } from '@angular/core';",
|
||||
"import { RouterModule, Routes } from '@angular/router';",
|
||||
"",
|
||||
"const routes: Routes = [",
|
||||
" $0",
|
||||
"];",
|
||||
"",
|
||||
"@NgModule({",
|
||||
" imports: [",
|
||||
" RouterModule.forChild(routes),",
|
||||
" ],",
|
||||
"})",
|
||||
"export class ${1}LazyModule {}",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Lazy Module class"
|
||||
},
|
||||
"[Moodle] Service Singleton": {
|
||||
"scope": "typescript",
|
||||
"prefix": "massingleton",
|
||||
"body": [
|
||||
"import { Injectable } from '@angular/core';",
|
||||
"import { makeSingleton } from '@singletons';",
|
||||
"",
|
||||
"/**",
|
||||
" * $2.",
|
||||
" */",
|
||||
"@Injectable({ providedIn: 'root' })",
|
||||
"export class ${1:${TM_FILENAME_BASE}}Service {",
|
||||
"",
|
||||
" $0",
|
||||
"",
|
||||
"}",
|
||||
"",
|
||||
"export const ${1:${TM_FILENAME_BASE}} = makeSingleton(${1:${TM_FILENAME_BASE}}Service);",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Service Singleton"
|
||||
},
|
||||
"[Moodle] Singleton": {
|
||||
"scope": "typescript",
|
||||
"prefix": "masingleton",
|
||||
"body": [
|
||||
"/**",
|
||||
" * Singleton$2.",
|
||||
" */",
|
||||
"export class ${1:${TM_FILENAME_BASE}} {",
|
||||
"",
|
||||
" $0",
|
||||
"",
|
||||
"}",
|
||||
""
|
||||
],
|
||||
"description": "[Moodle] Create a Pure Singleton"
|
||||
},
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
|
||||
"files.associations": {
|
||||
"moodle.config.json": "jsonc",
|
||||
"moodle.config.*.json": "jsonc",
|
||||
},
|
||||
|
||||
}
|
37
Dockerfile
37
Dockerfile
|
@ -1,27 +1,22 @@
|
|||
# This image is based on the fat node 11 image.
|
||||
# We require fat images as neither alpine, or slim, include git binaries.
|
||||
FROM node:11
|
||||
|
||||
# Port 8100 for ionic dev server.
|
||||
EXPOSE 8100
|
||||
|
||||
# Port 35729 is the live-reload server.
|
||||
EXPOSE 35729
|
||||
|
||||
# Port 53703 is the Chrome dev logger port.
|
||||
EXPOSE 53703
|
||||
## BUILD STAGE
|
||||
FROM node:14 as build-stage
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Prepare node dependencies
|
||||
RUN apt-get update && apt-get install libsecret-1-0 -y
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Build source
|
||||
ARG build_command="npm run build:prod"
|
||||
COPY . /app
|
||||
RUN ${build_command}
|
||||
|
||||
# Install npm libraries.
|
||||
RUN npm install && rm -rf /root/.npm
|
||||
## SERVE STAGE
|
||||
FROM nginx:alpine as serve-stage
|
||||
|
||||
# Run gulp before starting.
|
||||
RUN npx gulp
|
||||
|
||||
# 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
|
||||
|
||||
CMD ["npm", "run", "ionic:serve"]
|
||||
# Copy assets & config
|
||||
COPY --from=build-stage /app/www /usr/share/nginx/html
|
||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||
HEALTHCHECK --interval=10s --timeout=4s CMD curl -f http://localhost/assets/env.json || exit 1
|
||||
|
|
202
LICENSE
202
LICENSE
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
13
NOTICE
13
NOTICE
|
@ -1,13 +0,0 @@
|
|||
(C) Copyright 2015 Moodle Pty Ltd.
|
||||
|
||||
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.
|
|
@ -1,17 +0,0 @@
|
|||
Package updates known problems
|
||||
=================
|
||||
|
||||
@ionic/app-scripts 3.2.3 shows error Cannot find type definition file for '@types'. on ngc build.
|
||||
|
||||
com-darryncampbell-cordova-plugin-intent 2.0.0 onwards needs Android X Support. Unsupported on PGB.
|
||||
|
||||
typescript is needed to be less than 2.7 for @angular/compiler-cli
|
||||
|
||||
cordova-plugin-ionic-keyboard has problems on greater versions than 2.1.3
|
||||
|
||||
jszip has problems with "lie" dependency on greater versions than 3.1
|
||||
|
||||
promise.prototype.finally has problems on greater versions than 3.1
|
||||
|
||||
cordova-ios: should remain on 5.1 because of: https://github.com/apache/cordova-ios/pull/801
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"defaultProject": "app",
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"app": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "www",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*.svg",
|
||||
"input": "node_modules/ionicons/dist/ionicons/svg",
|
||||
"output": "./svg"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
{
|
||||
"input": "src/theme/theme.scss"
|
||||
}
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"optimization": {
|
||||
"scripts": false,
|
||||
"styles": true
|
||||
},
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "50mb",
|
||||
"maximumError": "100mb"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "app:build",
|
||||
"disableHostCheck": true,
|
||||
"port": 8100
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
},
|
||||
"ci": {
|
||||
"progress": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/core/**/*.html",
|
||||
"src/addons/**/*.html"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ionic-cordova-build": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-build",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionic-cordova-serve": {
|
||||
"builder": "@ionic/angular-toolkit:cordova-serve",
|
||||
"options": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build",
|
||||
"devServerTarget": "app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"cordovaBuildTarget": "app:ionic-cordova-build:production",
|
||||
"devServerTarget": "app:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"defaultCollection": "@ionic/angular-toolkit"
|
||||
},
|
||||
"schematics": {
|
||||
"@ionic/angular-toolkit:component": {
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@ionic/angular-toolkit:page": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# This file indicates the platforms supported. These targets will only be polyfilled automatically in CSS,
|
||||
# JavaScript polyfills have to be configured manually in `src/polyfills.ts`.
|
||||
#
|
||||
# In order to see which browsers are supported you can run `npx browserslist` (or visit https://browserslist.dev/).
|
||||
#
|
||||
# Keep in mind that not all versions of all browsers will be displayed, here's all the versions available:
|
||||
# https://caniuse.com/ciu/comparison
|
||||
#
|
||||
# From time to time, you'll want to update the database by running `npx browserslist@latest --update-db`.
|
||||
#
|
||||
# More info: https://github.com/browserslist/browserslist
|
||||
|
||||
Android >= 5
|
||||
iOS >= 11
|
||||
Chrome >= 61
|
28
config.xml
28
config.xml
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget android-versionCode="39400" id="com.moodle.moodlemobile" ios-CFBundleVersion="3.9.4.0" version="3.9.4" versionCode="39400" 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 android-versionCode="39500" id="com.moodle.moodlemobile" ios-CFBundleVersion="3.9.5.0" version="3.9.5" versionCode="39500" 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>
|
||||
|
@ -31,6 +31,7 @@
|
|||
<preference name="BackupWebStorage" value="none" />
|
||||
<preference name="ScrollEnabled" value="false" />
|
||||
<preference name="KeyboardDisplayRequiresUserAction" value="false" />
|
||||
<preference name="HideKeyboardFormAccessoryBar" value="false" />
|
||||
<preference name="AllowInlineMediaPlayback" value="true" />
|
||||
<preference name="LoadUrlTimeoutValue" value="60000" />
|
||||
<preference name="load-url-timeout" value="60000" />
|
||||
|
@ -38,9 +39,10 @@
|
|||
<preference name="SplashScreenDelay" value="15000" />
|
||||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="android-minSdkVersion" value="19" />
|
||||
<preference name="android-targetSdkVersion" value="29" />
|
||||
<preference name="android-minSdkVersion" value="22" />
|
||||
<preference name="android-targetSdkVersion" value="30" />
|
||||
<preference name="AndroidPersistentFileLocation" value="Compatibility" />
|
||||
<preference name="AndroidInsecureFileModeEnabled" value="true" />
|
||||
<preference name="CustomURLSchemePluginClearsAndroidIntent" value="true" />
|
||||
<preference name="iosPersistentFileLocation" value="Compatibility" />
|
||||
<preference name="iosScheme" value="moodleappfs" />
|
||||
|
@ -222,6 +224,16 @@
|
|||
<config-file parent="/*" target="AndroidManifest.xml">
|
||||
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
|
||||
</config-file>
|
||||
<config-file parent="/*" target="AndroidManifest.xml">
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
</intent>
|
||||
</queries>
|
||||
</config-file>
|
||||
</platform>
|
||||
<platform name="ios">
|
||||
<resource-file src="GoogleService-Info.plist" />
|
||||
|
@ -244,7 +256,12 @@
|
|||
<true />
|
||||
</edit-config>
|
||||
<edit-config file="*-Info.plist" mode="merge" target="CFBundleShortVersionString">
|
||||
<string>3.9.4</string>
|
||||
<string>3.9.5</string>
|
||||
</edit-config>
|
||||
<edit-config file="*-Info.plist" mode="overwrite" target="CFBundleLocalizations">
|
||||
<array>
|
||||
<string>en</string>
|
||||
</array>
|
||||
</edit-config>
|
||||
<config-file parent="FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED" target="*-Info.plist">
|
||||
<string>YES</string>
|
||||
|
@ -268,6 +285,9 @@
|
|||
<config-file parent="UIRequiresFullScreen" target="*-Info.plist">
|
||||
<false />
|
||||
</config-file>
|
||||
<config-file parent="NSCrossWebsiteTrackingUsageDescription" target="*-Info.plist">
|
||||
<string>This app needs third party cookies to correctly render embedded content from the Moodle site.</string>
|
||||
</config-file>
|
||||
<config-file parent="CFBundleDocumentTypes" target="*-Info.plist">
|
||||
<array>
|
||||
<dict>
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
// New copy task for font files and config.json.
|
||||
module.exports = {
|
||||
// Override Ionic copyFonts task to exclude Roboto and Noto fonts.
|
||||
copyFonts: {
|
||||
src: ['{{ROOT}}/node_modules/ionicons/dist/fonts/**/*'],
|
||||
dest: '{{WWW}}/assets/fonts'
|
||||
},
|
||||
copyFontAwesome: {
|
||||
src: ['{{ROOT}}/node_modules/font-awesome/fonts/**/*'],
|
||||
dest: '{{WWW}}/assets/fonts'
|
||||
},
|
||||
copyConfig: {
|
||||
src: ['{{ROOT}}/src/config.json'],
|
||||
dest: '{{WWW}}/'
|
||||
},
|
||||
copyMathJaxMain: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/MathJax.js'],
|
||||
dest: '{{WWW}}/lib/mathjax'
|
||||
},
|
||||
copyMathJaxExtensions: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/extensions/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/extensions'
|
||||
},
|
||||
copyMathJaxElement: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/jax/element/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/jax/element'
|
||||
},
|
||||
copyMathJaxInput: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/jax/input/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/jax/input'
|
||||
},
|
||||
copyMathJaxSVGOutput: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/jax/output/SVG/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/jax/output/SVG'
|
||||
},
|
||||
copyMathJaxPreviewHTMLOutput: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/jax/output/PreviewHTML/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/jax/output/PreviewHTML'
|
||||
},
|
||||
copyMathJaxLocalization: {
|
||||
src: ['{{ROOT}}/node_modules/mathjax/localization/**/*'],
|
||||
dest: '{{WWW}}/lib/mathjax/localization'
|
||||
},
|
||||
copyH5P: {
|
||||
src: ['{{ROOT}}/src/core/h5p/assets/**/*'],
|
||||
dest: '{{WWW}}/h5p/'
|
||||
},
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
// Adding Font Awesome to includePaths
|
||||
module.exports = {
|
||||
includePaths: [
|
||||
'node_modules/ionic-angular/themes',
|
||||
'node_modules/ionicons/dist/scss',
|
||||
'node_modules/ionic-angular/fonts',
|
||||
'node_modules/font-awesome/scss'
|
||||
],
|
||||
includeFiles: [
|
||||
/\.(s(c|a)ss)$/i
|
||||
],
|
||||
excludeFiles: [
|
||||
/\.(wp).(scss)$/i
|
||||
]
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
// Check https://github.com/mishoo/UglifyJS2/tree/harmony#minify-options-structure
|
||||
module.exports = {
|
||||
/**
|
||||
* mangle: uglify 2's mangle option
|
||||
*/
|
||||
mangle: {
|
||||
keep_classnames: true,
|
||||
keep_fnames: true
|
||||
},
|
||||
/**
|
||||
* compress: uglify 2's compress option
|
||||
*/
|
||||
compress: {
|
||||
toplevel: true,
|
||||
pure_getters: true
|
||||
},
|
||||
keep_classnames: true,
|
||||
keep_fnames: true
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
const { resolve } = require('path');
|
||||
const webpackMerge = require('webpack-merge');
|
||||
const { dev, prod } = require('@ionic/app-scripts/config/webpack.config');
|
||||
|
||||
const customConfig = {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@addon': resolve('./src/addon'),
|
||||
'@app': resolve('./src/app'),
|
||||
'@classes': resolve('./src/classes'),
|
||||
'@core': resolve('./src/core'),
|
||||
'@providers': resolve('./src/providers'),
|
||||
'@components': resolve('./src/components'),
|
||||
'@directives': resolve('./src/directives'),
|
||||
'@pipes': resolve('./src/pipes'),
|
||||
'@singletons': resolve('./src/singletons'),
|
||||
}
|
||||
},
|
||||
externals: [
|
||||
(function () {
|
||||
var IGNORES = ["fs","child_process","electron","path","assert","cluster","crypto","dns","domain","events","http","https","net","os","process","punycode","querystring","readline","repl","stream","string_decoder","tls","tty","dgram","url","util","v8","vm","zlib"];
|
||||
return function (context, request, callback) {
|
||||
if (IGNORES.indexOf(request) >= 0) {
|
||||
return callback(null, "require('" + request + "')");
|
||||
}
|
||||
return callback();
|
||||
};
|
||||
})()
|
||||
],
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.node$/,
|
||||
use: 'node-loader'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
dev: webpackMerge(dev, customConfig),
|
||||
prod: webpackMerge(prod, customConfig),
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.inherit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>2NU57U5PAW.com.moodle.moodledesktop</string>
|
||||
</array>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,38 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script to sign macOSX pkg.
|
||||
# https://www.electronjs.org/docs/tutorial/mac-app-store-submission-guide
|
||||
#
|
||||
|
||||
# Name of your app.
|
||||
APP="Moodle Desktop"
|
||||
# The name of certificates you requested.
|
||||
APP_KEY="3rd Party Mac Developer Application: Moodle Pty Ltd (2NU57U5PAW)"
|
||||
INSTALLER_KEY="3rd Party Mac Developer Installer: Moodle Pty Ltd (2NU57U5PAW)"
|
||||
|
||||
|
||||
BASEPATH="desktop/dist/mas"
|
||||
# The path of your app to sign.
|
||||
APP_PATH="${BASEPATH}/${APP}.app"
|
||||
# The path to the location you want to put the signed package.
|
||||
RESULT_PATH="${BASEPATH}/${APP}.pkg"
|
||||
|
||||
# The path of your plist files.
|
||||
CHILD_PLIST="desktop/assets/mac/child.plist"
|
||||
PARENT_PLIST="desktop/assets/mac/parent.plist"
|
||||
LOGINHELPER_PLIST="desktop/assets/mac/loginhelper.plist"
|
||||
|
||||
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
|
||||
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/Contents/MacOS/$APP Login Helper"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$LOGINHELPER_PLIST" "$APP_PATH/Contents/Library/LoginItems/$APP Login Helper.app/"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP"
|
||||
codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH"
|
||||
|
||||
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
|
||||
<Identity Name="3312ADB7.MoodleDesktop"
|
||||
ProcessorArchitecture="x64"
|
||||
Publisher="CN=33CDCDF6-1EB5-4827-9897-ED25C91A32F6"
|
||||
Version="3.9.4.0" />
|
||||
<Properties>
|
||||
<DisplayName>Moodle Desktop</DisplayName>
|
||||
<PublisherDisplayName>Moodle Pty Ltd.</PublisherDisplayName>
|
||||
<Description>The official app for Moodle.</Description>
|
||||
<Logo>assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
<Resources>
|
||||
<Resource Language="en" />
|
||||
</Resources>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14316.0" MaxVersionTested="10.0.14316.0" />
|
||||
</Dependencies>
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust"/>
|
||||
</Capabilities>
|
||||
<Applications>
|
||||
<Application Id="com.moodle.moodlemobile" Executable="app\Moodle Desktop.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<uap:VisualElements
|
||||
BackgroundColor="#464646"
|
||||
DisplayName="Moodle Desktop"
|
||||
Square150x150Logo="assets\Square150x150Logo.png"
|
||||
Square44x44Logo="assets\Square44x44Logo.png"
|
||||
Description="Moodle Desktop: The official desktop app for Moodle.">
|
||||
<uap:DefaultTile Wide310x150Logo="assets\Wide310x150Logo.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="moodlemobile">
|
||||
<uap:DisplayName>Moodle Mobile URI Scheme</uap:DisplayName>
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
</Package>
|
|
@ -1,265 +0,0 @@
|
|||
|
||||
// dialog isn't used, but not requiring it throws an error.
|
||||
const {app, BrowserWindow, ipcMain, shell, dialog, Menu} = require('electron');
|
||||
const path = require('path');
|
||||
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.
|
||||
let mainWindow,
|
||||
appName = 'Moodle Desktop', // Default value.
|
||||
isReady = false,
|
||||
configRead = false;
|
||||
|
||||
function createWindow() {
|
||||
// Create the browser window.
|
||||
var width = 800,
|
||||
height = 600;
|
||||
|
||||
const screen = require('electron').screen;
|
||||
if (screen) {
|
||||
const display = screen.getPrimaryDisplay();
|
||||
if (display && display.workArea) {
|
||||
width = display.workArea.width || width;
|
||||
height = display.workArea.height || height;
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
width: width,
|
||||
height: height,
|
||||
minWidth: 400,
|
||||
minHeight: 400,
|
||||
textAreasAreResizable: false,
|
||||
plugins: true,
|
||||
show: false // Don't show it until it's ready to prevent showing a blank screen.
|
||||
};
|
||||
|
||||
if (os.platform().indexOf('linux') === 0) {
|
||||
options.icon = path.join(__dirname, '/../www/assets/icon/icon.png');
|
||||
}
|
||||
|
||||
mainWindow = new BrowserWindow(options);
|
||||
|
||||
// And load the index.html of the app.
|
||||
mainWindow.loadURL(url.format({
|
||||
pathname: path.join(__dirname, '/../www/index.html'),
|
||||
protocol: 'file:',
|
||||
slashes: true
|
||||
}));
|
||||
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
mainWindow.maximize();
|
||||
});
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', () => {
|
||||
// Dereference the window object.
|
||||
mainWindow = null
|
||||
});
|
||||
|
||||
mainWindow.on('focus', () => {
|
||||
mainWindow.webContents.send('coreAppFocused'); // Send an event to the main window.
|
||||
});
|
||||
|
||||
// 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.
|
||||
// For some reason, gotTheLock is always false in signed Mac apps so we should ingore it.
|
||||
// See https://github.com/electron/electron/issues/15958
|
||||
var gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
if (!gotTheLock && !isMac) {
|
||||
// It's not the main instance of the app, kill it.
|
||||
app.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
// Another instance was launched. If it was launched with a URL, it should be in the second param.
|
||||
if (commandLine && commandLine[1]) {
|
||||
appLaunched(commandLine[1]);
|
||||
} else {
|
||||
focusApp();
|
||||
}
|
||||
});
|
||||
|
||||
// This method will be called when Electron has finished initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', function() {
|
||||
isReady = true;
|
||||
|
||||
createWindow();
|
||||
|
||||
if (configRead) {
|
||||
setAppMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', () => {
|
||||
app.exit();
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
// Read the config.json file.
|
||||
fs.readFile(path.join(__dirname, 'config.json'), 'utf8', (err, data) => {
|
||||
configRead = true;
|
||||
|
||||
// Default values.
|
||||
var ssoScheme = 'moodlemobile',
|
||||
appId = 'com.moodle.moodlemobile';
|
||||
|
||||
if (!err) {
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
ssoScheme = data.customurlscheme;
|
||||
appName = data.desktopappname;
|
||||
appId = data.app_id;
|
||||
} catch(ex) {}
|
||||
}
|
||||
|
||||
// Set default protocol (custom URL scheme).
|
||||
app.setAsDefaultProtocolClient(ssoScheme);
|
||||
|
||||
// Fix notifications in Windows.
|
||||
app.setAppUserModelId(appId);
|
||||
|
||||
if (isReady) {
|
||||
setAppMenu();
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for open-url events (Mac OS only).
|
||||
app.on('open-url', (event, url) => {
|
||||
event.preventDefault();
|
||||
appLaunched(url);
|
||||
});
|
||||
|
||||
function appLaunched(url) {
|
||||
// App was launched again with a URL. Focus the main window and send an event to treat the URL.
|
||||
if (mainWindow) {
|
||||
focusApp();
|
||||
mainWindow.webContents.send('coreAppLaunched', url); // Send an event to the main window.
|
||||
}
|
||||
}
|
||||
|
||||
function focusApp() {
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
}
|
||||
mainWindow.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for events sent by the renderer processes (windows).
|
||||
ipcMain.on('openItem', (event, path) => {
|
||||
var result;
|
||||
|
||||
// Add file:// protocol if it isn't there.
|
||||
if (path.indexOf('file://') == -1) {
|
||||
path = 'file://' + path;
|
||||
}
|
||||
|
||||
if (os.platform().indexOf('darwin') > -1) {
|
||||
// Use openExternal in MacOS because openItem doesn't work in sandboxed apps.
|
||||
// https://github.com/electron/electron/issues/9005
|
||||
result = shell.openExternal(path);
|
||||
} else {
|
||||
result = shell.openItem(path);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// Cannot open file, probably no app to handle it. Open the folder.
|
||||
result = shell.showItemInFolder(path.replace('file://', ''));
|
||||
}
|
||||
|
||||
event.returnValue = result;
|
||||
});
|
||||
|
||||
ipcMain.on('closeSecondaryWindows', () => {
|
||||
const windows = BrowserWindow.getAllWindows();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
const win = windows[i];
|
||||
if (!win.isDestroyed() && (!mainWindow || win.id != mainWindow.id)) {
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('focusApp', focusApp);
|
||||
|
||||
// Configure the app's menu.
|
||||
function setAppMenu() {
|
||||
let menuTemplate = [
|
||||
{
|
||||
label: appName,
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'CmdorCtrl+Q',
|
||||
role: 'close'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Cut',
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
role: 'copy'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
role: 'paste'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
role: 'selectall'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
role: 'help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Docs',
|
||||
accelerator: 'CmdOrCtrl+H',
|
||||
click() {
|
||||
shell.openExternal('https://docs.moodle.org/en/Moodle_Mobile');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate));
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// (C) Copyright 2021 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const { exec } = require('child_process');
|
||||
const { resolve } = require('path');
|
||||
|
||||
/**
|
||||
* Task to build a Moodle plugin to run Behat tests.
|
||||
*/
|
||||
class BuildBehatPluginTask {
|
||||
|
||||
/**
|
||||
* Check whether Behat is configured to run app tests.
|
||||
*
|
||||
* @returns Whether Behat is configured.
|
||||
*/
|
||||
static isBehatConfigured() {
|
||||
if (process.env.MOODLE_APP_BEHAT_PLUGIN_PATH) {
|
||||
return !['0', 'false'].includes(process.env.MOODLE_APP_BEHAT_PLUGIN_PATH);
|
||||
}
|
||||
|
||||
return !!process.env.MOODLE_DOCKER_WWWROOT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param done Function to call when done.
|
||||
*/
|
||||
run(done) {
|
||||
exec(resolve(__dirname, '../scripts/build-behat-plugin.js'), done);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BuildBehatPluginTask;
|
|
@ -1,138 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const gulp = require('gulp');
|
||||
const through = require('through');
|
||||
const bufferFrom = require('buffer-from');
|
||||
const rename = require('gulp-rename');
|
||||
const exec = require('child_process').exec;
|
||||
|
||||
const LICENSE = '' +
|
||||
'// (C) Copyright 2015 Moodle Pty Ltd.\n' +
|
||||
'//\n' +
|
||||
'// Licensed under the Apache License, Version 2.0 (the "License");\n' +
|
||||
'// you may not use this file except in compliance with the License.\n' +
|
||||
'// You may obtain a copy of the License at\n' +
|
||||
'//\n' +
|
||||
'// http://www.apache.org/licenses/LICENSE-2.0\n' +
|
||||
'//\n' +
|
||||
'// Unless required by applicable law or agreed to in writing, software\n' +
|
||||
'// distributed under the License is distributed on an "AS IS" BASIS,\n' +
|
||||
'// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' +
|
||||
'// See the License for the specific language governing permissions and\n' +
|
||||
'// limitations under the License.\n\n';
|
||||
|
||||
/**
|
||||
* Task to convert config.json into a TypeScript class.
|
||||
*/
|
||||
class BuildConfigTask {
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param path Path to the config file.
|
||||
* @param done Function to call when done.
|
||||
*/
|
||||
run(path, done) {
|
||||
const self = this;
|
||||
|
||||
// Get the last commit.
|
||||
exec('git log -1 --pretty=format:"%H"', (err, commit, stderr) => {
|
||||
if (err) {
|
||||
console.error('An error occurred while getting the last commit: ' + err);
|
||||
} else if (stderr) {
|
||||
console.error('An error occurred while getting the last commit: ' + stderr);
|
||||
}
|
||||
|
||||
gulp.src(path)
|
||||
.pipe(through(function(file) {
|
||||
// Convert the contents of the file into a TypeScript class.
|
||||
// Disable the rule variable-name in the file.
|
||||
const config = JSON.parse(file.contents.toString());
|
||||
let contents = LICENSE + '// tslint:disable: variable-name\n' + 'export class CoreConfigConstants {\n';
|
||||
|
||||
for (let key in config) {
|
||||
let value = self.transformValue(config[key]);
|
||||
|
||||
if (typeof config[key] != 'number' && typeof config[key] != 'boolean' && typeof config[key] != 'string') {
|
||||
key = key + ': any';
|
||||
}
|
||||
|
||||
// If key has quotation marks, remove them.
|
||||
if (key[0] == '"') {
|
||||
key = key.substr(1, key.length - 2);
|
||||
}
|
||||
contents += ' static ' + key + ' = ' + value + ';\n';
|
||||
}
|
||||
|
||||
// Add compilation info.
|
||||
contents += ' static compilationtime = ' + Date.now() + ';\n';
|
||||
contents += ' static lastcommit = \'' + commit + '\';\n';
|
||||
|
||||
contents += '}\n';
|
||||
|
||||
file.contents = bufferFrom(contents);
|
||||
|
||||
this.emit('data', file);
|
||||
}))
|
||||
.pipe(rename('configconstants.ts'))
|
||||
.pipe(gulp.dest('./src'))
|
||||
.on('end', done);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively transform a config value into personalized TS.
|
||||
*
|
||||
* @param value Value to convert
|
||||
* @return Converted value.
|
||||
*/
|
||||
transformValue(value) {
|
||||
if (typeof value == 'string') {
|
||||
// Wrap the string in ' and escape them.
|
||||
return "'" + value.replace(/([^\\])'/g, "$1\\'") + "'";
|
||||
}
|
||||
|
||||
if (typeof value != 'number' && typeof value != 'boolean') {
|
||||
const isArray = Array.isArray(value);
|
||||
let contents = '';
|
||||
|
||||
let quoteKeys = false;
|
||||
if (!isArray) {
|
||||
for (let key in value) {
|
||||
if (key.indexOf('-') >= 0) {
|
||||
quoteKeys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in value) {
|
||||
value[key] = this.transformValue(value[key]);
|
||||
|
||||
const quotedKey = quoteKeys ? "'" + key + "'" : key;
|
||||
contents += ' ' + (isArray ? '' : quotedKey + ': ') + value[key] + ",\n";
|
||||
}
|
||||
|
||||
contents += (isArray ? ']' : '}');
|
||||
|
||||
return (isArray ? '[' : '{') + "\n" + contents.replace(/^/gm, ' ');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BuildConfigTask;
|
|
@ -0,0 +1,76 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const { existsSync, readFileSync, writeFile } = require('fs');
|
||||
const { parse: parseJsonc } = require('jsonc-parser');
|
||||
const { resolve } = require('path');
|
||||
|
||||
function getConfig(environment) {
|
||||
const envSuffixesMap = {
|
||||
testing: ['test', 'testing'],
|
||||
development: ['dev', 'development'],
|
||||
production: ['prod', 'production'],
|
||||
};
|
||||
const config = parseJsonc(readFileSync(resolve(__dirname, '../moodle.config.json')).toString());
|
||||
const envSuffixes = (envSuffixesMap[environment] || []);
|
||||
const envConfigPath = envSuffixes.map(suffix => resolve(__dirname, `../moodle.config.${suffix}.json`)).find(existsSync);
|
||||
|
||||
if (envConfigPath) {
|
||||
const envConfig = parseJsonc(readFileSync(envConfigPath).toString());
|
||||
|
||||
for (const [key, value] of Object.entries(envConfig)) {
|
||||
config[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
function getBuild(environment) {
|
||||
const { version } = JSON.parse(readFileSync(resolve(__dirname, '../package.json')));
|
||||
|
||||
return {
|
||||
version,
|
||||
isProduction: environment === 'production',
|
||||
isTesting: environment === 'testing',
|
||||
isDevelopment: environment === 'development',
|
||||
lastCommitHash: execSync('git log -1 --pretty=format:"%H"').toString(),
|
||||
compilationTime: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to build an env file depending on the current environment.
|
||||
*/
|
||||
class BuildEnvTask {
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param done Function to call when done.
|
||||
*/
|
||||
run(done) {
|
||||
const envFile = resolve(__dirname, '../src/assets/env.json');
|
||||
const env = {
|
||||
config: getConfig(process.env.NODE_ENV || 'development'),
|
||||
build: getBuild(process.env.NODE_ENV || 'development'),
|
||||
};
|
||||
|
||||
writeFile(envFile, JSON.stringify(env), done);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BuildEnvTask;
|
|
@ -41,22 +41,24 @@ class BuildLangTask {
|
|||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param language Language to treat.
|
||||
* @param langPaths Paths to the possible language files.
|
||||
* @param done Function to call when done.
|
||||
*/
|
||||
run(language, langPaths, done) {
|
||||
const filename = language + '.json';
|
||||
run(langPaths, done) {
|
||||
const data = {};
|
||||
let firstFile = null;
|
||||
const self = this;
|
||||
|
||||
const paths = langPaths.map((path) => {
|
||||
if (path.slice(-1) != '/') {
|
||||
if (path.endsWith('.json')) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (!path.endsWith('/')) {
|
||||
path = path + '/';
|
||||
}
|
||||
|
||||
return path + language + '.json';
|
||||
return path + 'lang.json';
|
||||
});
|
||||
|
||||
gulp.src(paths, { allowEmpty: true })
|
||||
|
@ -72,7 +74,7 @@ class BuildLangTask {
|
|||
/* This implementation is based on gulp-jsoncombine module.
|
||||
* https://github.com/reflog/gulp-jsoncombine */
|
||||
if (firstFile) {
|
||||
const joinedPath = pathLib.join(firstFile.base, language + '.json');
|
||||
const joinedPath = pathLib.join(firstFile.base, 'en.json');
|
||||
|
||||
const joinedFile = new File({
|
||||
cwd: firstFile.cwd,
|
||||
|
@ -103,13 +105,24 @@ class BuildLangTask {
|
|||
}
|
||||
|
||||
try {
|
||||
let srcPos = file.path.lastIndexOf('/src/');
|
||||
if (srcPos == -1) {
|
||||
// It's probably a Windows environment.
|
||||
srcPos = file.path.lastIndexOf('\\src\\');
|
||||
}
|
||||
let path = file.path;
|
||||
let length = 9;
|
||||
|
||||
let srcPos = path.lastIndexOf('/src/app/');
|
||||
if (srcPos < 0) {
|
||||
// It's probably a Windows environment.
|
||||
srcPos = path.lastIndexOf('\\src\\app\\');
|
||||
}
|
||||
if (srcPos < 0) {
|
||||
length = 5;
|
||||
srcPos = path.lastIndexOf('/src/');
|
||||
if (srcPos < 0) {
|
||||
// It's probably a Windows environment.
|
||||
srcPos = path.lastIndexOf('\\src\\');
|
||||
}
|
||||
}
|
||||
path = path.substr(srcPos + length);
|
||||
|
||||
const path = file.path.substr(srcPos + 5);
|
||||
data[path] = JSON.parse(file.contents.toString());
|
||||
} catch (err) {
|
||||
console.log('Error parsing JSON: ' + err);
|
||||
|
@ -125,42 +138,32 @@ class BuildLangTask {
|
|||
treatMergedData(data) {
|
||||
const merged = {};
|
||||
const mergedOrdered = {};
|
||||
const getPrefix = (path) => {
|
||||
const folders = path.split(/[\/\\]/);
|
||||
let filename = folders.pop();
|
||||
|
||||
switch (folders[0]) {
|
||||
case 'core':
|
||||
switch (folders[1]) {
|
||||
case 'features':
|
||||
return `core.${folders[2]}.`;
|
||||
default:
|
||||
return 'core.';
|
||||
}
|
||||
case 'addons':
|
||||
return `addon.${folders.slice(1).join('_')}.`;
|
||||
case 'assets':
|
||||
filename = filename.split('.').slice(0, -1).join('.');
|
||||
return `assets.${filename}.`;
|
||||
default:
|
||||
return `${folders[0]}.${folders[1]}.`;
|
||||
}
|
||||
}
|
||||
|
||||
for (let filepath in data) {
|
||||
const pathSplit = filepath.split(/[\/\\]/);
|
||||
let prefix;
|
||||
|
||||
pathSplit.pop();
|
||||
|
||||
switch (pathSplit[0]) {
|
||||
case 'lang':
|
||||
prefix = 'core';
|
||||
break;
|
||||
case 'core':
|
||||
if (pathSplit[1] == 'lang') {
|
||||
// Not used right now.
|
||||
prefix = 'core';
|
||||
} else {
|
||||
prefix = 'core.' + pathSplit[1];
|
||||
}
|
||||
break;
|
||||
case 'addon':
|
||||
// Remove final item 'lang'.
|
||||
pathSplit.pop();
|
||||
// Remove first item 'addon'.
|
||||
pathSplit.shift();
|
||||
|
||||
// For subplugins. We'll use plugin_subfolder_subfolder2_...
|
||||
// E.g. 'mod_assign_feedback_comments'.
|
||||
prefix = 'addon.' + pathSplit.join('_');
|
||||
break;
|
||||
case 'assets':
|
||||
prefix = 'assets.' + pathSplit[1];
|
||||
break;
|
||||
}
|
||||
|
||||
const prefix = getPrefix(filepath);
|
||||
if (prefix) {
|
||||
this.addProperties(merged, data[filepath], prefix + '.');
|
||||
this.addProperties(merged, data[filepath], prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,164 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const gulp = require('gulp');
|
||||
const through = require('through');
|
||||
const bufferFrom = require('buffer-from');
|
||||
const concat = require('gulp-concat');
|
||||
const pathLib = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* Task to combine scss into a single file.
|
||||
*/
|
||||
class CombineScssTask {
|
||||
|
||||
/**
|
||||
* Finds the file and returns its content.
|
||||
*
|
||||
* @param capture Import file path.
|
||||
* @param baseDir Directory where the file was found.
|
||||
* @param paths Alternative paths where to find the imports.
|
||||
* @param parsedFiles Already parsed files to reduce size of the result.
|
||||
* @return Partially combined scss.
|
||||
*/
|
||||
getReplace(capture, baseDir, paths, parsedFiles) {
|
||||
let parse = pathLib.parse(pathLib.resolve(baseDir, capture + '.scss'));
|
||||
let file = parse.dir + '/' + parse.name;
|
||||
|
||||
if (file.slice(-3) === '.wp') {
|
||||
console.log('Windows Phone not supported "' + capture);
|
||||
// File was already parsed, leave the import commented.
|
||||
return '// @import "' + capture + '";';
|
||||
}
|
||||
|
||||
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.
|
||||
let x = 0;
|
||||
while (!fs.existsSync(file + '.scss') && paths.length > x) {
|
||||
parse = pathLib.parse(pathLib.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);
|
||||
const text = fs.readFileSync(file);
|
||||
|
||||
// Recursive call.
|
||||
return this.scssCombine(text, parse.dir, paths, parsedFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param done Function to call when done.
|
||||
*/
|
||||
run(done) {
|
||||
const paths = [
|
||||
'node_modules/ionic-angular/themes/',
|
||||
'node_modules/font-awesome/scss/',
|
||||
'node_modules/ionicons/dist/scss/'
|
||||
];
|
||||
const parsedFiles = [];
|
||||
const self = this;
|
||||
|
||||
gulp.src([
|
||||
'./src/theme/variables.scss',
|
||||
'./node_modules/ionic-angular/themes/ionic.globals.*.scss',
|
||||
'./node_modules/ionic-angular/themes/ionic.components.scss',
|
||||
'./src/**/*.scss',
|
||||
]).pipe(through(function(file) { // Combine them based on @import and save it to stream.
|
||||
if (file.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parsedFiles.push(file);
|
||||
file.contents = bufferFrom(self.scssCombine(
|
||||
file.contents, pathLib.dirname(file.path), paths, parsedFiles));
|
||||
|
||||
this.emit('data', file);
|
||||
})).pipe(concat('combined.scss')) // Concat the stream output in single file.
|
||||
.pipe(gulp.dest('.')) // Save file to destination.
|
||||
.on('end', done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine scss files with its imports
|
||||
*
|
||||
* @param content Scss string to treat.
|
||||
* @param baseDir Directory where the file was found.
|
||||
* @param paths Alternative paths where to find the imports.
|
||||
* @param parsedFiles Already parsed files to reduce size of the result.
|
||||
* @return Scss string with the replaces done.
|
||||
*/
|
||||
scssCombine(content, baseDir, paths, parsedFiles) {
|
||||
// Content is a Buffer, convert to string.
|
||||
if (typeof content != "string") {
|
||||
content = content.toString();
|
||||
}
|
||||
|
||||
// Search of single imports.
|
||||
let regex = /@import[ ]*['"](.*)['"][ ]*;/g;
|
||||
|
||||
if (regex.test(content)) {
|
||||
return content.replace(regex, (m, capture) => {
|
||||
if (capture == "bmma") {
|
||||
return m;
|
||||
}
|
||||
|
||||
return this.getReplace(capture, baseDir, paths, parsedFiles);
|
||||
});
|
||||
}
|
||||
|
||||
// Search of multiple imports.
|
||||
regex = /@import(?:[ \n]+['"](.*)['"][,]?[ \n]*)+;/gm;
|
||||
if (regex.test(content)) {
|
||||
return content.replace(regex, (m, capture) => {
|
||||
let text = '';
|
||||
|
||||
// Divide the import into multiple files.
|
||||
const captures = m.match(/['"]([^'"]*)['"]/g);
|
||||
|
||||
for (let x in captures) {
|
||||
text += this.getReplace(captures[x].replace(/['"]+/g, ''), baseDir, paths, parsedFiles) + '\n';
|
||||
}
|
||||
|
||||
return text;
|
||||
});
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CombineScssTask;
|
|
@ -1,79 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const fs = require('fs');
|
||||
const gulp = require('gulp');
|
||||
const flatten = require('gulp-flatten');
|
||||
const htmlmin = require('gulp-htmlmin');
|
||||
const pathLib = require('path');
|
||||
|
||||
const TEMPLATES_SRC = [
|
||||
'./src/components/**/*.html',
|
||||
'./src/core/**/components/**/*.html',
|
||||
'./src/core/**/component/**/*.html',
|
||||
// Copy all addon components because any component can be injected using extraImports.
|
||||
'./src/addon/**/components/**/*.html',
|
||||
'./src/addon/**/component/**/*.html'
|
||||
];
|
||||
const TEMPLATES_DEST = './www/templates';
|
||||
|
||||
/**
|
||||
* Task to copy component templates to www to make compile-html work in AOT.
|
||||
*/
|
||||
class CopyComponentTemplatesTask {
|
||||
|
||||
/**
|
||||
* Delete a folder and all its contents.
|
||||
*
|
||||
* @param path [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
deleteFolderRecursive(path) {
|
||||
if (fs.existsSync(path)) {
|
||||
fs.readdirSync(path).forEach((file) => {
|
||||
var curPath = pathLib.join(path, file);
|
||||
|
||||
if (fs.lstatSync(curPath).isDirectory()) {
|
||||
this.deleteFolderRecursive(curPath);
|
||||
} else {
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
|
||||
fs.rmdirSync(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task.
|
||||
*
|
||||
* @param done Callback to call once done.
|
||||
*/
|
||||
run(done) {
|
||||
this.deleteFolderRecursive(TEMPLATES_DEST);
|
||||
|
||||
gulp.src(TEMPLATES_SRC, { allowEmpty: true })
|
||||
.pipe(flatten())
|
||||
// Check options here: https://github.com/kangax/html-minifier
|
||||
.pipe(htmlmin({
|
||||
collapseWhitespace: true,
|
||||
removeComments: true,
|
||||
caseSensitive: true
|
||||
}))
|
||||
.pipe(gulp.dest(TEMPLATES_DEST))
|
||||
.on('end', done);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CopyComponentTemplatesTask;
|
57
gulpfile.js
57
gulpfile.js
|
@ -12,57 +12,60 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
const BuildConfigTask = require('./gulp/task-build-config');
|
||||
const BuildLangTask = require('./gulp/task-build-lang');
|
||||
const CombineScssTask = require('./gulp/task-combine-scss');
|
||||
const CopyComponentTemplatesTask = require('./gulp/task-copy-component-templates');
|
||||
const BuildBehatPluginTask = require('./gulp/task-build-behat-plugin');
|
||||
const BuildEnvTask = require('./gulp/task-build-env');
|
||||
const PushTask = require('./gulp/task-push');
|
||||
const Utils = require('./gulp/utils');
|
||||
const gulp = require('gulp');
|
||||
const pathLib = require('path');
|
||||
|
||||
const paths = {
|
||||
lang: [
|
||||
'./src/lang/',
|
||||
'./src/core/**/lang/',
|
||||
'./src/addon/**/lang/',
|
||||
'./src/assets/countries/',
|
||||
'./src/assets/mimetypes/'
|
||||
'./src/addons/**/',
|
||||
'./src/assets/countries.json',
|
||||
'./src/assets/mimetypes.json',
|
||||
'./src/core/features/**/',
|
||||
'./src/core/',
|
||||
],
|
||||
config: './src/config.json',
|
||||
};
|
||||
|
||||
const args = Utils.getCommandLineArguments();
|
||||
|
||||
// Build the language files into a single file per language.
|
||||
gulp.task('lang', (done) => {
|
||||
new BuildLangTask().run('en', paths.lang, done);
|
||||
new BuildLangTask().run(paths.lang, done);
|
||||
});
|
||||
|
||||
// Convert config.json into a TypeScript class.
|
||||
gulp.task('config', (done) => {
|
||||
new BuildConfigTask().run(paths.config, done);
|
||||
// Build an env file depending on the current environment.
|
||||
gulp.task('env', (done) => {
|
||||
new BuildEnvTask().run(done);
|
||||
});
|
||||
|
||||
// Copy component templates to www to make compile-html work in AOT.
|
||||
gulp.task('copy-component-templates', (done) => {
|
||||
new CopyComponentTemplatesTask().run(done);
|
||||
});
|
||||
|
||||
// Combine SCSS files.
|
||||
gulp.task('combine-scss', (done) => {
|
||||
new CombineScssTask().run(done);
|
||||
});
|
||||
// Build a Moodle plugin to run Behat tests.
|
||||
if (BuildBehatPluginTask.isBehatConfigured()) {
|
||||
gulp.task('behat', (done) => {
|
||||
new BuildBehatPluginTask().run(done);
|
||||
});
|
||||
}
|
||||
|
||||
gulp.task('push', (done) => {
|
||||
new PushTask().run(args, done);
|
||||
});
|
||||
|
||||
gulp.task('default', gulp.parallel('lang', 'config'));
|
||||
gulp.task(
|
||||
'default',
|
||||
gulp.parallel([
|
||||
'lang',
|
||||
'env',
|
||||
...(BuildBehatPluginTask.isBehatConfigured() ? ['behat'] : [])
|
||||
]),
|
||||
);
|
||||
|
||||
gulp.task('watch', () => {
|
||||
const langsPaths = paths.lang.map(path => path + 'en.json');
|
||||
gulp.watch(paths.lang, { interval: 500 }, gulp.parallel('lang'));
|
||||
gulp.watch(['./moodle.config.json', './moodle.config.*.json'], { interval: 500 }, gulp.parallel('env'));
|
||||
|
||||
gulp.watch(langsPaths, { interval: 500 }, gulp.parallel('lang'));
|
||||
gulp.watch(paths.config, { interval: 500 }, gulp.parallel('config'));
|
||||
if (BuildBehatPluginTask.isBehatConfigured()) {
|
||||
gulp.watch(['./tests/behat'], { interval: 500 }, gulp.parallel('behat'));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
# Override DockerHub build hook in order to create images of different flavors (production & testing).
|
||||
# See: https://docs.docker.com/docker-hub/builds/advanced/
|
||||
|
||||
if [[ "$IMAGE_NAME" == *-test ]]
|
||||
then
|
||||
docker build --build-arg build_command="npm run build:test" -f $DOCKERFILE_PATH -t $IMAGE_NAME .
|
||||
elif [[ "$IMAGE_NAME" == *-dev ]]
|
||||
then
|
||||
docker build --build-arg build_command="npm run build" -f $DOCKERFILE_PATH -t $IMAGE_NAME .
|
||||
else
|
||||
docker build -f $DOCKERFILE_PATH -t $IMAGE_NAME .
|
||||
fi
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "integration" != "${SOURCE_BRANCH}" ]
|
||||
then
|
||||
# A space-separated list of additional tags to place on this image.
|
||||
additionalTags=(latest)
|
||||
|
||||
# Tag and push image for each additional tag
|
||||
for tag in ${additionalTags[@]}; do
|
||||
echo "Tagging {$IMAGE_NAME} as ${DOCKER_REPO}:${tag}"
|
||||
docker tag $IMAGE_NAME ${DOCKER_REPO}:${tag}
|
||||
|
||||
echo "Pushing ${DOCKER_REPO}:${tag}"
|
||||
docker push ${DOCKER_REPO}:${tag}
|
||||
done
|
||||
fi
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"rulesDirectory": ["@ionic/v4-migration-tslint/rules"],
|
||||
"rules": {
|
||||
"ion-action-sheet-method-create-parameters-renamed": true,
|
||||
"ion-alert-method-create-parameters-renamed": true,
|
||||
"ion-back-button-not-added-by-default": { "options": [true], "severity": "warning" },
|
||||
"ion-button-attributes-renamed": true,
|
||||
"ion-button-is-now-an-element": true,
|
||||
"ion-buttons-attributes-renamed": true,
|
||||
"ion-col-attributes-renamed": true,
|
||||
"ion-datetime-capitalization-changed": true,
|
||||
"ion-fab-attributes-renamed": true,
|
||||
"ion-fab-button-is-now-an-element": true,
|
||||
"ion-fab-fixed-content": true,
|
||||
"ion-icon-attribute-is-active-removed": true,
|
||||
"ion-item-attributes-renamed": true,
|
||||
"ion-item-divider-ion-label-required": true,
|
||||
"ion-item-ion-label-required": true,
|
||||
"ion-item-is-now-an-element": true,
|
||||
"ion-item-option-is-now-an-element": true,
|
||||
"ion-item-option-method-get-sliding-percent-renamed": true,
|
||||
"ion-item-options-attribute-values-renamed": true,
|
||||
"ion-label-attributes-renamed": true,
|
||||
"ion-list-header-ion-label-required": true,
|
||||
"ion-loading-method-create-parameters-renamed": true,
|
||||
"ion-menu-events-renamed": true,
|
||||
"ion-menu-toggle-is-now-an-element": true,
|
||||
"ion-navbar-is-now-ion-toolbar": true,
|
||||
"ion-option-is-now-ion-select-option": true,
|
||||
"ion-overlay-method-create-should-use-await": true,
|
||||
"ion-overlay-method-present-should-use-await": { "options": [true], "severity": "warning" },
|
||||
"ion-radio-attributes-renamed": true,
|
||||
"ion-radio-group-is-now-an-element": true,
|
||||
"ion-radio-slot-required": true,
|
||||
"ion-range-attributes-renamed": true,
|
||||
"ion-segment-button-ion-label-required": true,
|
||||
"ion-spinner-attribute-values-renamed": true,
|
||||
"ion-tabs-refactored": { "options": [true], "severity": "warning" },
|
||||
"ion-text-is-now-an-element": true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
{
|
||||
"name": "moodlemobile",
|
||||
"integrations": {
|
||||
"cordova": {},
|
||||
"gulp": {}
|
||||
"cordova": {}
|
||||
},
|
||||
"type": "ionic-angular",
|
||||
"watchPatterns": [],
|
||||
"id": "com.moodle.moodlemobile"
|
||||
"type": "angular",
|
||||
"hooks": {
|
||||
"build:before": "./scripts/copy-assets.js",
|
||||
"serve:before": "./scripts/copy-assets.js"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
const { pathsToModuleNameMapper } = require('ts-jest/utils');
|
||||
const { compilerOptions } = require('./tsconfig');
|
||||
|
||||
module.exports = {
|
||||
preset: 'jest-preset-angular',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/testing/setup.ts'],
|
||||
testMatch: ['**/?(*.)test.ts'],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{ts,html}',
|
||||
'!src/testing/**/*',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.(ts|html)$': 'ts-jest',
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!@ionic-native|@ionic)'],
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/src/' }),
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsConfig: './tsconfig.test.json',
|
||||
},
|
||||
},
|
||||
};
|
3018
licenses.json
3018
licenses.json
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Application config.
|
||||
*
|
||||
* You can create your own environment files such as "moodle.config.prod.json" and "moodle.config.dev.json"
|
||||
* to override some values. The values will be merged, so you don't need to duplicate everything in this file.
|
||||
*/
|
||||
{
|
||||
// You can find all the properties you can configure in src/types/config.d.ts
|
||||
"default_lang": "es"
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
"app_id": "com.moodle.moodlemobile",
|
||||
"appname": "Moodle Mobile",
|
||||
"versioncode": 3950,
|
||||
"versionname": "3.9.5",
|
||||
"cache_update_frequency_usually": 420000,
|
||||
"cache_update_frequency_often": 1200000,
|
||||
"cache_update_frequency_sometimes": 3600000,
|
||||
"cache_update_frequency_rarely": 43200000,
|
||||
"default_lang": "en",
|
||||
"languages": {
|
||||
"af": "Afrikaans",
|
||||
"ar": "عربي",
|
||||
"bg": "Български",
|
||||
"ca": "Català",
|
||||
"cs": "Čeština",
|
||||
"da": "Dansk",
|
||||
"de": "Deutsch",
|
||||
"de-du": "Deutsch - Du",
|
||||
"el": "Ελληνικά",
|
||||
"en": "English",
|
||||
"en-us": "English - United States",
|
||||
"es": "Español",
|
||||
"es-mx": "Español - México",
|
||||
"eu": "Euskara",
|
||||
"fa": "فارسی",
|
||||
"fi": "Suomi",
|
||||
"fr": "Français",
|
||||
"gl": "Galego",
|
||||
"he": "עברית",
|
||||
"hi": "हिंदी",
|
||||
"hr": "Hrvatski",
|
||||
"hu": "magyar",
|
||||
"hy": "Հայերեն",
|
||||
"id": "Indonesian",
|
||||
"it": "Italiano",
|
||||
"ja": "日本語",
|
||||
"km": "ខ្មែរ",
|
||||
"kn": "ಕನ್ನಡ",
|
||||
"ko": "한국어",
|
||||
"lt": "Lietuvių",
|
||||
"lv": "Latviešu",
|
||||
"mn": "Монгол",
|
||||
"mr": "मराठी",
|
||||
"nl": "Nederlands",
|
||||
"no": "Norsk - bokmål",
|
||||
"pl": "Polski",
|
||||
"pt": "Português - Portugal",
|
||||
"pt-br": "Português - Brasil",
|
||||
"ro": "Română",
|
||||
"ru": "Русский",
|
||||
"sl": "Slovenščina",
|
||||
"sr-cr": "Српски",
|
||||
"sr-lt": "Srpski",
|
||||
"sv": "Svenska",
|
||||
"tg": "Тоҷикӣ",
|
||||
"tr": "Türkçe",
|
||||
"uk": "Українська",
|
||||
"uz": "O'zbekcha",
|
||||
"vi": "Vietnamese",
|
||||
"zh-cn": "简体中文",
|
||||
"zh-tw": "正體中文"
|
||||
},
|
||||
"wsservice": "moodle_mobile_app",
|
||||
"wsextservice": "local_mobile",
|
||||
"demo_sites": {
|
||||
"student": {
|
||||
"url": "https:\/\/school.moodledemo.net",
|
||||
"username": "student",
|
||||
"password": "moodle"
|
||||
},
|
||||
"teacher": {
|
||||
"url": "https:\/\/school.moodledemo.net",
|
||||
"username": "teacher",
|
||||
"password": "moodle"
|
||||
}
|
||||
},
|
||||
"zoomlevels": {
|
||||
"normal": 100,
|
||||
"low": 110,
|
||||
"high": 120
|
||||
},
|
||||
"customurlscheme": "moodlemobile",
|
||||
"siteurl": "",
|
||||
"sitename": "",
|
||||
"multisitesdisplay": "",
|
||||
"sitefindersettings": {},
|
||||
"onlyallowlistedsites": false,
|
||||
"skipssoconfirmation": false,
|
||||
"forcedefaultlanguage": false,
|
||||
"privacypolicy": "https:\/\/moodle.net\/moodle-app-privacy\/",
|
||||
"notificoncolor": "#f98012",
|
||||
"enableanalytics": false,
|
||||
"enableonboarding": true,
|
||||
"forceColorScheme": "",
|
||||
"forceLoginLogo": false,
|
||||
"ioswebviewscheme": "moodleappfs",
|
||||
"appstores": {
|
||||
"android": "com.moodle.moodlemobile",
|
||||
"ios": "id633359593"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
server {
|
||||
listen 0.0.0.0:80;
|
||||
root /usr/share/nginx/html;
|
||||
server_tokens off;
|
||||
access_log off;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
371
package.json
371
package.json
|
@ -1,17 +1,11 @@
|
|||
{
|
||||
"name": "moodlemobile",
|
||||
"version": "3.9.4",
|
||||
"version": "3.9.5",
|
||||
"description": "The official app for Moodle.",
|
||||
"author": {
|
||||
"name": "Moodle Pty Ltd.",
|
||||
"email": "mobile@moodle.com"
|
||||
},
|
||||
"config": {
|
||||
"ionic_webpack": "./config/webpack.config.js",
|
||||
"ionic_copy": "./config/copy.config.js",
|
||||
"ionic_uglifyjs": "./config/uglifyjs.config.js",
|
||||
"ionic_sass": "./config/sass.config.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/moodlehq/moodlemobile2.git"
|
||||
|
@ -24,88 +18,87 @@
|
|||
}
|
||||
],
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"dev": "ionic serve",
|
||||
"ng": "ng",
|
||||
"start": "ionic serve",
|
||||
"build": "ionic build",
|
||||
"build:prod": "NODE_ENV=production ionic build --prod",
|
||||
"build:test": "NODE_ENV=testing ionic build",
|
||||
"dev:android": "ionic cordova run android --livereload",
|
||||
"dev:ios": "ionic cordova run ios --livereload",
|
||||
"prod:android": "ionic cordova run android --aot",
|
||||
"prod:ios": "ionic cordova run ios --aot",
|
||||
"setup": "npm install && npx cordova prepare && npx gulp",
|
||||
"clean": "npx ionic-app-scripts clean",
|
||||
"build": "npx ionic-app-scripts build",
|
||||
"lint": "npx 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": "npx gulp",
|
||||
"ionic:serve": "npx gulp watch & npx ionic-app-scripts serve -b --devapp --address=0.0.0.0",
|
||||
"ionic:build:before": "npx gulp",
|
||||
"ionic:watch:before": "npx gulp",
|
||||
"ionic:build:after": "npx gulp copy-component-templates",
|
||||
"preionic:build": "npx gulp",
|
||||
"postionic:build": "npx gulp copy-component-templates",
|
||||
"desktop.pack": "npx electron-builder --dir",
|
||||
"desktop.dist": "npx electron-builder -p never",
|
||||
"windows.store": "npx electron-windows-store --input-directory .\\desktop\\dist\\win-unpacked --output-directory .\\desktop\\store -a .\\resources\\desktop -m .\\desktop\\assets\\windows\\AppXManifest.xml --package-version 0.0.0.0 --package-name MoodleDesktop"
|
||||
"prod:android": "NODE_ENV=production ionic cordova run android --aot",
|
||||
"prod:ios": "NODE_ENV=production ionic cordova run ios --aot",
|
||||
"test": "NODE_ENV=testing gulp && jest --verbose",
|
||||
"test:ci": "NODE_ENV=testing gulp && jest -ci --runInBand --verbose",
|
||||
"test:watch": "NODE_ENV=testing gulp watch & jest --watch",
|
||||
"test:coverage": "NODE_ENV=testing gulp && jest --coverage",
|
||||
"lint": "NODE_OPTIONS=--max-old-space-size=4096 ng lint",
|
||||
"ionic:serve:before": "gulp",
|
||||
"ionic:serve": "gulp watch & NODE_OPTIONS=--max-old-space-size=4096 ng serve",
|
||||
"ionic:build:before": "gulp"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "5.2.11",
|
||||
"@angular/common": "5.2.11",
|
||||
"@angular/compiler": "5.2.11",
|
||||
"@angular/compiler-cli": "5.2.11",
|
||||
"@angular/core": "5.2.11",
|
||||
"@angular/forms": "5.2.11",
|
||||
"@angular/platform-browser": "5.2.11",
|
||||
"@angular/platform-browser-dynamic": "5.2.11",
|
||||
"@ionic-native/badge": "4.20.0",
|
||||
"@ionic-native/camera": "4.20.0",
|
||||
"@ionic-native/chooser": "4.20.0",
|
||||
"@ionic-native/clipboard": "4.20.0",
|
||||
"@ionic-native/core": "4.20.0",
|
||||
"@ionic-native/device": "4.20.0",
|
||||
"@ionic-native/diagnostic": "4.2.0",
|
||||
"@ionic-native/file": "4.20.0",
|
||||
"@ionic-native/file-opener": "4.20.0",
|
||||
"@ionic-native/file-transfer": "4.20.0",
|
||||
"@ionic-native/geolocation": "4.20.0",
|
||||
"@ionic-native/globalization": "4.20.0",
|
||||
"@ionic-native/http": "4.20.0",
|
||||
"@ionic-native/in-app-browser": "4.20.0",
|
||||
"@ionic-native/keyboard": "4.20.0",
|
||||
"@ionic-native/local-notifications": "4.20.0",
|
||||
"@ionic-native/media": "4.20.0",
|
||||
"@ionic-native/media-capture": "4.20.0",
|
||||
"@ionic-native/network": "4.20.0",
|
||||
"@ionic-native/push": "4.20.0",
|
||||
"@ionic-native/qr-scanner": "4.20.0",
|
||||
"@ionic-native/screen-orientation": "4.20.0",
|
||||
"@ionic-native/splash-screen": "4.20.0",
|
||||
"@ionic-native/sqlite": "4.20.0",
|
||||
"@ionic-native/status-bar": "4.20.0",
|
||||
"@ionic-native/web-intent": "4.20.0",
|
||||
"@ionic-native/zip": "4.20.0",
|
||||
"@ngx-translate/core": "8.0.0",
|
||||
"@ngx-translate/http-loader": "2.0.1",
|
||||
"ajv": "6.11.0",
|
||||
"chart.js": "2.9.3",
|
||||
"@angular/animations": "10.0.14",
|
||||
"@angular/common": "10.0.14",
|
||||
"@angular/core": "10.0.14",
|
||||
"@angular/forms": "10.0.14",
|
||||
"@angular/platform-browser": "10.0.14",
|
||||
"@angular/platform-browser-dynamic": "10.0.14",
|
||||
"@angular/router": "10.0.14",
|
||||
"@ionic-native/badge": "5.33.0",
|
||||
"@ionic-native/camera": "5.33.0",
|
||||
"@ionic-native/chooser": "5.33.0",
|
||||
"@ionic-native/clipboard": "5.33.0",
|
||||
"@ionic-native/core": "5.33.0",
|
||||
"@ionic-native/device": "5.33.0",
|
||||
"@ionic-native/diagnostic": "5.33.0",
|
||||
"@ionic-native/file": "5.33.0",
|
||||
"@ionic-native/file-opener": "5.33.0",
|
||||
"@ionic-native/file-transfer": "5.33.0",
|
||||
"@ionic-native/geolocation": "5.33.0",
|
||||
"@ionic-native/http": "5.33.0",
|
||||
"@ionic-native/in-app-browser": "5.33.0",
|
||||
"@ionic-native/ionic-webview": "5.33.0",
|
||||
"@ionic-native/keyboard": "5.33.0",
|
||||
"@ionic-native/local-notifications": "5.33.0",
|
||||
"@ionic-native/media": "5.33.0",
|
||||
"@ionic-native/media-capture": "5.33.0",
|
||||
"@ionic-native/network": "5.33.0",
|
||||
"@ionic-native/push": "5.33.0",
|
||||
"@ionic-native/qr-scanner": "5.33.0",
|
||||
"@ionic-native/splash-screen": "5.33.0",
|
||||
"@ionic-native/sqlite": "5.33.0",
|
||||
"@ionic-native/status-bar": "5.33.0",
|
||||
"@ionic-native/web-intent": "5.33.0",
|
||||
"@ionic-native/zip": "5.33.0",
|
||||
"@ionic/angular": "5.6.6",
|
||||
"@ngx-translate/core": "13.0.0",
|
||||
"@ngx-translate/http-loader": "6.0.0",
|
||||
"@types/chart.js": "2.9.31",
|
||||
"@types/cordova": "0.0.34",
|
||||
"@types/cordova-plugin-file-transfer": "1.6.2",
|
||||
"@types/dom-mediacapture-record": "1.0.7",
|
||||
"chart.js": "2.9.4",
|
||||
"com-darryncampbell-cordova-plugin-intent": "1.3.0",
|
||||
"cordova": "10.0.0",
|
||||
"cordova-android": "8.1.0",
|
||||
"cordova-android": "9.1.0",
|
||||
"cordova-android-support-gradle-release": "3.0.1",
|
||||
"cordova-clipboard": "1.3.0",
|
||||
"cordova-ios": "5.1.1",
|
||||
"cordova-plugin-advanced-http": "2.4.1",
|
||||
"cordova-ios": "6.2.0",
|
||||
"cordova-plugin-add-swift-support": "2.0.2",
|
||||
"cordova-plugin-advanced-http": "3.1.0",
|
||||
"cordova-plugin-badge": "0.8.8",
|
||||
"cordova-plugin-camera": "4.1.0",
|
||||
"cordova-plugin-camera": "5.0.1",
|
||||
"cordova-plugin-chooser": "1.3.2",
|
||||
"cordova-plugin-customurlscheme": "5.0.1",
|
||||
"cordova-plugin-customurlscheme": "5.0.2",
|
||||
"cordova-plugin-device": "2.0.3",
|
||||
"cordova-plugin-file": "6.0.2",
|
||||
"cordova-plugin-file-opener2": "3.0.4",
|
||||
"cordova-plugin-file-transfer": "1.7.1",
|
||||
"cordova-plugin-geolocation": "git+https://github.com/apache/cordova-plugin-geolocation.git#89cf51d222e8f225bdfb661965b3007d669c40ff",
|
||||
"cordova-plugin-file-opener2": "3.0.5",
|
||||
"cordova-plugin-file-transfer": "git+https://github.com/moodlemobile/cordova-plugin-file-transfer.git",
|
||||
"cordova-plugin-geolocation": "4.1.0",
|
||||
"cordova-plugin-globalization": "1.11.0",
|
||||
"cordova-plugin-inappbrowser": "git+https://github.com/moodlemobile/cordova-plugin-inappbrowser.git#moodle",
|
||||
"cordova-plugin-ionic-keyboard": "2.1.3",
|
||||
"cordova-plugin-ionic-webview": "git+https://github.com/moodlemobile/cordova-plugin-ionic-webview.git#500-moodle",
|
||||
"cordova-plugin-inappbrowser": "git+https://github.com/moodlemobile/cordova-plugin-inappbrowser.git#moodle-ionic5",
|
||||
"cordova-plugin-ionic-keyboard": "2.2.0",
|
||||
"cordova-plugin-ionic-webview": "5.0.0",
|
||||
"cordova-plugin-local-notification": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle",
|
||||
"cordova-plugin-media": "5.0.3",
|
||||
"cordova-plugin-media-capture": "3.0.3",
|
||||
|
@ -118,61 +111,71 @@
|
|||
"cordova-plugin-wkuserscript": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git",
|
||||
"cordova-plugin-wkwebview-cookies": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git",
|
||||
"cordova-plugin-zip": "3.1.0",
|
||||
"cordova-sqlite-storage": "4.0.0",
|
||||
"cordova-sqlite-storage": "6.0.0",
|
||||
"cordova-support-google-services": "1.3.2",
|
||||
"cordova.plugins.diagnostic": "5.0.2",
|
||||
"core-js": "3.9.1",
|
||||
"es6-promise-plugin": "4.2.2",
|
||||
"font-awesome": "4.7.0",
|
||||
"inquirer": "^7.3.2",
|
||||
"ionic-angular": "3.9.9",
|
||||
"ionicons": "3.0.0",
|
||||
"jszip": "3.1.5",
|
||||
"jszip": "3.5.0",
|
||||
"mathjax": "2.7.7",
|
||||
"moment": "2.24.0",
|
||||
"moment": "2.29.0",
|
||||
"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-v3",
|
||||
"promise.prototype.finally": "3.1.0",
|
||||
"rxjs": "5.5.12",
|
||||
"sw-toolbox": "3.6.0",
|
||||
"rxjs": "6.5.5",
|
||||
"ts-md5": "1.2.7",
|
||||
"web-animations-js": "2.3.2",
|
||||
"zone.js": "0.8.29"
|
||||
"tslib": "2.0.1",
|
||||
"zone.js": "0.10.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/app-scripts": "3.2.3",
|
||||
"@ionic/cli": "^6.11.7",
|
||||
"@types/cordova": "^0.0.34",
|
||||
"@types/cordova-plugin-file-transfer": "^0.0.3",
|
||||
"@types/cordova-plugin-globalization": "^0.0.3",
|
||||
"@types/cordova-plugin-network-information": "^0.0.3",
|
||||
"@types/node": "^8.10.59",
|
||||
"@types/promise.prototype.finally": "^2.0.4",
|
||||
"acorn": "^5.7.4",
|
||||
"cordova.plugins.diagnostic": "^5.0.2",
|
||||
"electron-builder-lib": "^20.23.1",
|
||||
"electron-rebuild": "^1.10.0",
|
||||
"@angular-devkit/architect": "0.1101.2",
|
||||
"@angular-devkit/build-angular": "0.1000.8",
|
||||
"@angular-eslint/builder": "4.2.0",
|
||||
"@angular-eslint/eslint-plugin": "4.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "4.2.0",
|
||||
"@angular-eslint/schematics": "4.2.0",
|
||||
"@angular-eslint/template-parser": "4.2.0",
|
||||
"@angular/cli": "10.0.8",
|
||||
"@angular/compiler": "10.0.14",
|
||||
"@angular/compiler-cli": "10.0.14",
|
||||
"@angular/language-service": "10.0.14",
|
||||
"@ionic/angular-toolkit": "2.3.3",
|
||||
"@ionic/cli": "6.14.1",
|
||||
"@types/faker": "5.1.3",
|
||||
"@types/node": "12.12.64",
|
||||
"@types/resize-observer-browser": "0.1.5",
|
||||
"@types/webpack-env": "1.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||
"@typescript-eslint/parser": "4.22.0",
|
||||
"check-es-compat": "1.1.1",
|
||||
"cordova-plugin-prevent-override": "git+https://github.com/moodlemobile/cordova-plugin-prevent-override.git",
|
||||
"eslint": "7.25.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-header": "3.1.1",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-jsdoc": "32.3.3",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"eslint-plugin-promise": "5.1.0",
|
||||
"faker": "5.1.0",
|
||||
"fs-extra": "9.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-clip-empty-files": "^0.1.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-flatten": "^0.4.0",
|
||||
"gulp-htmlmin": "^5.0.1",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-slash": "^1.1.3",
|
||||
"lodash.template": "^4.5.0",
|
||||
"minimist": "^1.2.5",
|
||||
"native-run": "^1.0.0",
|
||||
"node-loader": "^0.6.0",
|
||||
"request": "^2.88.2",
|
||||
"through": "^2.3.8",
|
||||
"typescript": "~2.6.2",
|
||||
"vinyl": "^2.2.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
"gulp-clip-empty-files": "0.1.2",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-flatten": "0.4.0",
|
||||
"gulp-htmlmin": "5.0.1",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-slash": "1.1.3",
|
||||
"jest": "26.5.2",
|
||||
"jest-preset-angular": "8.3.1",
|
||||
"jsonc-parser": "2.3.1",
|
||||
"native-run": "^1.4.0",
|
||||
"ts-jest": "26.4.1",
|
||||
"ts-node": "8.3.0",
|
||||
"typescript": "3.9.9"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"keytar": "^6.0.1"
|
||||
},
|
||||
"browser": {
|
||||
"electron": false
|
||||
"engines": {
|
||||
"node": ">=12.x"
|
||||
},
|
||||
"cordova": {
|
||||
"platforms": [
|
||||
|
@ -180,118 +183,64 @@
|
|||
"ios"
|
||||
],
|
||||
"plugins": {
|
||||
"com-darryncampbell-cordova-plugin-intent": {},
|
||||
"cordova-android-support-gradle-release": {
|
||||
"ANDROID_SUPPORT_VERSION": "27.1.0"
|
||||
},
|
||||
"cordova-plugin-advanced-http": {},
|
||||
"cordova-clipboard": {},
|
||||
"cordova-plugin-badge": {},
|
||||
"cordova-plugin-camera": {},
|
||||
"cordova-plugin-camera": {
|
||||
"ANDROID_SUPPORT_V4_VERSION": "27.+"
|
||||
},
|
||||
"cordova-plugin-chooser": {},
|
||||
"cordova-plugin-customurlscheme": {
|
||||
"URL_SCHEME": "moodlemobile"
|
||||
"URL_SCHEME": "moodlemobile",
|
||||
"ANDROID_SCHEME": " ",
|
||||
"ANDROID_HOST": " ",
|
||||
"ANDROID_PATHPREFIX": "/"
|
||||
},
|
||||
"cordova-plugin-device": {},
|
||||
"cordova-plugin-file": {},
|
||||
"cordova-plugin-file-opener2": {},
|
||||
"cordova-plugin-file-transfer": {},
|
||||
"cordova-plugin-globalization": {},
|
||||
"cordova-plugin-file-opener2": {
|
||||
"ANDROID_SUPPORT_V4_VERSION": "27.+"
|
||||
},
|
||||
"cordova-plugin-geolocation": {
|
||||
"GPS_REQUIRED": "false"
|
||||
},
|
||||
"cordova-plugin-inappbrowser": {},
|
||||
"cordova-plugin-ionic-keyboard": {},
|
||||
"cordova-plugin-local-notification": {},
|
||||
"cordova-plugin-ionic-webview": {},
|
||||
"cordova-plugin-local-notification": {
|
||||
"ANDROID_SUPPORT_V4_VERSION": "26.+"
|
||||
},
|
||||
"cordova-plugin-media-capture": {},
|
||||
"cordova-plugin-media": {
|
||||
"KEEP_AVAUDIOSESSION_ALWAYS_ACTIVE": "NO"
|
||||
},
|
||||
"cordova-plugin-network-information": {},
|
||||
"cordova-plugin-qrscanner": {},
|
||||
"cordova-plugin-screen-orientation": {},
|
||||
"cordova-plugin-splashscreen": {},
|
||||
"cordova-plugin-statusbar": {},
|
||||
"cordova-plugin-whitelist": {},
|
||||
"cordova-plugin-wkuserscript": {},
|
||||
"cordova-plugin-wkwebview-cookies": {},
|
||||
"cordova-plugin-zip": {},
|
||||
"cordova-sqlite-storage": {},
|
||||
"nl.kingsquare.cordova.background-audio": {},
|
||||
"phonegap-plugin-push": {
|
||||
"ANDROID_SUPPORT_V13_VERSION": "27.+",
|
||||
"FCM_VERSION": "17.5.+"
|
||||
"FCM_VERSION": "17.0.+"
|
||||
},
|
||||
"cordova-plugin-geolocation": {
|
||||
"GEOLOCATION_USAGE_DESCRIPTION": "We need your location so you can attach it as part of your submissions.",
|
||||
"GPS_REQUIRED": "false"
|
||||
"com-darryncampbell-cordova-plugin-intent": {},
|
||||
"nl.kingsquare.cordova.background-audio": {},
|
||||
"cordova-android-support-gradle-release": {
|
||||
"ANDROID_SUPPORT_VERSION": "27.+"
|
||||
},
|
||||
"cordova-plugin-ionic-webview": {},
|
||||
"cordova-plugin-advanced-http": {
|
||||
"OKHTTP_VERSION": "3.10.0"
|
||||
"cordova.plugins.diagnostic": {
|
||||
"ANDROID_SUPPORT_VERSION": "28.+"
|
||||
},
|
||||
"cordova-plugin-wkwebview-cookies": {},
|
||||
"cordova-plugin-qrscanner": {},
|
||||
"cordova-plugin-chooser": {},
|
||||
"cordova-plugin-wkuserscript": {},
|
||||
"cordova-plugin-media": {
|
||||
"KEEP_AVAUDIOSESSION_ALWAYS_ACTIVE": "NO"
|
||||
},
|
||||
"cordova.plugins.diagnostic": {}
|
||||
"cordova-plugin-globalization": {},
|
||||
"cordova-plugin-file-transfer": {},
|
||||
"cordova-plugin-prevent-override": {}
|
||||
}
|
||||
},
|
||||
"main": "desktop/electron.js",
|
||||
"build": {
|
||||
"appId": "com.moodle.moodledesktop",
|
||||
"productName": "Moodle Desktop",
|
||||
"files": [
|
||||
"desktop/electron.js",
|
||||
"www/**/*",
|
||||
"!config",
|
||||
"!desktop/assets",
|
||||
"!desktop/dist",
|
||||
"!node_modules",
|
||||
"!**/e2e",
|
||||
"!hooks",
|
||||
"!platforms",
|
||||
"!plugins",
|
||||
"!resources",
|
||||
"!src",
|
||||
"!**/*.scss"
|
||||
],
|
||||
"directories": {
|
||||
"output": "desktop/dist"
|
||||
},
|
||||
"protocols": [
|
||||
{
|
||||
"name": "Moodle Mobile URL",
|
||||
"schemes": [
|
||||
"moodlemobile"
|
||||
],
|
||||
"role": "Viewer"
|
||||
}
|
||||
],
|
||||
"compression": "maximum",
|
||||
"electronVersion": "8.0.2",
|
||||
"mac": {
|
||||
"category": "public.app-category.education",
|
||||
"icon": "resources/desktop/icon.icns",
|
||||
"target": "mas",
|
||||
"bundleVersion": "3.9.4",
|
||||
"extendInfo": {
|
||||
"ElectronTeamID": "2NU57U5PAW",
|
||||
"NSLocationWhenInUseUsageDescription": "We need your location so you can attach it as part of your submissions.",
|
||||
"NSLocationAlwaysUsageDescription": "We need your location so you can attach it as part of your submissions.",
|
||||
"NSCameraUsageDescription": "We need camera access to take pictures so you can attach them as part of your submissions.",
|
||||
"NSMicrophoneUsageDescription": "We need microphone access to record sounds so you can attach them as part of your submissions.",
|
||||
"NSPhotoLibraryUsageDescription": "We need photo library access to get pictures from there so you can attach them as part of your submissions."
|
||||
}
|
||||
},
|
||||
"win": {
|
||||
"target": "appx",
|
||||
"icon": "resources/desktop/icon.ico"
|
||||
},
|
||||
"linux": {
|
||||
"category": "Education",
|
||||
"target": "AppImage"
|
||||
},
|
||||
"snap": {
|
||||
"confinement": "classic"
|
||||
},
|
||||
"nsis": {
|
||||
"deleteAppDataOnUninstall": true
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=11.x"
|
||||
"optionalDependencies": {
|
||||
"keytar": "7.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">localhost</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 932 B |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 103 KiB |
|
@ -1,32 +0,0 @@
|
|||
#!/bin/bash
|
||||
source "scripts/functions.sh"
|
||||
|
||||
if [ ! -z $GIT_ORG_PRIVATE ] && [ ! -z $GIT_TOKEN ] ; then
|
||||
print_title "Run scripts"
|
||||
git clone --depth 1 https://$GIT_TOKEN@github.com/$GIT_ORG_PRIVATE/apps-scripts.git ../scripts
|
||||
cp ../scripts/*.sh scripts/
|
||||
|
||||
if [ $TRAVIS_BUILD_STAGE_NAME == 'prepare' ] && [ -f scripts/prepare.sh ] ; then
|
||||
print_title 'Prepare Build'
|
||||
./scripts/prepare.sh
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
elif [ $TRAVIS_BUILD_STAGE_NAME != 'prepare' ] && [ -f scripts/platform.sh ]; then
|
||||
print_title 'Platform Build'
|
||||
./scripts/platform.sh
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
print_title "AOT Compilation"
|
||||
# Dynamic template loading without errors.
|
||||
sed -ie $'s~throw new Error("No ResourceLoader.*~url = "templates/" + url;\\\nvar resolve;\\\nvar reject;\\\nvar promise = new Promise(function (res, rej) {\\\nresolve = res;\\\nreject = rej;\\\n});\\\nvar xhr = new XMLHttpRequest();\\\nxhr.open("GET", url, true);\\\nxhr.responseType = "text";\\\nxhr.onload = function () {\\\nvar response = xhr.response || xhr.responseText;\\\nvar status = xhr.status === 1223 ? 204 : xhr.status;\\\nif (status === 0) {\\\nstatus = response ? 200 : 0;\\\n}\\\nif (200 <= status \&\& status <= 300) {\\\nresolve(response);\\\n}\\\nelse {\\\nreject("Failed to load " + url);\\\n}\\\n};\\\nxhr.onerror = function () { reject("Failed to load " + url); };\\\nxhr.send();\\\nreturn promise;\\\n~g' node_modules/@angular/platform-browser-dynamic/esm5/platform-browser-dynamic.js
|
||||
# Do not run JS optimizations to avoid problems with site plugins.
|
||||
sed -ie "s/context\.isProd || hasArg('--optimizeJs')/false/g" node_modules/@ionic/app-scripts/dist/util/config.js
|
||||
npm run ionic:build -- --prod
|
||||
fi
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// (C) Copyright 2021 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
const { existsSync, readFileSync, writeFileSync } = require('fs');
|
||||
const { readdir } = require('fs').promises;
|
||||
const { mkdirSync, copySync } = require('fs-extra');
|
||||
const { resolve } = require('path');
|
||||
|
||||
async function main() {
|
||||
const pluginPath = process.argv[2] || guessPluginPath() || fail('Folder argument missing!');
|
||||
|
||||
if (!existsSync(pluginPath)) {
|
||||
mkdirSync(pluginPath);
|
||||
}
|
||||
|
||||
// Copy plugin template.
|
||||
const { version: appVersion } = require(projectPath('package.json'));
|
||||
const templatePath = projectPath('scripts/templates/behat-plugin');
|
||||
const replacements = {
|
||||
appVersion,
|
||||
pluginVersion: getMoodlePluginVersion(),
|
||||
};
|
||||
|
||||
copySync(templatePath, pluginPath);
|
||||
|
||||
for await (const templateFilePath of getDirectoryFiles(templatePath)) {
|
||||
const pluginFilePath = pluginPath + templateFilePath.substr(templatePath.length);
|
||||
const fileContents = readFileSync(pluginFilePath).toString();
|
||||
|
||||
writeFileSync(pluginFilePath, replaceArguments(fileContents, replacements));
|
||||
}
|
||||
|
||||
// Copy features.
|
||||
copySync(projectPath('tests/behat'), `${pluginPath}/tests/behat`);
|
||||
}
|
||||
|
||||
function fail(message) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function guessPluginPath() {
|
||||
if (process.env.MOODLE_APP_BEHAT_PLUGIN_PATH) {
|
||||
return process.env.MOODLE_APP_BEHAT_PLUGIN_PATH;
|
||||
}
|
||||
|
||||
if (process.env.MOODLE_DOCKER_WWWROOT) {
|
||||
return `${process.env.MOODLE_DOCKER_WWWROOT}/local/moodleappbehat`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function projectPath(path) {
|
||||
return resolve(__dirname, '../', path);
|
||||
}
|
||||
|
||||
async function* getDirectoryFiles(dir) {
|
||||
const files = await readdir(dir, { withFileTypes: true });
|
||||
|
||||
for (const file of files) {
|
||||
const path = resolve(dir, file.name);
|
||||
if (file.isDirectory()) {
|
||||
yield* getDirectoryFiles(path);
|
||||
} else {
|
||||
yield path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function replaceArguments(text, args) {
|
||||
for (const [arg, value] of Object.entries(args)) {
|
||||
const regexp = new RegExp(`\\{\\{\\s+${arg}\\s+\\}\\}`, 'gm');
|
||||
|
||||
text = text.replace(regexp, value);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function getMoodlePluginVersion() {
|
||||
const now = new Date();
|
||||
const padded = (number, length = 2) => number.toString().padStart(length, '0');
|
||||
const year = padded(now.getFullYear(), 4);
|
||||
const month = padded(now.getMonth() + 1);
|
||||
const day = padded(now.getDate());
|
||||
|
||||
return `${year}${month}${day}00`;
|
||||
}
|
||||
|
||||
main();
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
source "scripts/functions.sh"
|
||||
|
||||
if [ -z $GIT_TOKEN ]; then
|
||||
print_error "Env vars not correctly defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_title "Run scripts"
|
||||
# TODO Change branch name.
|
||||
git clone --depth 1 --single-branch --branch ionic5 https://$GIT_TOKEN@github.com/moodlemobile/apps-scripts.git ../scripts
|
||||
cp ../scripts/*.sh scripts/
|
||||
|
||||
if [ ! -f scripts/platform.sh ]; then
|
||||
print_error "Platform file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_title 'Platform Build'
|
||||
./scripts/platform.sh
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,39 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* Script to copy some files to the www folder.
|
||||
*/
|
||||
const fse = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
// Assets to copy.
|
||||
const ASSETS = {
|
||||
'/node_modules/mathjax/MathJax.js': '/lib/mathjax/MathJax.js',
|
||||
'/node_modules/mathjax/extensions': '/lib/mathjax/extensions',
|
||||
'/node_modules/mathjax/jax/element': '/lib/mathjax/jax/element',
|
||||
'/node_modules/mathjax/jax/input': '/lib/mathjax/jax/input',
|
||||
'/node_modules/mathjax/jax/output/SVG': '/lib/mathjax/jax/output/SVG',
|
||||
'/node_modules/mathjax/jax/output/PreviewHTML': '/lib/mathjax/jax/output/PreviewHTML',
|
||||
'/node_modules/mathjax/localization': '/lib/mathjax/localization',
|
||||
'/src/core/features/h5p/assets': '/lib/h5p',
|
||||
};
|
||||
|
||||
module.exports = function(ctx) {
|
||||
const assetsPath = ctx.project.srcDir + '/assets';
|
||||
|
||||
for (const src in ASSETS) {
|
||||
fse.copySync(ctx.project.dir + src, assetsPath + ASSETS[src], { overwrite: true });
|
||||
}
|
||||
};
|
|
@ -1,5 +1,12 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script to create langindex from available language packs.
|
||||
# ./create_langindex.sh [findbetter]
|
||||
# If findbetter is set it will try to find a better solution for every key.
|
||||
#
|
||||
|
||||
source "functions.sh"
|
||||
source "lang_functions.sh"
|
||||
|
||||
#Saves or updates a key on langindex_old.json
|
||||
function save_key {
|
||||
|
@ -48,7 +55,8 @@ function exists_in_mobile {
|
|||
}
|
||||
|
||||
function do_match {
|
||||
match=$1
|
||||
match=${1/\{\{/\{}
|
||||
match=${match/\}\}/\}}
|
||||
filematch=""
|
||||
|
||||
coincidence=`grep "$match" $LANGPACKSFOLDER/en/*.php | wc -l`
|
||||
|
@ -56,7 +64,7 @@ function do_match {
|
|||
filematch=`grep "$match" $LANGPACKSFOLDER/en/*.php | cut -d'/' -f5 | cut -d'.' -f1`
|
||||
exists_in_file $filematch $plainid
|
||||
elif [ $coincidence -gt 0 ] && [ "$#" -gt 1 ]; then
|
||||
print_message $2
|
||||
print_message "$2"
|
||||
tput setaf 6
|
||||
grep "$match" $LANGPACKSFOLDER/en/*.php
|
||||
fi
|
||||
|
@ -67,18 +75,21 @@ function find_matches {
|
|||
do_match "string\[\'$plainid\'\] = \'$value\'" "Found EXACT match for $key in the following paths"
|
||||
if [ $coincidence -gt 0 ]; then
|
||||
case=1
|
||||
save_key $key "TBD"
|
||||
return
|
||||
fi
|
||||
|
||||
do_match " = \'$value\'" "Found some string VALUES for $key in the following paths"
|
||||
if [ $coincidence -gt 0 ]; then
|
||||
case=2
|
||||
save_key $key "TBD"
|
||||
return
|
||||
fi
|
||||
|
||||
do_match "string\[\'$plainid\'\]" "Found some string KEYS for $key in the following paths, value $value"
|
||||
if [ $coincidence -gt 0 ]; then
|
||||
case=3
|
||||
save_key $key "TBD"
|
||||
return
|
||||
fi
|
||||
|
||||
|
@ -297,17 +308,13 @@ function array_contains {
|
|||
done
|
||||
}
|
||||
|
||||
|
||||
print_title 'Generating language from code...'
|
||||
gulp lang
|
||||
npx gulp lang
|
||||
|
||||
print_title 'Getting languages'
|
||||
git clone https://git.in.moodle.com/moodle/moodle-langpacks.git $LANGPACKSFOLDER
|
||||
pushd $LANGPACKSFOLDER
|
||||
BRANCHES=($(git branch -r --format="%(refname:lstrip=3)" --sort="refname" | grep MOODLE_))
|
||||
BRANCH=${BRANCHES[${#BRANCHES[@]}-1]}
|
||||
git checkout $BRANCH
|
||||
git pull
|
||||
popd
|
||||
|
||||
get_language en
|
||||
|
||||
print_title 'Processing file'
|
||||
#Create langindex.json if not exists.
|
||||
|
@ -324,4 +331,4 @@ jq -S --indent 2 -s '.[0]' langindex.json > langindex_new.json
|
|||
mv langindex_new.json langindex.json
|
||||
rm langindex_old.json
|
||||
|
||||
print_ok 'All done!'
|
||||
print_ok 'All done!'
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
LANGPACKSFOLDER='../../moodle-langpacks'
|
||||
|
||||
function check_success_exit {
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "$1"
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script for getting the PHP structure of a WS returns or params.
|
||||
*
|
||||
* The first parameter (required) is the path to the Moodle installation to use.
|
||||
* The second parameter (required) is the name to the WS to convert.
|
||||
* The third parameter (optional) is a number: 1 to convert the params structure,
|
||||
* 0 to convert the returns structure. Defaults to 0.
|
||||
*/
|
||||
|
||||
if (!isset($argv[1])) {
|
||||
echo "ERROR: Please pass the Moodle path as the first parameter.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
$moodlepath = $argv[1];
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require($moodlepath . '/config.php');
|
||||
require($CFG->dirroot . '/webservice/lib.php');
|
||||
require_once('ws_to_ts_functions.php');
|
||||
|
||||
$structures = get_all_ws_structures();
|
||||
|
||||
foreach ($structures as $wsname => $structure) {
|
||||
|
||||
remove_default_closures($structure->parameters_desc);
|
||||
print_ws_structure($wsname, $structure->parameters_desc, true);
|
||||
|
||||
remove_default_closures($structure->returns_desc);
|
||||
print_ws_structure($wsname, $structure->returns_desc, false);
|
||||
}
|
|
@ -28,16 +28,17 @@ if (!isset($argv[1])) {
|
|||
die();
|
||||
}
|
||||
|
||||
|
||||
if (!isset($argv[2])) {
|
||||
echo "ERROR: Please pass the WS name as the second parameter.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
define('CACHE_DISABLE_ALL', true);
|
||||
define('SERIALIZED', true);
|
||||
require_once('ws_to_ts_functions.php');
|
||||
|
||||
$versions = array('master', '38', '37', '36', '35', '34', '33', '32', '31');
|
||||
$versions = array('master', '310', '39', '38', '37', '36', '35', '34', '33', '32', '31');
|
||||
|
||||
$moodlespath = $argv[1];
|
||||
$wsname = $argv[2];
|
||||
|
@ -58,7 +59,12 @@ $previousversion = null;
|
|||
$libsloaded = false;
|
||||
|
||||
foreach ($versions as $version) {
|
||||
$moodlepath = concatenate_paths($moodlespath, 'stable_' . $version, $pathseparator);
|
||||
$moodlepath = concatenate_paths($moodlespath, 'stable_' . $version . '/moodle', $pathseparator);
|
||||
|
||||
if (!file_exists($moodlepath)) {
|
||||
echo "Folder does not exist for version $version, skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$libsloaded) {
|
||||
$libsloaded = true;
|
||||
|
|
|
@ -28,12 +28,15 @@ if (!isset($argv[1])) {
|
|||
die();
|
||||
}
|
||||
|
||||
|
||||
if (!isset($argv[2])) {
|
||||
echo "ERROR: Please pass the WS name as the second parameter.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
if (!defined('SERIALIZED')) {
|
||||
define('SERIALIZED', false);
|
||||
}
|
||||
|
||||
$moodlepath = $argv[1];
|
||||
$wsname = $argv[2];
|
||||
$useparams = !!(isset($argv[3]) && $argv[3]);
|
||||
|
@ -52,4 +55,9 @@ if ($structure === false) {
|
|||
}
|
||||
|
||||
remove_default_closures($structure);
|
||||
echo serialize($structure);
|
||||
|
||||
if (SERIALIZED) {
|
||||
echo serialize($structure);
|
||||
} else {
|
||||
print_ws_structure($wsname, $structure, $useparams);
|
||||
}
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script for converting a PHP WS structure to a TS type.
|
||||
*
|
||||
* The first parameter (required) is the path to the Moodle installation to use.
|
||||
* The second parameter (required) is the name to the WS to convert.
|
||||
* The third parameter (optional) is the name to put to the TS type. Defaults to "TypeName".
|
||||
* The fourth parameter (optional) is a number: 1 to convert the params structure,
|
||||
* 0 to convert the returns structure. Defaults to 0.
|
||||
*/
|
||||
|
||||
if (!isset($argv[1])) {
|
||||
echo "ERROR: Please pass the Moodle path as the first parameter.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
|
||||
if (!isset($argv[2])) {
|
||||
echo "ERROR: Please pass the WS name as the second parameter.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
$moodlepath = $argv[1];
|
||||
$wsname = $argv[2];
|
||||
$typename = isset($argv[3]) ? $argv[3] : 'TypeName';
|
||||
$useparams = !!(isset($argv[4]) && $argv[4]);
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require($moodlepath . '/config.php');
|
||||
require($CFG->dirroot . '/webservice/lib.php');
|
||||
require_once('ws_to_ts_functions.php');
|
||||
|
||||
$structure = get_ws_structure($wsname, $useparams);
|
||||
|
||||
if ($structure === false) {
|
||||
echo "ERROR: The WS wasn't found in this Moodle installation.\n";
|
||||
die();
|
||||
}
|
||||
|
||||
if ($useparams) {
|
||||
$description = "Params of WS $wsname.";
|
||||
} else {
|
||||
$description = "Result of WS $wsname.";
|
||||
}
|
||||
|
||||
echo get_ts_doc(null, $description, '') . "export type $typename = " . convert_to_ts(null, $structure, $useparams) . ";\n";
|
|
@ -358,9 +358,7 @@ function detect_lang($lang, $keys) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function save_key($key, $value, $path) {
|
||||
$filePath = $path . '/en.json';
|
||||
|
||||
function save_key($key, $value, $filePath) {
|
||||
$file = file_get_contents($filePath);
|
||||
$file = (array) json_decode($file);
|
||||
$value = html_entity_decode($value);
|
||||
|
@ -387,27 +385,31 @@ function override_component_lang_files($keys, $translations) {
|
|||
}
|
||||
switch($type) {
|
||||
case 'core':
|
||||
case 'addon':
|
||||
switch($component) {
|
||||
case 'moodle':
|
||||
$path .= 'lang';
|
||||
$path .= 'core/lang.json';
|
||||
break;
|
||||
default:
|
||||
$path .= $type.'/'.str_replace('_', '/', $component).'/lang';
|
||||
$path .= 'core/features/'.str_replace('_', '/', $component).'/lang.json';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'addon':
|
||||
$path .= 'addons/'.str_replace('_', '/', $component).'/lang.json';
|
||||
break;
|
||||
case 'assets':
|
||||
$path .= $type.'/'.$component;
|
||||
$path .= $type.'/'.$component.'.json';
|
||||
break;
|
||||
default:
|
||||
$path .= $type.'/lang';
|
||||
$path .= $type.'/lang.json';
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (is_file($path.'/en.json')) {
|
||||
if (is_file($path)) {
|
||||
save_key($plainid, $value, $path);
|
||||
} else {
|
||||
echo "Cannot override: $path not found.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Functions to fetch languages.
|
||||
#
|
||||
|
||||
LANGPACKSFOLDER='../../moodle-langpacks'
|
||||
BUCKET='moodle-lang-prod'
|
||||
MOODLEORG_URL='https://download.moodle.org/download.php/direct/langpack'
|
||||
DEFAULT_LASTVERSION='4.0'
|
||||
|
||||
# Checks if AWS is available and configured.
|
||||
function check_aws {
|
||||
AWS_SERVICE=1
|
||||
|
||||
aws --version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
AWS_SERVICE=0
|
||||
echo 'AWS not installed. Check https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html for more info.'
|
||||
return
|
||||
fi
|
||||
|
||||
# In order to login to AWS, use credentials file or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY vars.
|
||||
if [ ! -f ~/.aws/credentials ] && ([ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]); then
|
||||
AWS_SERVICE=0
|
||||
lastversion=$DEFAULT_LASTVERSION
|
||||
echo 'AWS Cannot authenticate. Use aws configure or set the proper env vars.'
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
# Get last version of Moodle to fetch latest languages.
|
||||
function get_last_version {
|
||||
if [ ! -z "${lastversion}" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
check_aws
|
||||
if [ $AWS_SERVICE -eq 0 ]; then
|
||||
lastversion=$DEFAULT_LASTVERSION
|
||||
echo "Using default version $lastversion"
|
||||
return
|
||||
fi
|
||||
|
||||
list=`aws s3 ls s3://$BUCKET/`
|
||||
if [ $? -ne 0 ]; then
|
||||
AWS_SERVICE=0
|
||||
lastversion=$DEFAULT_LASTVERSION
|
||||
echo "AWS Cannot authenticate. Using default version $lastversion"
|
||||
return
|
||||
fi
|
||||
|
||||
lastversion=''
|
||||
for folder in $list; do
|
||||
if [ $folder != 'PRE' ]; then
|
||||
lastversion=${folder/\//}
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -z "${lastversion}" ]; then
|
||||
echo "Last version $lastversion detected"
|
||||
return
|
||||
fi
|
||||
|
||||
lastversion=$DEFAULT_LASTVERSION
|
||||
}
|
||||
|
||||
# Create langfolder
|
||||
function create_langfolder {
|
||||
if [ ! -d $LANGPACKSFOLDER ]; then
|
||||
mkdir $LANGPACKSFOLDER
|
||||
fi
|
||||
}
|
||||
|
||||
# Get all language list from AWS.
|
||||
function get_all_languages_aws {
|
||||
langsfiles=`aws s3 ls s3://$BUCKET/$lastversion/`
|
||||
langs=""
|
||||
for file in $langsfiles; do
|
||||
if [[ "$file" == *.zip ]]; then
|
||||
file=${file/\.zip/}
|
||||
langs+="$file "
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Get language list from the installed ones (will not discover new translations).
|
||||
function get_installed_languages {
|
||||
langs=`jq -r '.languages | keys[]' ../moodle.config.json`
|
||||
}
|
||||
|
||||
# Entry function to get a language file.
|
||||
function get_language {
|
||||
lang=$1
|
||||
lang=${lang/-/_}
|
||||
|
||||
get_last_version
|
||||
|
||||
create_langfolder
|
||||
|
||||
echo "Getting $lang language"
|
||||
|
||||
pushd $LANGPACKSFOLDER > /dev/null
|
||||
|
||||
curl -s $MOODLEORG_URL/$lastversion/$lang.zip --output $lang.zip > /dev/null
|
||||
rm -R $lang > /dev/null 2>&1> /dev/null
|
||||
unzip -o -u $lang.zip > /dev/null
|
||||
|
||||
# This is the AWS version to get the language but right now it's slower.
|
||||
# aws s3 cp s3://$BUCKET/$lastversion/$lang.zip . > /dev/null
|
||||
|
||||
rm $lang.zip
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
# Entry function to get all language files.
|
||||
function get_languages {
|
||||
get_last_version
|
||||
|
||||
if [ -d $LANGPACKSFOLDER ]; then
|
||||
lastupdate=`date -r $LANGPACKSFOLDER +%s`
|
||||
currenttime=`date +%s`
|
||||
ellapsedtime=$((currenttime - lastupdate))
|
||||
if [ $ellapsedtime -lt 3600 ]; then
|
||||
echo 'Recently updated, skip update languages'
|
||||
return
|
||||
fi
|
||||
else
|
||||
create_langfolder
|
||||
fi
|
||||
|
||||
|
||||
if [ $AWS_SERVICE -eq 1 ]; then
|
||||
get_all_languages_aws
|
||||
else
|
||||
echo "Fallback language list will only get current installation languages"
|
||||
get_installed_languages
|
||||
fi
|
||||
|
||||
for lang in $langs; do
|
||||
get_language "$lang"
|
||||
done
|
||||
}
|
|
@ -228,12 +228,6 @@
|
|||
"addon.coursecompletion.requirement": "block_completionstatus",
|
||||
"addon.coursecompletion.status": "moodle",
|
||||
"addon.coursecompletion.viewcoursereport": "completion",
|
||||
"addon.files.couldnotloadfiles": "local_moodlemobileapp",
|
||||
"addon.files.emptyfilelist": "local_moodlemobileapp",
|
||||
"addon.files.erroruploadnotworking": "local_moodlemobileapp",
|
||||
"addon.files.files": "moodle",
|
||||
"addon.files.privatefiles": "moodle",
|
||||
"addon.files.sitefiles": "moodle",
|
||||
"addon.messageoutput_airnotifier.processorsettingsdesc": "local_moodlemobileapp",
|
||||
"addon.messages.acceptandaddcontact": "message",
|
||||
"addon.messages.addcontact": "message",
|
||||
|
@ -243,6 +237,7 @@
|
|||
"addon.messages.blocknoncontacts": "message",
|
||||
"addon.messages.blockuser": "message",
|
||||
"addon.messages.blockuserconfirm": "message",
|
||||
"addon.messages.cantblockuser": "message",
|
||||
"addon.messages.contactableprivacy": "message",
|
||||
"addon.messages.contactableprivacy_coursemember": "message",
|
||||
"addon.messages.contactableprivacy_onlycontacts": "message",
|
||||
|
@ -287,6 +282,7 @@
|
|||
"addon.messages.noncontacts": "message",
|
||||
"addon.messages.nousersfound": "local_moodlemobileapp",
|
||||
"addon.messages.numparticipants": "message",
|
||||
"addon.messages.pendingcontactrequests": "message",
|
||||
"addon.messages.removecontact": "message",
|
||||
"addon.messages.removecontactconfirm": "message",
|
||||
"addon.messages.removefromfavourites": "message",
|
||||
|
@ -307,6 +303,8 @@
|
|||
"addon.messages.unblockuser": "message",
|
||||
"addon.messages.unblockuserconfirm": "message",
|
||||
"addon.messages.unmuteconversation": "message",
|
||||
"addon.messages.unreadconversations": "message",
|
||||
"addon.messages.unreadmessages": "message",
|
||||
"addon.messages.useentertosend": "message",
|
||||
"addon.messages.useentertosenddescdesktop": "local_moodlemobileapp",
|
||||
"addon.messages.useentertosenddescmac": "local_moodlemobileapp",
|
||||
|
@ -382,10 +380,15 @@
|
|||
"addon.mod_assign.noteam_desc": "assign",
|
||||
"addon.mod_assign.notgraded": "assign",
|
||||
"addon.mod_assign.numberofdraftsubmissions": "assign",
|
||||
"addon.mod_assign.numberofdraftsubmissionscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_assign.numberofparticipants": "assign",
|
||||
"addon.mod_assign.numberofparticipantscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_assign.numberofsubmissionsneedgrading": "assign",
|
||||
"addon.mod_assign.numberofsubmissionsneedgradingcountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_assign.numberofsubmittedassignments": "assign",
|
||||
"addon.mod_assign.numberofsubmittedassignmentscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_assign.numberofteams": "assign",
|
||||
"addon.mod_assign.numberofteamscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_assign.numwords": "moodle",
|
||||
"addon.mod_assign.outof": "assign",
|
||||
"addon.mod_assign.overdue": "assign",
|
||||
|
@ -414,7 +417,6 @@
|
|||
"addon.mod_assign.ungroupedusersoptional": "assign",
|
||||
"addon.mod_assign.unlimitedattempts": "assign",
|
||||
"addon.mod_assign.userswhoneedtosubmit": "assign",
|
||||
"addon.mod_assign.userwithid": "local_moodlemobileapp",
|
||||
"addon.mod_assign.viewsubmission": "assign",
|
||||
"addon.mod_assign.warningsubmissiongrademodified": "local_moodlemobileapp",
|
||||
"addon.mod_assign.warningsubmissionmodified": "local_moodlemobileapp",
|
||||
|
@ -434,6 +436,7 @@
|
|||
"addon.mod_book.toc": "book",
|
||||
"addon.mod_chat.beep": "chat",
|
||||
"addon.mod_chat.chatreport": "chat",
|
||||
"addon.mod_chat.confirmloss": "local_moodlemobileapp",
|
||||
"addon.mod_chat.currentusers": "chat",
|
||||
"addon.mod_chat.enterchat": "chat",
|
||||
"addon.mod_chat.entermessage": "chat",
|
||||
|
@ -539,6 +542,7 @@
|
|||
"addon.mod_feedback.captchaofflinewarning": "local_moodlemobileapp",
|
||||
"addon.mod_feedback.complete_the_form": "feedback",
|
||||
"addon.mod_feedback.completed_feedbacks": "feedback",
|
||||
"addon.mod_feedback.completedfeedbackscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_feedback.continue_the_form": "feedback",
|
||||
"addon.mod_feedback.feedback_is_not_open": "feedback",
|
||||
"addon.mod_feedback.feedback_submitted_offline": "local_moodlemobileapp",
|
||||
|
@ -561,6 +565,7 @@
|
|||
"addon.mod_feedback.preview": "moodle",
|
||||
"addon.mod_feedback.previous_page": "feedback",
|
||||
"addon.mod_feedback.questions": "feedback",
|
||||
"addon.mod_feedback.questionscountdescription": "local_moodlemobileapp",
|
||||
"addon.mod_feedback.response_nr": "feedback",
|
||||
"addon.mod_feedback.responses": "feedback",
|
||||
"addon.mod_feedback.save_entries": "feedback",
|
||||
|
@ -600,6 +605,7 @@
|
|||
"addon.mod_forum.errorgetforum": "local_moodlemobileapp",
|
||||
"addon.mod_forum.errorgetgroups": "local_moodlemobileapp",
|
||||
"addon.mod_forum.errorposttoallgroups": "local_moodlemobileapp",
|
||||
"addon.mod_forum.favourites": "forum",
|
||||
"addon.mod_forum.favouriteupdated": "forum",
|
||||
"addon.mod_forum.forumnodiscussionsyet": "local_moodlemobileapp",
|
||||
"addon.mod_forum.group": "local_moodlemobileapp",
|
||||
|
@ -867,6 +873,7 @@
|
|||
"addon.mod_quiz.summaryofattempts": "quiz",
|
||||
"addon.mod_quiz.timeleft": "quiz",
|
||||
"addon.mod_quiz.timetaken": "quiz",
|
||||
"addon.mod_quiz.unit": "quiz",
|
||||
"addon.mod_quiz.warningattemptfinished": "local_moodlemobileapp",
|
||||
"addon.mod_quiz.warningdatadiscarded": "local_moodlemobileapp",
|
||||
"addon.mod_quiz.warningdatadiscardedfromfinished": "local_moodlemobileapp",
|
||||
|
@ -1010,6 +1017,10 @@
|
|||
"addon.mod_workshop.switchphase30": "workshop",
|
||||
"addon.mod_workshop.switchphase40": "workshop",
|
||||
"addon.mod_workshop.switchphase50": "workshop",
|
||||
"addon.mod_workshop.taskdone": "workshop",
|
||||
"addon.mod_workshop.taskfail": "workshop",
|
||||
"addon.mod_workshop.taskinfo": "workshop",
|
||||
"addon.mod_workshop.tasktodo": "workshop",
|
||||
"addon.mod_workshop.userplan": "workshop",
|
||||
"addon.mod_workshop.userplancurrentphase": "workshop",
|
||||
"addon.mod_workshop.warningassessmentmodified": "local_moodlemobileapp",
|
||||
|
@ -1019,6 +1030,7 @@
|
|||
"addon.mod_workshop.yourassessmentfor": "workshop",
|
||||
"addon.mod_workshop.yourgrades": "workshop",
|
||||
"addon.mod_workshop.yoursubmission": "workshop",
|
||||
"addon.mod_workshop.yoursubmissionwithassessments": "workshop",
|
||||
"addon.mod_workshop_assessment_accumulative.dimensioncommentfor": "workshopform_accumulative",
|
||||
"addon.mod_workshop_assessment_accumulative.dimensiongradefor": "workshopform_accumulative",
|
||||
"addon.mod_workshop_assessment_accumulative.dimensionnumber": "workshopform_accumulative",
|
||||
|
@ -1041,7 +1053,6 @@
|
|||
"addon.notes.personalnotes": "notes",
|
||||
"addon.notes.publishstate": "notes",
|
||||
"addon.notes.sitenotes": "notes",
|
||||
"addon.notes.userwithid": "local_moodlemobileapp",
|
||||
"addon.notes.warningnotenotsent": "local_moodlemobileapp",
|
||||
"addon.notifications.errorgetnotifications": "local_moodlemobileapp",
|
||||
"addon.notifications.markallread": "moodle",
|
||||
|
@ -1049,6 +1060,15 @@
|
|||
"addon.notifications.notifications": "local_moodlemobileapp",
|
||||
"addon.notifications.playsound": "local_moodlemobileapp",
|
||||
"addon.notifications.therearentnotificationsyet": "local_moodlemobileapp",
|
||||
"addon.notifications.unreadnotification": "message",
|
||||
"addon.privatefiles.couldnotloadfiles": "local_moodlemobileapp",
|
||||
"addon.privatefiles.emptyfilelist": "local_moodlemobileapp",
|
||||
"addon.privatefiles.erroruploadnotworking": "local_moodlemobileapp",
|
||||
"addon.privatefiles.files": "moodle",
|
||||
"addon.privatefiles.privatefiles": "moodle",
|
||||
"addon.privatefiles.sitefiles": "moodle",
|
||||
"addon.qtype_essay.maxwordlimitboundary": "qtype_essay",
|
||||
"addon.qtype_essay.minwordlimitboundary": "qtype_essay",
|
||||
"addon.storagemanager.deletecourse": "local_moodlemobileapp",
|
||||
"addon.storagemanager.deletecourses": "local_moodlemobileapp",
|
||||
"addon.storagemanager.deletedatafrom": "local_moodlemobileapp",
|
||||
|
@ -1388,6 +1408,7 @@
|
|||
"core.clicktohideshow": "moodle",
|
||||
"core.clicktoseefull": "local_moodlemobileapp",
|
||||
"core.close": "repository",
|
||||
"core.collapse": "moodle",
|
||||
"core.comments": "moodle",
|
||||
"core.comments.addcomment": "moodle",
|
||||
"core.comments.comments": "moodle",
|
||||
|
@ -1434,9 +1455,22 @@
|
|||
"core.course.activitynotyetviewableremoteaddon": "local_moodlemobileapp",
|
||||
"core.course.activitynotyetviewablesiteupgradeneeded": "local_moodlemobileapp",
|
||||
"core.course.allsections": "local_moodlemobileapp",
|
||||
"core.course.aria:sectionprogress": "local_moodlemobileapp",
|
||||
"core.course.askadmintosupport": "local_moodlemobileapp",
|
||||
"core.course.availablespace": "local_moodlemobileapp",
|
||||
"core.course.cannotdeletewhiledownloading": "local_moodlemobileapp",
|
||||
"core.course.completion_automatic:done": "course",
|
||||
"core.course.completion_automatic:failed": "course",
|
||||
"core.course.completion_automatic:todo": "course",
|
||||
"core.course.completion_manual:aria:done": "course",
|
||||
"core.course.completion_manual:aria:markdone": "course",
|
||||
"core.course.completion_manual:done": "course",
|
||||
"core.course.completion_manual:markdone": "course",
|
||||
"core.course.completion_setby:auto:done": "course",
|
||||
"core.course.completion_setby:auto:todo": "course",
|
||||
"core.course.completion_setby:manual:done": "course",
|
||||
"core.course.completion_setby:manual:markdone": "course",
|
||||
"core.course.completionrequirements": "course",
|
||||
"core.course.confirmdeletemodulefiles": "local_moodlemobileapp",
|
||||
"core.course.confirmdeletestoreddata": "local_moodlemobileapp",
|
||||
"core.course.confirmdownload": "local_moodlemobileapp",
|
||||
|
@ -1449,6 +1483,8 @@
|
|||
"core.course.couldnotloadsections": "local_moodlemobileapp",
|
||||
"core.course.coursesummary": "moodle",
|
||||
"core.course.downloadcourse": "tool_mobile",
|
||||
"core.course.downloadcoursesprogressdescription": "local_moodlemobileapp",
|
||||
"core.course.downloadsectionprogressdescription": "local_moodlemobileapp",
|
||||
"core.course.errordownloadingcourse": "local_moodlemobileapp",
|
||||
"core.course.errordownloadingsection": "local_moodlemobileapp",
|
||||
"core.course.errorgetmodule": "local_moodlemobileapp",
|
||||
|
@ -1460,6 +1496,7 @@
|
|||
"core.course.nocontentavailable": "local_moodlemobileapp",
|
||||
"core.course.overriddennotice": "grades",
|
||||
"core.course.refreshcourse": "local_moodlemobileapp",
|
||||
"core.course.section": "moodle",
|
||||
"core.course.sections": "moodle",
|
||||
"core.course.useactivityonbrowser": "local_moodlemobileapp",
|
||||
"core.course.warningmanualcompletionmodified": "local_moodlemobileapp",
|
||||
|
@ -1468,6 +1505,10 @@
|
|||
"core.coursenogroups": "local_moodlemobileapp",
|
||||
"core.courses.addtofavourites": "block_myoverview",
|
||||
"core.courses.allowguests": "enrol_guest",
|
||||
"core.courses.aria:coursecategory": "course",
|
||||
"core.courses.aria:coursename": "course",
|
||||
"core.courses.aria:courseprogress": "block_myoverview",
|
||||
"core.courses.aria:favourite": "course",
|
||||
"core.courses.availablecourses": "moodle",
|
||||
"core.courses.cannotretrievemorecategories": "local_moodlemobileapp",
|
||||
"core.courses.categories": "moodle",
|
||||
|
@ -1480,6 +1521,7 @@
|
|||
"core.courses.errorloadplugins": "local_moodlemobileapp",
|
||||
"core.courses.errorsearching": "local_moodlemobileapp",
|
||||
"core.courses.errorselfenrol": "local_moodlemobileapp",
|
||||
"core.courses.favourite": "course",
|
||||
"core.courses.filtermycourses": "local_moodlemobileapp",
|
||||
"core.courses.frontpage": "admin",
|
||||
"core.courses.hidecourse": "block_myoverview",
|
||||
|
@ -1502,6 +1544,7 @@
|
|||
"core.courses.selfenrolment": "local_moodlemobileapp",
|
||||
"core.courses.sendpaymentbutton": "enrol_paypal",
|
||||
"core.courses.show": "block_myoverview",
|
||||
"core.courses.therearecourses": "moodle",
|
||||
"core.courses.totalcoursesearchresults": "local_moodlemobileapp",
|
||||
"core.currentdevice": "local_moodlemobileapp",
|
||||
"core.datastoredoffline": "local_moodlemobileapp",
|
||||
|
@ -1559,6 +1602,7 @@
|
|||
"core.errorinvalidresponse": "local_moodlemobileapp",
|
||||
"core.errorloadingcontent": "local_moodlemobileapp",
|
||||
"core.errorofflinedisabled": "local_moodlemobileapp",
|
||||
"core.erroropenfiledownloading": "local_moodlemobileapp",
|
||||
"core.erroropenfilenoapp": "local_moodlemobileapp",
|
||||
"core.erroropenfilenoextension": "local_moodlemobileapp",
|
||||
"core.erroropenpopup": "local_moodlemobileapp",
|
||||
|
@ -1568,6 +1612,7 @@
|
|||
"core.errorsyncblocked": "local_moodlemobileapp",
|
||||
"core.errorurlschemeinvalidscheme": "local_moodlemobileapp",
|
||||
"core.errorurlschemeinvalidsite": "local_moodlemobileapp",
|
||||
"core.expand": "moodle",
|
||||
"core.explanationdigitalminor": "moodle",
|
||||
"core.favourites": "moodle",
|
||||
"core.filename": "repository",
|
||||
|
@ -1605,16 +1650,23 @@
|
|||
"core.forcepasswordchangenotice": "moodle",
|
||||
"core.fulllistofcourses": "moodle",
|
||||
"core.fullnameandsitename": "local_moodlemobileapp",
|
||||
"core.grades.aggregatemean": "grades",
|
||||
"core.grades.aggregatesum": "grades",
|
||||
"core.grades.average": "grades",
|
||||
"core.grades.badgrade": "grades",
|
||||
"core.grades.calculatedgrade": "grades",
|
||||
"core.grades.category": "grades",
|
||||
"core.grades.contributiontocoursetotal": "grades",
|
||||
"core.grades.feedback": "grades",
|
||||
"core.grades.grade": "grades",
|
||||
"core.grades.gradeitem": "grades",
|
||||
"core.grades.gradepass": "grades",
|
||||
"core.grades.grades": "grades",
|
||||
"core.grades.lettergrade": "grades",
|
||||
"core.grades.manualitem": "grades",
|
||||
"core.grades.nogradesreturned": "grades",
|
||||
"core.grades.nooutcome": "grades",
|
||||
"core.grades.outcome": "grades",
|
||||
"core.grades.percentage": "grades",
|
||||
"core.grades.range": "grades",
|
||||
"core.grades.rank": "grades",
|
||||
|
@ -1716,13 +1768,16 @@
|
|||
"core.hasdatatosync": "local_moodlemobileapp",
|
||||
"core.help": "moodle",
|
||||
"core.hide": "moodle",
|
||||
"core.hideadvanced": "form",
|
||||
"core.hour": "moodle",
|
||||
"core.hours": "moodle",
|
||||
"core.humanreadablesize": "local_moodlemobileapp",
|
||||
"core.iframehelp": "local_moodlemobileapp",
|
||||
"core.image": "local_moodlemobileapp",
|
||||
"core.imageviewer": "local_moodlemobileapp",
|
||||
"core.info": "moodle",
|
||||
"core.invalidformdata": "error",
|
||||
"core.ioscookieshelp": "local_moodlemobileapp",
|
||||
"core.labelsep": "langconfig",
|
||||
"core.lastaccess": "moodle",
|
||||
"core.lastdownloaded": "local_moodlemobileapp",
|
||||
|
@ -1840,6 +1895,7 @@
|
|||
"core.login.signuprequiredfieldnotsupported": "local_moodlemobileapp",
|
||||
"core.login.siteaddress": "local_moodlemobileapp",
|
||||
"core.login.siteaddressplaceholder": "donottranslate",
|
||||
"core.login.sitebadgedescription": "local_moodlemobileapp",
|
||||
"core.login.sitehasredirect": "local_moodlemobileapp",
|
||||
"core.login.siteinmaintenance": "local_moodlemobileapp",
|
||||
"core.login.sitepolicynotagreederror": "local_moodlemobileapp",
|
||||
|
@ -1859,6 +1915,7 @@
|
|||
"core.lostconnection": "local_moodlemobileapp",
|
||||
"core.mainmenu.changesite": "local_moodlemobileapp",
|
||||
"core.mainmenu.help": "moodle",
|
||||
"core.mainmenu.home": "moodle",
|
||||
"core.mainmenu.logout": "moodle",
|
||||
"core.mainmenu.website": "local_moodlemobileapp",
|
||||
"core.maxfilesize": "moodle",
|
||||
|
@ -1928,6 +1985,9 @@
|
|||
"core.openfullimage": "local_moodlemobileapp",
|
||||
"core.openinbrowser": "local_moodlemobileapp",
|
||||
"core.openmodinbrowser": "local_moodlemobileapp",
|
||||
"core.opensecurityquestion": "local_moodlemobileapp",
|
||||
"core.opensettings": "local_moodlemobileapp",
|
||||
"core.openwith": "local_moodlemobileapp",
|
||||
"core.othergroups": "group",
|
||||
"core.pagea": "moodle",
|
||||
"core.parentlanguage": "langconfig",
|
||||
|
@ -1935,6 +1995,7 @@
|
|||
"core.percentagenumber": "local_moodlemobileapp",
|
||||
"core.phone": "moodle",
|
||||
"core.pictureof": "moodle",
|
||||
"core.play": "local_moodlemobileapp",
|
||||
"core.previous": "moodle",
|
||||
"core.proceed": "moodle",
|
||||
"core.pulltorefresh": "local_moodlemobileapp",
|
||||
|
@ -1982,6 +2043,8 @@
|
|||
"core.save": "moodle",
|
||||
"core.savechanges": "assign",
|
||||
"core.scanqr": "local_moodlemobileapp",
|
||||
"core.scrollbackward": "local_moodlemobileapp",
|
||||
"core.scrollforward": "local_moodlemobileapp",
|
||||
"core.search": "moodle",
|
||||
"core.searching": "local_moodlemobileapp",
|
||||
"core.searchresults": "moodle",
|
||||
|
@ -2001,9 +2064,10 @@
|
|||
"core.settings.cannotsyncoffline": "local_moodlemobileapp",
|
||||
"core.settings.cannotsyncwithoutwifi": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme-auto": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme-dark": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme-light": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme-system": "local_moodlemobileapp",
|
||||
"core.settings.colorscheme-system-notice": "local_moodlemobileapp",
|
||||
"core.settings.compilationinfo": "local_moodlemobileapp",
|
||||
"core.settings.copyinfo": "local_moodlemobileapp",
|
||||
"core.settings.cordovadevicemodel": "local_moodlemobileapp",
|
||||
|
@ -2036,6 +2100,9 @@
|
|||
"core.settings.fontsizecharacter": "block_accessibility/char",
|
||||
"core.settings.forcedsetting": "local_moodlemobileapp",
|
||||
"core.settings.general": "moodle",
|
||||
"core.settings.helpusimprove": "local_moodlemobileapp",
|
||||
"core.settings.ioscookies": "local_moodlemobileapp",
|
||||
"core.settings.ioscookiesdescription": "local_moodlemobileapp",
|
||||
"core.settings.language": "moodle",
|
||||
"core.settings.license": "moodle",
|
||||
"core.settings.localnotifavailable": "local_moodlemobileapp",
|
||||
|
@ -2075,6 +2142,7 @@
|
|||
"core.sharedfiles.sharedfiles": "local_moodlemobileapp",
|
||||
"core.sharedfiles.successstorefile": "local_moodlemobileapp",
|
||||
"core.show": "moodle",
|
||||
"core.showadvanced": "form",
|
||||
"core.showless": "form",
|
||||
"core.showmore": "form",
|
||||
"core.site": "moodle",
|
||||
|
@ -2123,6 +2191,7 @@
|
|||
"core.tag.tagarea_course_modules": "tag",
|
||||
"core.tag.tagarea_post": "tag",
|
||||
"core.tag.tagarea_user": "tag",
|
||||
"core.tag.tagareabadgedescription": "local_moodlemobileapp",
|
||||
"core.tag.tags": "moodle",
|
||||
"core.tag.warningareasnotsupported": "local_moodlemobileapp",
|
||||
"core.teachers": "moodle",
|
||||
|
@ -2131,6 +2200,7 @@
|
|||
"core.time": "moodle",
|
||||
"core.timesup": "quiz",
|
||||
"core.today": "moodle",
|
||||
"core.toggledelete": "local_moodlemobileapp",
|
||||
"core.tryagain": "local_moodlemobileapp",
|
||||
"core.twoparagraphs": "local_moodlemobileapp",
|
||||
"core.uhoh": "local_moodlemobileapp",
|
||||
|
@ -2168,6 +2238,7 @@
|
|||
"core.user.sendemail": "local_moodlemobileapp",
|
||||
"core.user.student": "moodle/defaultcoursestudent",
|
||||
"core.user.teacher": "moodle/noneditingteacher",
|
||||
"core.user.userwithid": "local_moodlemobileapp",
|
||||
"core.user.webpage": "moodle",
|
||||
"core.userdeleted": "moodle",
|
||||
"core.userdetails": "moodle",
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
#!/bin/bash
|
||||
source "scripts/functions.sh"
|
||||
|
||||
npm run build --bailOnLintError true --typeCheckOnLint true
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $GIT_ORG_PRIVATE ] || [ -z $GIT_TOKEN ]; then
|
||||
print_error "Env vars not correctly defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# List first level of installed libraries so we can check the installed versions.
|
||||
print_title "NPM packages list"
|
||||
npm list --depth=0
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == 'master' ]; then
|
||||
print_title "Update langpacks"
|
||||
cd scripts
|
||||
./update_lang.sh
|
||||
cd ..
|
||||
|
||||
print_title "Update generated lang files"
|
||||
git remote set-url origin https://$GIT_TOKEN@github.com/$TRAVIS_REPO_SLUG.git
|
||||
git fetch -q origin
|
||||
git add -A src/assets/lang
|
||||
git add */en.json
|
||||
git add src/config.json
|
||||
git commit -m 'Update lang files [ci skip]'
|
||||
|
||||
print_title "Update Licenses"
|
||||
npm install -g license-checker
|
||||
|
||||
jq --version
|
||||
license-checker --json --production --relativeLicensePath > licenses.json
|
||||
jq 'del(.[].path)' licenses.json > licenses_old.json
|
||||
mv licenses_old.json licenses.json
|
||||
licenses=`jq -r 'keys[]' licenses.json`
|
||||
echo "{" > licensesurl.json
|
||||
first=1
|
||||
for license in $licenses; do
|
||||
obj=`jq --arg lic $license '.[$lic]' licenses.json`
|
||||
licensePath=`echo $obj | jq -r '.licenseFile'`
|
||||
file=""
|
||||
if [[ ! -z "$licensePath" ]] || [[ "$licensePath" != "null" ]]; then
|
||||
file=$(basename $licensePath)
|
||||
if [ $first -eq 1 ] ; then
|
||||
first=0
|
||||
echo "\"$license\" : { \"licenseFile\" : \"$file\"}" >> licensesurl.json
|
||||
else
|
||||
echo ",\"$license\" : { \"licenseFile\" : \"$file\"}" >> licensesurl.json
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "}" >> licensesurl.json
|
||||
|
||||
jq -s '.[0] * .[1]' licenses.json licensesurl.json > licenses_old.json
|
||||
mv licenses_old.json licenses.json
|
||||
rm licensesurl.json
|
||||
|
||||
git add licenses.json
|
||||
git commit -m 'Update licenses [ci skip]'
|
||||
|
||||
git push origin HEAD:$TRAVIS_BRANCH
|
||||
notify_on_error_exit "MIRROR: Unsuccessful push, stopping..."
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == 'integration' ] || [ "$TRAVIS_BRANCH" == 'master' ] || [ "$TRAVIS_BRANCH" == 'desktop' ] ; then
|
||||
print_title "Mirror repository"
|
||||
git remote add mirror https://$GIT_TOKEN@github.com/$GIT_ORG_PRIVATE/moodleapp.git
|
||||
git fetch -q --unshallow mirror
|
||||
notify_on_error_exit "MIRROR: Unsuccessful fetch of mirror, stopping..."
|
||||
git fetch -q origin --depth=100
|
||||
notify_on_error_exit "MIRROR: Unsuccessful fetch of origin, stopping..."
|
||||
git push -f mirror HEAD:$TRAVIS_BRANCH
|
||||
notify_on_error_exit "MIRROR: Unsuccessful mirror, stopping..."
|
||||
git push -f mirror --tags
|
||||
notify_on_error_exit "MIRROR: Unsuccessful mirror tags, stopping..."
|
||||
fi
|
|
@ -25,7 +25,7 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
|
|||
define('MOODLE_INTERNAL', 1);
|
||||
define('LANGPACKSFOLDER', '../../moodle-langpacks');
|
||||
define('ASSETSPATH', '../src/assets/lang/');
|
||||
define('CONFIG', '../src/config.json');
|
||||
define('CONFIG', '../moodle.config.json');
|
||||
define('OVERRIDE_LANG_SUFIX', false);
|
||||
|
||||
global $strings;
|
||||
|
@ -46,6 +46,11 @@ if (isset($argv[1]) && !empty($argv[1])) {
|
|||
$languages = $config_langs;
|
||||
}
|
||||
|
||||
if (!file_exists(ASSETSPATH)) {
|
||||
mkdir(ASSETSPATH);
|
||||
}
|
||||
|
||||
|
||||
$keys = get_langindex_keys();
|
||||
|
||||
$added_langs = build_languages($languages, $keys);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
$string['pluginname'] = 'Moodle App Behat (auto-generated)';
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This plugin has been auto-generated, please don't modify it.
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = {{ pluginVersion }};
|
||||
$plugin->requires = 2016052300;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
$plugin->release = '{{ appVersion }}';
|
||||
$plugin->component = 'local_moodleappbehat';
|
|
@ -10,21 +10,22 @@ dockercompose="$dockerscripts/moodle-docker-compose"
|
|||
export MOODLE_DOCKER_DB=pgsql
|
||||
export MOODLE_DOCKER_BROWSER=chrome
|
||||
export MOODLE_DOCKER_WWWROOT="$HOME/moodle"
|
||||
export MOODLE_DOCKER_PHP_VERSION=7.3
|
||||
export MOODLE_DOCKER_PHP_VERSION=7.4
|
||||
export MOODLE_DOCKER_APP_PATH=$basedir
|
||||
|
||||
# Prepare dependencies
|
||||
print_title "Preparing dependencies"
|
||||
git clone --branch master --depth 1 git://github.com/moodle/moodle $HOME/moodle
|
||||
git clone --branch master --depth 1 git://github.com/moodlehq/moodle-local_moodlemobileapp $HOME/moodle/local/moodlemobileapp
|
||||
git clone --branch master --depth 1 git://github.com/moodlehq/moodle-docker $HOME/moodle-docker
|
||||
git clone --branch ionic5 --depth 1 git://github.com/moodlehq/moodle-local_moodlemobileapp $HOME/moodle/local/moodlemobileapp
|
||||
|
||||
# TODO replace for moodlehq/moodle-docker after merging https://github.com/moodlehq/moodle-docker/pull/156
|
||||
git clone --branch MOBILE-3738 --depth 1 git://github.com/NoelDeMartin/moodle-docker $HOME/moodle-docker
|
||||
|
||||
cp $HOME/moodle-docker/config.docker-template.php $HOME/moodle/config.php
|
||||
|
||||
# Build app
|
||||
print_title "Building app"
|
||||
npm install
|
||||
npm run setup
|
||||
npm ci
|
||||
|
||||
# Start containers
|
||||
print_title "Starting containers"
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script to update language packs on assets and detect new translated languages.
|
||||
# ./update_lang.sh [language]
|
||||
# If language is set it will only update the selected language.
|
||||
#
|
||||
source "functions.sh"
|
||||
forceLang=$1
|
||||
source "lang_functions.sh"
|
||||
|
||||
print_title 'Getting languages'
|
||||
git clone --depth 1 --no-single-branch https://git.in.moodle.com/moodle/moodle-langpacks.git $LANGPACKSFOLDER
|
||||
pushd $LANGPACKSFOLDER
|
||||
BRANCHES=($(git branch -r --format="%(refname:lstrip=3)" --sort="refname" | grep MOODLE_))
|
||||
BRANCH=${BRANCHES[${#BRANCHES[@]}-1]}
|
||||
git checkout $BRANCH
|
||||
git pull
|
||||
popd
|
||||
forceLang=$1
|
||||
|
||||
print_title 'Getting local mobile langs'
|
||||
git clone --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp
|
||||
|
||||
if [ -z $forceLang ]; then
|
||||
get_languages
|
||||
php -f moodle_to_json.php
|
||||
else
|
||||
get_language "$forceLang"
|
||||
php -f moodle_to_json.php "$forceLang"
|
||||
fi
|
||||
|
||||
print_ok 'All done!'
|
||||
print_ok 'All done!'
|
||||
|
|
|
@ -25,19 +25,34 @@ function get_ws_structure($wsname, $useparams) {
|
|||
global $DB;
|
||||
|
||||
// get all the function descriptions
|
||||
$functions = $DB->get_records('external_functions', array(), 'name');
|
||||
$function = $DB->get_record('external_functions', array('services' => 'moodle_mobile_app', 'name' => $wsname));
|
||||
if (!$function) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$functiondesc = external_api::external_function_info($function);
|
||||
|
||||
if ($useparams) {
|
||||
return $functiondesc->parameters_desc;
|
||||
} else {
|
||||
return $functiondesc->returns_desc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all WS structures.
|
||||
*/
|
||||
function get_all_ws_structures() {
|
||||
global $DB;
|
||||
|
||||
// get all the function descriptions
|
||||
$functions = $DB->get_records('external_functions', array('services' => 'moodle_mobile_app'), 'name');
|
||||
$functiondescs = array();
|
||||
foreach ($functions as $function) {
|
||||
$functiondescs[$function->name] = external_api::external_function_info($function);
|
||||
}
|
||||
|
||||
if (!isset($functiondescs[$wsname])) {
|
||||
return false;
|
||||
} else if ($useparams) {
|
||||
return $functiondescs[$wsname]->parameters_desc;
|
||||
} else {
|
||||
return $functiondescs[$wsname]->returns_desc;
|
||||
}
|
||||
return $functiondescs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,6 +66,16 @@ function fix_comment($desc) {
|
|||
$desc .= '.';
|
||||
}
|
||||
|
||||
$lines = explode("\n", $desc);
|
||||
if (count($lines) > 1) {
|
||||
$desc = array_shift($lines)."\n";
|
||||
|
||||
foreach ($lines as $i => $line) {
|
||||
$spaces = strlen($line) - strlen(ltrim($line));
|
||||
$desc .= str_repeat(' ', $spaces - 3) . '// '. ltrim($line)."\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $desc;
|
||||
}
|
||||
|
||||
|
@ -86,7 +111,7 @@ function get_ts_doc($type, $desc, $indentation) {
|
|||
function convert_key_type($key, $type, $required, $indentation) {
|
||||
if ($key) {
|
||||
// It has a key, it's inside an object.
|
||||
return $indentation . "$key" . ($required == VALUE_OPTIONAL ? '?' : '') . ": $type";
|
||||
return $indentation . "$key" . ($required == VALUE_OPTIONAL || $required == VALUE_DEFAULT ? '?' : '') . ": $type";
|
||||
} else {
|
||||
// No key, it's probably in an array. Just include the type.
|
||||
return $type;
|
||||
|
@ -152,13 +177,32 @@ function convert_to_ts($key, $value, $boolisnumber = false, $indentation = '', $
|
|||
$result .= "[]";
|
||||
|
||||
return $result;
|
||||
} else if ($value == null) {
|
||||
return "{}; // WARNING: Null structure found";
|
||||
} else {
|
||||
echo "WARNING: Unknown structure: $key " . get_class($value) . " \n";
|
||||
|
||||
return "";
|
||||
return "{}; // WARNING: Unknown structure: $key " . get_class($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print structure ready to use.
|
||||
*/
|
||||
function print_ws_structure($name, $structure, $useparams) {
|
||||
if ($useparams) {
|
||||
$type = implode('', array_map('ucfirst', explode('_', $name))) . 'WSParams';
|
||||
$comment = "Params of $name WS.";
|
||||
} else {
|
||||
$type = implode('', array_map('ucfirst', explode('_', $name))) . 'WSResponse';
|
||||
$comment = "Data returned by $name WS.";
|
||||
}
|
||||
|
||||
echo "
|
||||
/**
|
||||
* $comment
|
||||
*/
|
||||
export type $type = ".convert_to_ts(null, $structure).";\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two paths.
|
||||
*/
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
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[] = [
|
||||
AddonBadgesProvider
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
],
|
||||
providers: [
|
||||
AddonBadgesProvider,
|
||||
AddonBadgesUserHandler,
|
||||
AddonBadgesMyBadgesLinkHandler,
|
||||
AddonBadgesBadgeLinkHandler,
|
||||
AddonBadgesPushClickHandler
|
||||
]
|
||||
})
|
||||
export class AddonBadgesModule {
|
||||
constructor(userDelegate: CoreUserDelegate, userHandler: AddonBadgesUserHandler,
|
||||
contentLinksDelegate: CoreContentLinksDelegate, myBadgesLinkHandler: AddonBadgesMyBadgesLinkHandler,
|
||||
badgeLinkHandler: AddonBadgesBadgeLinkHandler,
|
||||
pushNotificationsDelegate: CorePushNotificationsDelegate, pushClickHandler: AddonBadgesPushClickHandler) {
|
||||
|
||||
userDelegate.registerHandler(userHandler);
|
||||
contentLinksDelegate.registerHandler(myBadgesLinkHandler);
|
||||
contentLinksDelegate.registerHandler(badgeLinkHandler);
|
||||
pushNotificationsDelegate.registerClickHandler(pushClickHandler);
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-navbar core-back-button>
|
||||
<ion-title>{{badge && badge.name}}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="badgeLoaded" (ionRefresh)="refreshBadges($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="badgeLoaded">
|
||||
|
||||
<ion-item-group *ngIf="badge">
|
||||
<ion-item text-wrap class="item-avatar-center">
|
||||
<img *ngIf="badge.badgeurl" class="avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name">
|
||||
<ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire">
|
||||
{{ 'addon.badges.expired' | translate }}
|
||||
</ion-badge>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="user.fullname">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.recipientdetails' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'core.name' | translate}}</h2>
|
||||
<p>{{ user.fullname }}</p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="badge">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.issuerdetails' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="badge.issuername">
|
||||
<h2>{{ 'addon.badges.issuername' | translate}}</h2>
|
||||
<p>{{ badge.issuername }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.issuercontact">
|
||||
<h2>{{ 'addon.badges.contact' | translate}}</h2>
|
||||
<p><a href="mailto:{{badge.issuercontact}}" core-link auto-login="no">
|
||||
{{ badge.issuercontact }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="badge">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.badgedetails' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="badge.name">
|
||||
<h2>{{ 'core.name' | translate}}</h2>
|
||||
<p>{{ badge.name }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.version">
|
||||
<h2>{{ 'addon.badges.version' | translate}}</h2>
|
||||
<p>{{ badge.version }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.language">
|
||||
<h2>{{ 'addon.badges.language' | translate}}</h2>
|
||||
<p>{{ badge.language }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.description">
|
||||
<h2>{{ 'core.description' | translate}}</h2>
|
||||
<p>{{ badge.description }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.imageauthorname">
|
||||
<h2>{{ 'addon.badges.imageauthorname' | translate}}</h2>
|
||||
<p>{{ badge.imageauthorname }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.imageauthoremail">
|
||||
<h2>{{ 'addon.badges.imageauthoremail' | translate}}</h2>
|
||||
<p><a href="mailto:{{badge.imageauthoremail}}" core-link auto-login="no">
|
||||
{{ badge.imageauthoremail }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.imageauthorurl">
|
||||
<h2>{{ 'addon.badges.imageauthorurl' | translate}}</h2>
|
||||
<p><a [href]="badge.imageauthorurl" core-link auto-login="no">
|
||||
{{ badge.imageauthorurl }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.imagecaption">
|
||||
<h2>{{ 'addon.badges.imagecaption' | translate}}</h2>
|
||||
<p>{{ badge.imagecaption }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="course.fullname">
|
||||
<h2>{{ 'core.course' | translate}}</h2>
|
||||
<p>
|
||||
<core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"></core-format-text>
|
||||
</p>
|
||||
</ion-item>
|
||||
<!-- Criteria (not yet avalaible) -->
|
||||
</ion-item-group>
|
||||
|
||||
<ion-item-group *ngIf="badge">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.issuancedetails' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="badge.dateissued">
|
||||
<h2>{{ 'addon.badges.dateawarded' | translate}}</h2>
|
||||
<p>{{badge.dateissued * 1000 | coreFormatDate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.dateexpire">
|
||||
<h2>{{ 'addon.badges.expirydate' | translate}}</h2>
|
||||
<p>
|
||||
{{ badge.dateexpire * 1000 | coreFormatDate }}
|
||||
<span class="text-danger" *ngIf="currentTime >= badge.dateexpire">
|
||||
{{ 'addon.badges.warnexpired' | translate }}
|
||||
</span>
|
||||
</p>
|
||||
</ion-item>
|
||||
<!-- Evidence (not yet avalaible) -->
|
||||
</ion-item-group>
|
||||
|
||||
<!-- Endorsement -->
|
||||
<ion-item-group *ngIf="badge && badge.endorsement">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.bendorsement' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.issuername">
|
||||
<h2>{{ 'addon.badges.issuername' | translate}}</h2>
|
||||
<p>{{ badge.endorsement.issuername }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.issueremail">
|
||||
<h2>{{ 'addon.badges.issueremail' | translate}}</h2>
|
||||
<p><a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no">
|
||||
{{ badge.endorsement.issueremail }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.issuerurl">
|
||||
<h2>{{ 'addon.badges.issuerurl' | translate}}</h2>
|
||||
<p><a [href]="badge.endorsement.issuerurl" core-link auto-login="no">
|
||||
{{ badge.endorsement.issuerurl }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.dateissued">
|
||||
<h2>{{ 'addon.badges.dateawarded' | translate}}</h2>
|
||||
<p>{{ badge.endorsement.dateissued * 1000 | coreFormatDate }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.claimid">
|
||||
<h2>{{ 'addon.badges.claimid' | translate}}</h2>
|
||||
<p><a [href]="badge.endorsement.claimid" core-link auto-login="no">
|
||||
{{ badge.endorsement.claimid }}
|
||||
</a></p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.endorsement.claimcomment">
|
||||
<h2>{{ 'addon.badges.claimcomment' | translate}}</h2>
|
||||
<p>{{ badge.endorsement.claimcomment }}</p>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<!-- Related badges -->
|
||||
<ion-item-group *ngIf="badge && badge.relatedbadges">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.relatedbages' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngFor="let relatedBadge of badge.relatedbadges">
|
||||
<h2>{{ relatedBadge.name }}</h2>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="badge.relatedbadges.length == 0">
|
||||
<h2>{{ 'addon.badges.norelated' | translate}}</h2>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
|
||||
<!-- Competencies alignment -->
|
||||
<ion-item-group *ngIf="badge && badge.alignment">
|
||||
<ion-item-divider>
|
||||
<h2>{{ 'addon.badges.alignment' | translate}}</h2>
|
||||
</ion-item-divider>
|
||||
<a ion-item text-wrap *ngFor="let alignment of badge.alignment" [href]="alignment.targeturl" core-link auto-login="no">
|
||||
<h2>{{ alignment.targetname }}</h2>
|
||||
</a>
|
||||
<ion-item text-wrap *ngIf="badge.alignment.length == 0">
|
||||
<h2>{{ 'addon.badges.noalignment' | translate}}</h2>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -1,35 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { AddonBadgesIssuedBadgePage } from './issued-badge';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonBadgesIssuedBadgePage,
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
IonicPageModule.forChild(AddonBadgesIssuedBadgePage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonBadgesIssuedBadgePageModule {}
|
|
@ -1,113 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { Component, ViewChild } from '@angular/core';
|
||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||
import { AddonBadgesProvider, AddonBadgesUserBadge } from '../../providers/badges';
|
||||
|
||||
/**
|
||||
* Page that displays the list of calendar events.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-badges-issued-badge' })
|
||||
@Component({
|
||||
selector: 'page-addon-badges-issued-badge',
|
||||
templateUrl: 'issued-badge.html',
|
||||
})
|
||||
export class AddonBadgesIssuedBadgePage {
|
||||
@ViewChild(Content) content: Content;
|
||||
|
||||
protected badgeHash: string;
|
||||
protected userId: number;
|
||||
protected courseId: number;
|
||||
|
||||
user: any = {};
|
||||
course: any = {};
|
||||
badge: AddonBadgesUserBadge;
|
||||
|
||||
badgeLoaded = false;
|
||||
currentTime = 0;
|
||||
|
||||
constructor(private badgesProvider: AddonBadgesProvider, navParams: NavParams, sitesProvider: CoreSitesProvider,
|
||||
private domUtils: CoreDomUtilsProvider, private timeUtils: CoreTimeUtilsProvider,
|
||||
private userProvider: CoreUserProvider, private coursesProvider: CoreCoursesProvider) {
|
||||
|
||||
this.courseId = navParams.get('courseId') || 0; // Use 0 for site badges.
|
||||
this.userId = navParams.get('userId') || sitesProvider.getCurrentSite().getUserId();
|
||||
this.badgeHash = navParams.get('badgeHash');
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
|
||||
this.fetchIssuedBadge().finally(() => {
|
||||
this.badgeLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the issued badge required for the view.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
fetchIssuedBadge(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
this.currentTime = this.timeUtils.timestamp();
|
||||
promises.push(this.userProvider.getProfile(this.userId, this.courseId, true).then((user) => {
|
||||
this.user = user;
|
||||
}));
|
||||
|
||||
promises.push(this.badgesProvider.getUserBadges(this.courseId, this.userId).then((badges) => {
|
||||
const badge = badges.find((badge) => {
|
||||
return this.badgeHash == badge.uniquehash;
|
||||
});
|
||||
|
||||
if (badge) {
|
||||
this.badge = badge;
|
||||
if (badge.courseid) {
|
||||
return this.coursesProvider.getUserCourse(badge.courseid, true).then((course) => {
|
||||
this.course = course;
|
||||
}).catch(() => {
|
||||
// Maybe an old deleted course.
|
||||
this.course = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch((message) => {
|
||||
this.domUtils.showErrorModalDefault(message, 'Error getting badge data.');
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the badges.
|
||||
*
|
||||
* @param refresher Refresher.
|
||||
*/
|
||||
refreshBadges(refresher: any): void {
|
||||
this.badgesProvider.invalidateUserBadges(this.courseId, this.userId).finally(() => {
|
||||
this.fetchIssuedBadge().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-navbar core-back-button>
|
||||
<ion-title>{{ 'addon.badges.badges' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<core-split-view>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="badgesLoaded" (ionRefresh)="refreshBadges($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="badgesLoaded">
|
||||
<core-empty-box *ngIf="!badges || badges.length == 0" icon="trophy" [message]="'addon.badges.nobadges' | translate">
|
||||
</core-empty-box>
|
||||
|
||||
<ion-list *ngIf="badges && badges.length" no-margin>
|
||||
<a ion-item text-wrap *ngFor="let badge of badges" [title]="badge.name" (click)="loadIssuedBadge(badge.uniquehash)" [class.core-split-item-selected]="badge.uniquehash == badgeHash">
|
||||
<ion-avatar item-start>
|
||||
<img [src]="badge.badgeurl" [alt]="badge.name" item-start core-external-content>
|
||||
</ion-avatar>
|
||||
<h2>{{ badge.name }}</h2>
|
||||
<p>{{ badge.dateissued * 1000 | coreFormatDate :'strftimedatetimeshort' }}</p>
|
||||
<ion-badge item-end color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire">
|
||||
{{ 'addon.badges.expired' | translate }}
|
||||
</ion-badge>
|
||||
</a>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
</core-split-view>
|
|
@ -1,35 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { AddonBadgesUserBadgesPage } from './user-badges';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonBadgesUserBadgesPage,
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
IonicPageModule.forChild(AddonBadgesUserBadgesPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonBadgesUserBadgesPageModule {}
|
|
@ -1,102 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { Component, ViewChild } from '@angular/core';
|
||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
||||
import { AddonBadgesProvider, AddonBadgesUserBadge } from '../../providers/badges';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
|
||||
/**
|
||||
* Page that displays the list of calendar events.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-badges-user-badges' })
|
||||
@Component({
|
||||
selector: 'page-addon-badges-user-badges',
|
||||
templateUrl: 'user-badges.html',
|
||||
})
|
||||
export class AddonBadgesUserBadgesPage {
|
||||
@ViewChild(Content) content: Content;
|
||||
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
||||
|
||||
courseId: number;
|
||||
userId: number;
|
||||
|
||||
badgesLoaded = false;
|
||||
badges: AddonBadgesUserBadge[] = [];
|
||||
currentTime = 0;
|
||||
badgeHash: string;
|
||||
|
||||
constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, private badgesProvider: AddonBadgesProvider,
|
||||
private domUtils: CoreDomUtilsProvider, private timeUtils: CoreTimeUtilsProvider) {
|
||||
|
||||
this.courseId = navParams.get('courseId') || 0; // Use 0 for site badges.
|
||||
this.userId = navParams.get('userId') || sitesProvider.getCurrentSite().getUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
|
||||
this.fetchBadges().finally(() => {
|
||||
if (!this.badgeHash && this.splitviewCtrl.isOn() && this.badges.length > 0) {
|
||||
// Take first and load it.
|
||||
this.loadIssuedBadge(this.badges[0].uniquehash);
|
||||
}
|
||||
this.badgesLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all the badges required for the view.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
fetchBadges(): Promise<any> {
|
||||
this.currentTime = this.timeUtils.timestamp();
|
||||
|
||||
return this.badgesProvider.getUserBadges(this.courseId, this.userId).then((badges) => {
|
||||
this.badges = badges;
|
||||
}).catch((message) => {
|
||||
this.domUtils.showErrorModalDefault(message, 'Error getting badges data.');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the badges.
|
||||
*
|
||||
* @param refresher Refresher.
|
||||
*/
|
||||
refreshBadges(refresher: any): void {
|
||||
this.badgesProvider.invalidateUserBadges(this.courseId, this.userId).finally(() => {
|
||||
this.fetchBadges().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a particular badge.
|
||||
*
|
||||
* @param badgeHash Badge to load.
|
||||
*/
|
||||
loadIssuedBadge(badgeHash: string): void {
|
||||
this.badgeHash = badgeHash;
|
||||
const params = {courseId: this.courseId, userId: this.userId, badgeHash: badgeHash};
|
||||
this.splitviewCtrl.push('AddonBadgesIssuedBadgePage', params);
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { AddonBadgesProvider } from './badges';
|
||||
|
||||
/**
|
||||
* Handler to treat links to user participants page.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBadgesBadgeLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonBadgesBadgeLinkHandler';
|
||||
pattern = /\/badges\/badge\.php.*([\?\&]hash=)/;
|
||||
|
||||
constructor(private badgesProvider: AddonBadgesProvider, private linkHelper: CoreContentLinksHelperProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
* @param siteIds List of sites the URL belongs to.
|
||||
* @param url The URL to treat.
|
||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
||||
* @return 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, 'AddonBadgesIssuedBadgePage', {courseId: 0, badgeHash: params.hash}, siteId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @param url The URL to treat.
|
||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
||||
* @return Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||
|
||||
return this.badgesProvider.isPluginEnabled(siteId);
|
||||
}
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreWSExternalWarning } from '@providers/ws';
|
||||
import { CoreSite } from '@classes/site';
|
||||
|
||||
/**
|
||||
* Service to handle badges.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBadgesProvider {
|
||||
protected logger;
|
||||
protected ROOT_CACHE_KEY = 'mmaBadges:';
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
|
||||
this.logger = logger.getInstance('AddonBadgesProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the badge plugin is enabled for a certain site.
|
||||
*
|
||||
* This method is called quite often and thus should only perform a quick
|
||||
* check, we should not be calling WS from here.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if enabled, false otherwise.
|
||||
*/
|
||||
isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
if (!site.canUseAdvancedFeature('enablebadges')) {
|
||||
return false;
|
||||
} else if (!site.wsAvailable('core_course_get_user_navigation_options')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache key for the get badges call.
|
||||
*
|
||||
* @param courseId ID of the course to get the badges from.
|
||||
* @param userId ID of the user to get the badges from.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getBadgesCacheKey(courseId: number, userId: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'badges:' + courseId + ':' + userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get issued badges for a certain user in a course.
|
||||
*
|
||||
* @param courseId ID of the course to get the badges from.
|
||||
* @param userId ID of the user to get the badges from.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise to be resolved when the badges are retrieved.
|
||||
*/
|
||||
getUserBadges(courseId: number, userId: number, siteId?: string): Promise<AddonBadgesUserBadge[]> {
|
||||
|
||||
this.logger.debug('Get badges for course ' + courseId);
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
|
||||
const data = {
|
||||
courseid : courseId,
|
||||
userid : userId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getBadgesCacheKey(courseId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
return site.read('core_badges_get_user_badges', data, preSets).then((response: AddonBadgesGetUserBadgesResult): any => {
|
||||
if (response && response.badges) {
|
||||
// In 3.7, competencies was renamed to alignment. Rename the property in 3.6 too.
|
||||
response.badges.forEach((badge) => {
|
||||
badge.alignment = badge.alignment || badge.competencies;
|
||||
|
||||
// Check that the alignment is valid, they were broken in 3.7.
|
||||
if (badge.alignment && badge.alignment[0] && typeof badge.alignment[0].targetname == 'undefined') {
|
||||
// If any badge lacks targetname it means they are affected by the Moodle bug, don't display them.
|
||||
delete badge.alignment;
|
||||
}
|
||||
});
|
||||
|
||||
return response.badges;
|
||||
} else {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate get badges WS call.
|
||||
*
|
||||
* @param courseId Course ID.
|
||||
* @param userId ID of the user to get the badges from.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when data is invalidated.
|
||||
*/
|
||||
invalidateUserBadges(courseId: number, userId: number, siteId?: string): Promise<any> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.invalidateWsCacheForKey(this.getBadgesCacheKey(courseId, userId));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of WS core_badges_get_user_badges.
|
||||
*/
|
||||
export type AddonBadgesGetUserBadgesResult = {
|
||||
badges: AddonBadgesUserBadge[]; // List of badges.
|
||||
warnings?: CoreWSExternalWarning[]; // List of warnings.
|
||||
};
|
||||
|
||||
/**
|
||||
* Badge data returned by WS core_badges_get_user_badges.
|
||||
*/
|
||||
export type AddonBadgesUserBadge = {
|
||||
id?: number; // Badge id.
|
||||
name: string; // Badge name.
|
||||
description: string; // Badge description.
|
||||
timecreated?: number; // Time created.
|
||||
timemodified?: number; // Time modified.
|
||||
usercreated?: number; // User created.
|
||||
usermodified?: number; // User modified.
|
||||
issuername: string; // Issuer name.
|
||||
issuerurl: string; // Issuer URL.
|
||||
issuercontact: string; // Issuer contact.
|
||||
expiredate?: number; // Expire date.
|
||||
expireperiod?: number; // Expire period.
|
||||
type?: number; // Type.
|
||||
courseid?: number; // Course id.
|
||||
message?: string; // Message.
|
||||
messagesubject?: string; // Message subject.
|
||||
attachment?: number; // Attachment.
|
||||
notification?: number; // @since 3.6. Whether to notify when badge is awarded.
|
||||
nextcron?: number; // @since 3.6. Next cron.
|
||||
status?: number; // Status.
|
||||
issuedid?: number; // Issued id.
|
||||
uniquehash: string; // Unique hash.
|
||||
dateissued: number; // Date issued.
|
||||
dateexpire: number; // Date expire.
|
||||
visible?: number; // Visible.
|
||||
email?: string; // @since 3.6. User email.
|
||||
version?: string; // @since 3.6. Version.
|
||||
language?: string; // @since 3.6. Language.
|
||||
imageauthorname?: string; // @since 3.6. Name of the image author.
|
||||
imageauthoremail?: string; // @since 3.6. Email of the image author.
|
||||
imageauthorurl?: string; // @since 3.6. URL of the image author.
|
||||
imagecaption?: string; // @since 3.6. Caption of the image.
|
||||
badgeurl: string; // Badge URL.
|
||||
endorsement?: { // @since 3.6.
|
||||
id: number; // Endorsement id.
|
||||
badgeid: number; // Badge id.
|
||||
issuername: string; // Endorsement issuer name.
|
||||
issuerurl: string; // Endorsement issuer URL.
|
||||
issueremail: string; // Endorsement issuer email.
|
||||
claimid: string; // Claim URL.
|
||||
claimcomment: string; // Claim comment.
|
||||
dateissued: number; // Date issued.
|
||||
};
|
||||
alignment?: { // @since 3.7. Calculated by the app for 3.6 sites. Badge alignments.
|
||||
id?: number; // Alignment id.
|
||||
badgeid?: number; // Badge id.
|
||||
targetname?: string; // Target name.
|
||||
targeturl?: string; // Target URL.
|
||||
targetdescription?: string; // Target description.
|
||||
targetframework?: string; // Target framework.
|
||||
targetcode?: string; // Target code.
|
||||
}[];
|
||||
competencies?: { // @deprecated from 3.7. @since 3.6. In 3.7 it was renamed to alignment.
|
||||
id?: number; // Alignment id.
|
||||
badgeid?: number; // Badge id.
|
||||
targetname?: string; // Target name.
|
||||
targeturl?: string; // Target URL.
|
||||
targetdescription?: string; // Target description.
|
||||
targetframework?: string; // Target framework.
|
||||
targetcode?: string; // Target code.
|
||||
}[];
|
||||
relatedbadges?: { // @since 3.6. Related badges.
|
||||
id: number; // Badge id.
|
||||
name: string; // Badge name.
|
||||
version?: string; // Version.
|
||||
language?: string; // Language.
|
||||
type?: number; // Type.
|
||||
}[];
|
||||
};
|
|
@ -1,67 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { AddonBadgesProvider } from './badges';
|
||||
|
||||
/**
|
||||
* Handler to treat links to user badges page.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBadgesMyBadgesLinkHandler extends CoreContentLinksHandlerBase {
|
||||
name = 'AddonBadgesMyBadgesLinkHandler';
|
||||
featureName = 'CoreUserDelegate_AddonBadges';
|
||||
pattern = /\/badges\/mybadges\.php/;
|
||||
|
||||
constructor(private badgesProvider: AddonBadgesProvider, private linkHelper: CoreContentLinksHelperProvider) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of actions for a link (url).
|
||||
*
|
||||
* @param siteIds List of sites the URL belongs to.
|
||||
* @param url The URL to treat.
|
||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
||||
* @return 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, 'AddonBadgesUserBadgesPage', {}, siteId);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @param url The URL to treat.
|
||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
||||
* @return Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise<boolean> {
|
||||
|
||||
return this.badgesProvider.isPluginEnabled(siteId);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 notification The notification to check.
|
||||
* @return 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 notification The notification to check.
|
||||
* @return 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,75 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate';
|
||||
import { AddonBadgesProvider } from './badges';
|
||||
|
||||
/**
|
||||
* Profile badges handler.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBadgesUserHandler implements CoreUserProfileHandler {
|
||||
name = 'AddonBadges';
|
||||
priority = 50;
|
||||
type = CoreUserDelegate.TYPE_NEW_PAGE;
|
||||
|
||||
constructor(protected badgesProvider: AddonBadgesProvider) { }
|
||||
|
||||
/**
|
||||
* Check if handler is enabled.
|
||||
*
|
||||
* @return Always enabled.
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return this.badgesProvider.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if handler is enabled for this user in this context.
|
||||
*
|
||||
* @param user User to check.
|
||||
* @param courseId Course ID.
|
||||
* @param navOptions Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
|
||||
* @param admOptions Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
|
||||
* @return True if enabled, false otherwise.
|
||||
*/
|
||||
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean {
|
||||
|
||||
if (navOptions && typeof navOptions.badges != 'undefined') {
|
||||
return navOptions.badges;
|
||||
}
|
||||
|
||||
// If we reach here, it means we are opening the user site profile.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data needed to render the handler.
|
||||
*
|
||||
* @return Data needed to render the handler.
|
||||
*/
|
||||
getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData {
|
||||
return {
|
||||
icon: 'trophy',
|
||||
title: 'addon.badges.badges',
|
||||
class: '',
|
||||
action: (event, navCtrl, user, courseId): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
navCtrl.push('AddonBadgesUserBadgesPage', {courseId: courseId, userId: user.id });
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { AddonBlockActivityModulesComponentsModule } from './components/components.module';
|
||||
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||
import { AddonBlockActivityModulesHandler } from './providers/block-handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
AddonBlockActivityModulesComponentsModule,
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
exports: [
|
||||
],
|
||||
providers: [
|
||||
AddonBlockActivityModulesHandler
|
||||
]
|
||||
})
|
||||
export class AddonBlockActivityModulesModule {
|
||||
constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockActivityModulesHandler) {
|
||||
blockDelegate.registerHandler(blockHandler);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
ion-app.app-root.md addon-block-activitymodules {
|
||||
.core-module-icon {
|
||||
margin-top: $label-md-margin-top;
|
||||
margin-bottom: $label-md-margin-bottom;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
ion-app.app-root.ios addon-block-activitymodules {
|
||||
.core-module-icon {
|
||||
margin-top: $label-ios-margin-top;
|
||||
margin-bottom: $label-ios-margin-bottom;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { Component, OnInit, Injector, Input } from '@angular/core';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
|
||||
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
||||
import { CoreConstants, ContextLevel } from '@core/constants';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
|
||||
/**
|
||||
* Component to render an "activity modules" block.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-block-activitymodules',
|
||||
templateUrl: 'addon-block-activitymodules.html'
|
||||
})
|
||||
export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent implements OnInit {
|
||||
@Input() block: any; // The block to render.
|
||||
@Input() contextLevel: ContextLevel; // The context where the block will be used.
|
||||
@Input() instanceId: number; // The instance ID associated with the context level.
|
||||
|
||||
entries: any[] = [];
|
||||
|
||||
protected fetchContentDefaultError = 'Error getting activity modules data.';
|
||||
|
||||
constructor(injector: Injector, protected courseProvider: CoreCourseProvider,
|
||||
protected translate: TranslateService, protected moduleDelegate: CoreCourseModuleDelegate,
|
||||
protected sitesProvider: CoreSitesProvider) {
|
||||
|
||||
super(injector, 'AddonBlockActivityModulesComponent');
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
protected invalidateContent(): Promise<any> {
|
||||
return this.courseProvider.invalidateSections(this.instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the data to render the block.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchContent(): Promise<any> {
|
||||
return this.courseProvider.getSections(this.getCourseId(), false, true).then((sections) => {
|
||||
this.entries = [];
|
||||
|
||||
const archetypes = {},
|
||||
modIcons = {};
|
||||
let modFullNames = {};
|
||||
|
||||
sections.forEach((section) => {
|
||||
if (!section.modules) {
|
||||
return;
|
||||
}
|
||||
|
||||
section.modules.forEach((mod) => {
|
||||
if (mod.uservisible === false || !this.courseProvider.moduleHasView(mod) ||
|
||||
typeof modFullNames[mod.modname] != 'undefined') {
|
||||
// Ignore this module.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the archetype of the module type.
|
||||
if (typeof archetypes[mod.modname] == 'undefined') {
|
||||
archetypes[mod.modname] = this.moduleDelegate.supportsFeature(mod.modname,
|
||||
CoreConstants.FEATURE_MOD_ARCHETYPE, CoreConstants.MOD_ARCHETYPE_OTHER);
|
||||
}
|
||||
|
||||
// Get the full name of the module type.
|
||||
if (archetypes[mod.modname] == CoreConstants.MOD_ARCHETYPE_RESOURCE) {
|
||||
// All resources are gathered in a single "Resources" option.
|
||||
if (!modFullNames['resources']) {
|
||||
modFullNames['resources'] = this.translate.instant('core.resources');
|
||||
}
|
||||
} else {
|
||||
modFullNames[mod.modname] = mod.modplural;
|
||||
}
|
||||
modIcons[mod.modname] = mod.modicon;
|
||||
});
|
||||
});
|
||||
|
||||
// Sort the modnames alphabetically.
|
||||
modFullNames = this.utils.sortValues(modFullNames);
|
||||
|
||||
for (const modName in modFullNames) {
|
||||
let icon;
|
||||
|
||||
if (modName === 'resources') {
|
||||
icon = this.courseProvider.getModuleIconSrc('page', modIcons['page']);
|
||||
} else {
|
||||
icon = this.moduleDelegate.getModuleIconSrc(modName, modIcons[modName]);
|
||||
}
|
||||
|
||||
this.entries.push({
|
||||
icon: icon,
|
||||
name: modFullNames[modName],
|
||||
modName: modName
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the appropiate course id for the block.
|
||||
*
|
||||
* @return Course id.
|
||||
*/
|
||||
protected getCourseId(): number {
|
||||
switch (this.contextLevel) {
|
||||
case ContextLevel.COURSE:
|
||||
return this.instanceId;
|
||||
default:
|
||||
return this.sitesProvider.getCurrentSiteHomeId();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<ion-item-divider>
|
||||
<h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2>
|
||||
</ion-item-divider>
|
||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
<a ion-item text-wrap *ngFor="let entry of entries" class="item-media" detail-none navPush="CoreCourseListModTypePage" [navParams]="{title: entry.name, courseId: instanceId, modName: entry.modName}">
|
||||
<img item-start [src]="entry.icon" alt="" role="presentation" class="core-module-icon">
|
||||
{{ entry.name }}
|
||||
</a>
|
||||
</core-loading>
|
|
@ -1,45 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AddonBlockActivityModulesComponent } from './activitymodules/activitymodules';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonBlockActivityModulesComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CoreCourseComponentsModule
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonBlockActivityModulesComponent
|
||||
],
|
||||
entryComponents: [
|
||||
AddonBlockActivityModulesComponent
|
||||
]
|
||||
})
|
||||
export class AddonBlockActivityModulesComponentsModule {}
|
|
@ -1,50 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, Injector } from '@angular/core';
|
||||
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||
import { AddonBlockActivityModulesComponent } from '../components/activitymodules/activitymodules';
|
||||
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBlockActivityModulesHandler extends CoreBlockBaseHandler {
|
||||
name = 'AddonBlockActivityModules';
|
||||
blockName = 'activity_modules';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data needed to render the block.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param block The block to render.
|
||||
* @param contextLevel The context where the block will be used.
|
||||
* @param instanceId The instance ID associated with the context level.
|
||||
* @return Data or promise resolved with the data.
|
||||
*/
|
||||
getDisplayData(injector: Injector, block: any, contextLevel: string, instanceId: number)
|
||||
: CoreBlockHandlerData | Promise<CoreBlockHandlerData> {
|
||||
|
||||
return {
|
||||
title: 'addon.block_activitymodules.pluginname',
|
||||
class: 'addon-block-activitymodules',
|
||||
component: AddonBlockActivityModulesComponent
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||
import { AddonBlockActivityResultsHandler } from './providers/block-handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
exports: [
|
||||
],
|
||||
providers: [
|
||||
AddonBlockActivityResultsHandler
|
||||
]
|
||||
})
|
||||
export class AddonBlockActivityResultsModule {
|
||||
constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockActivityResultsHandler) {
|
||||
blockDelegate.registerHandler(blockHandler);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
.addon-block-activity-results core-block-pre-rendered {
|
||||
ion-item.core-block-content {
|
||||
table.grades {
|
||||
@include text-align('start');
|
||||
width: 100%;
|
||||
|
||||
.number {
|
||||
@include text-align('start');
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.name {
|
||||
@include text-align('start');
|
||||
width: 77%;
|
||||
}
|
||||
|
||||
.grade {
|
||||
@include text-align('end');
|
||||
}
|
||||
|
||||
caption {
|
||||
@include text-align('start');
|
||||
padding-top: .75rem;
|
||||
padding-bottom: .75rem;
|
||||
color: $gray-darker;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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, Injector } from '@angular/core';
|
||||
|
||||
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||
import { CoreBlockPreRenderedComponent } from '@core/block/components/pre-rendered-block/pre-rendered-block';
|
||||
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonBlockActivityResultsHandler extends CoreBlockBaseHandler {
|
||||
name = 'AddonBlockActivityResults';
|
||||
blockName = 'activity_results';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data needed to render the block.
|
||||
*
|
||||
* @param injector Injector.
|
||||
* @param block The block to render.
|
||||
* @param contextLevel The context where the block will be used.
|
||||
* @param instanceId The instance ID associated with the context level.
|
||||
* @return Data or promise resolved with the data.
|
||||
*/
|
||||
getDisplayData(injector: Injector, block: any, contextLevel: string, instanceId: number)
|
||||
: CoreBlockHandlerData | Promise<CoreBlockHandlerData> {
|
||||
|
||||
return {
|
||||
title: 'addon.block_activityresults.pluginname',
|
||||
class: 'addon-block-activity-results',
|
||||
component: CoreBlockPreRenderedComponent
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||
import { AddonBlockBadgesHandler } from './providers/block-handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
IonicModule,
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
exports: [
|
||||
],
|
||||
providers: [
|
||||
AddonBlockBadgesHandler
|
||||
]
|
||||
})
|
||||
export class AddonBlockBadgesModule {
|
||||
constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockBadgesHandler) {
|
||||
blockDelegate.registerHandler(blockHandler);
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
.addon-block-badges core-block-pre-rendered {
|
||||
.core-block-content {
|
||||
ul.badges {
|
||||
list-style: none;
|
||||
@include margin-horizontal(0);
|
||||
-webkit-padding-start: 0;
|
||||
|
||||
li {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding-top: 1em;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
width: 150px;
|
||||
|
||||
.badge-name {
|
||||
display: block;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue