Merge remote-tracking branch 'origin/feature/new-content-block-creation-workflow' into develop
This commit is contained in:
commit
a626fd9d04
|
|
@ -1,3 +1,13 @@
|
||||||
{
|
{
|
||||||
"schemaPath": "server/schema.graphql"
|
"projects": {
|
||||||
|
"private": {
|
||||||
|
"schemaPath": "./server/schema.graphql",
|
||||||
|
"includes": ["./client/src/graphql/**"],
|
||||||
|
"excludes": ["./client/src/graphql/gql/public-client/**"]
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"schemaPath": "./server/schema-public.graphql",
|
||||||
|
"includes": ["./client/src/graphql/gql/public-client/*.gql"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
schema: 'server/schema.graphql'
|
|
||||||
4
Pipfile
4
Pipfile
|
|
@ -42,6 +42,8 @@ ipython = "*"
|
||||||
requests = "*"
|
requests = "*"
|
||||||
unittest-xml-reporting = "*"
|
unittest-xml-reporting = "*"
|
||||||
django-silk = "*"
|
django-silk = "*"
|
||||||
wagtail-autocomplete = "*"
|
# todo: @django3-update
|
||||||
|
# wagtail-autocomplete = "*"
|
||||||
|
wagtail-autocomplete = "==0.6.3"
|
||||||
jedi = "==0.17.2"
|
jedi = "==0.17.2"
|
||||||
Authlib = "*"
|
Authlib = "*"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
[[source]]
|
||||||
|
url = "https://pypi.python.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
awscli = "*"
|
||||||
|
ipdb = "*"
|
||||||
|
coverage = "*"
|
||||||
|
django-silk = "*"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
factory-boy = "==2.11.0"
|
||||||
|
wagtail_factories = "==2.0.0"
|
||||||
|
django = "==3.2"
|
||||||
|
whitenoise = "~=5.3"
|
||||||
|
psycopg2 = "==2.8.6"
|
||||||
|
gunicorn = "==19.7.1"
|
||||||
|
python-dotenv = "==0.13.0"
|
||||||
|
dj-database-url = "==0.4.1"
|
||||||
|
raven = "==6.9.0"
|
||||||
|
django-extensions = "==1.9.8"
|
||||||
|
graphene-django = "==2.15.0"
|
||||||
|
django-filter = "~=21.1"
|
||||||
|
djangorestframework = "~=3.8"
|
||||||
|
pillow = "==5.0.0"
|
||||||
|
wagtail = "~=2.15"
|
||||||
|
django-cors-headers = "~=3.0"
|
||||||
|
django-storages = "*"
|
||||||
|
boto3 = "*"
|
||||||
|
django-compressor = "*"
|
||||||
|
django-libsass = "*"
|
||||||
|
bleach = "*"
|
||||||
|
newrelic = "*"
|
||||||
|
sentry-sdk = "==0.7.2"
|
||||||
|
django-sendgrid-v5 = "==0.8.0"
|
||||||
|
python-http-client = "==3.2.1"
|
||||||
|
ipython = "*"
|
||||||
|
requests = "*"
|
||||||
|
unittest-xml-reporting = "*"
|
||||||
|
django-silk = "*"
|
||||||
|
wagtail-autocomplete = "*"
|
||||||
|
jedi = "==0.17.2"
|
||||||
|
Authlib = "*"
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -270,3 +270,8 @@ Command:
|
||||||
```
|
```
|
||||||
./bin/pg-backup-to-s3
|
./bin/pg-backup-to-s3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Note on component
|
||||||
|
Our own components remain in kebap-case, imported components from third party libraries will be used in PascalCase.
|
||||||
|
E.g. `<password-change-form/>` vs. `<ValidationProvider/>`
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,36 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
parser: 'babel-eslint'
|
parser: '@typescript-eslint/parser',
|
||||||
|
extraFileExtensions: ['.vue'],
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
},
|
},
|
||||||
|
globals: {
|
||||||
|
process: "readonly"
|
||||||
|
},
|
||||||
extends: [
|
extends: [
|
||||||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
||||||
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
||||||
'plugin:vue/recommended',
|
'plugin:vue/recommended',
|
||||||
// 'plugin:vue/recommended',
|
// 'plugin:vue/recommended',
|
||||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||||
'standard'
|
//'standard'
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/eslint-recommended'
|
||||||
],
|
],
|
||||||
// required to lint *.vue files
|
// required to lint *.vue files
|
||||||
plugins: [
|
plugins: [
|
||||||
'vue'
|
'vue',
|
||||||
|
'@typescript-eslint'
|
||||||
],
|
],
|
||||||
|
overrides: [{
|
||||||
|
files: ['*.ts','*.tsx'],
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': 'off'
|
||||||
|
}
|
||||||
|
}],
|
||||||
// add your custom rules here
|
// add your custom rules here
|
||||||
rules: {
|
rules: {
|
||||||
// allow async-await
|
// allow async-await
|
||||||
|
|
@ -49,6 +62,9 @@ module.exports = {
|
||||||
'CONTENT'
|
'CONTENT'
|
||||||
]
|
]
|
||||||
}],
|
}],
|
||||||
|
"vue/multi-word-component-names": ["off", {
|
||||||
|
"ignores": []
|
||||||
|
}],
|
||||||
'vue/order-in-components': ['error', {
|
'vue/order-in-components': ['error', {
|
||||||
'order': [
|
'order': [
|
||||||
'el',
|
'el',
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ spinner.start()
|
||||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
webpack(webpackConfig, (err, stats) => {
|
webpack(webpackConfig, (err, stats) => {
|
||||||
spinner.stop()
|
spinner.succeed()
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
process.stdout.write(stats.toString({
|
process.stdout.write(stats.toString({
|
||||||
colors: true,
|
colors: true,
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,10 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
|
||||||
const packageConfig = require('../package.json')
|
const packageConfig = require('../package.json')
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV !== 'production';
|
const isDev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
const styleRule = (scss) => {
|
|
||||||
const test = scss ? /\.scss$/ : /\.css$/;
|
|
||||||
let use = [
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
// options: {importLoaders: scss ? 3 : 2}
|
|
||||||
options: {
|
|
||||||
sourceMap: isDev,
|
|
||||||
importLoaders: scss ? 2 : 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'postcss-loader'
|
|
||||||
];
|
|
||||||
if (scss) {
|
|
||||||
use = [
|
|
||||||
...use,
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
data: process.env.THEME ? `@import "styles/themes/_${process.env.THEME}.scss";` : '',
|
|
||||||
sourceMap: isDev
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDev) {
|
|
||||||
return {
|
|
||||||
test,
|
|
||||||
loader: ExtractTextPlugin.extract({
|
|
||||||
use,
|
|
||||||
fallback: 'vue-style-loader'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
test,
|
|
||||||
use: [
|
|
||||||
'vue-style-loader',
|
|
||||||
...use
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const assetsPath = (_path) => {
|
const assetsPath = (_path) => {
|
||||||
const assetsSubDirectory = isDev
|
const assetsSubDirectory = isDev
|
||||||
? config.dev.assetsSubDirectory
|
? config.dev.assetsSubDirectory
|
||||||
|
|
@ -78,7 +32,6 @@ const createNotifierCallback = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
styleRule,
|
|
||||||
isDev,
|
isDev,
|
||||||
assetsPath,
|
assetsPath,
|
||||||
createNotifierCallback
|
createNotifierCallback
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
'use strict'
|
|
||||||
const config = require('../config')
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// cacheBusting: config.dev.cacheBusting,
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
|
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||||
|
|
||||||
const {VueLoaderPlugin} = require('vue-loader');
|
const {VueLoaderPlugin} = require('vue-loader');
|
||||||
|
|
||||||
const {isDev, styleRule, assetsPath} = require('./utils');
|
const {isDev, assetsPath} = require('./utils');
|
||||||
|
|
||||||
function resolve(dir) {
|
function resolve(dir) {
|
||||||
return path.join(__dirname, '..', dir);
|
return path.join(__dirname, '..', dir);
|
||||||
|
|
@ -37,13 +38,29 @@ module.exports = {
|
||||||
? config.dev.assetsPublicPath
|
? config.dev.assetsPublicPath
|
||||||
: config.build.assetsPublicPath,
|
: config.build.assetsPublicPath,
|
||||||
},
|
},
|
||||||
|
optimization: {
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'all'
|
||||||
|
}
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue', '.json', '.gql', '.graphql', '.scss'],
|
extensions: ['.js', '.vue', '.json', '.gql', '.graphql', '.scss'],
|
||||||
alias: {
|
alias: {
|
||||||
'@': resolve('src'),
|
'@': resolve('src'),
|
||||||
styles: resolve('src/styles'),
|
styles: resolve('src/styles'),
|
||||||
gql: resolve('src/graphql/gql'),
|
gql: resolve('src/graphql/gql'),
|
||||||
|
// vue: '@vue/compat',
|
||||||
},
|
},
|
||||||
|
// we probably don't need this anymore
|
||||||
|
// fallback: {
|
||||||
|
// // used to be in node: {setImmediate: false,...}
|
||||||
|
// setImmediate: false,
|
||||||
|
// dgram: false,
|
||||||
|
// fs: false,
|
||||||
|
// net: false,
|
||||||
|
// tls: false,
|
||||||
|
// child_process: false,
|
||||||
|
// },
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
@ -58,6 +75,11 @@ module.exports = {
|
||||||
img: 'src',
|
img: 'src',
|
||||||
image: 'xlink:href',
|
image: 'xlink:href',
|
||||||
},
|
},
|
||||||
|
compilerOptions: {
|
||||||
|
compatConfig: {
|
||||||
|
MODE: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -105,23 +127,33 @@ module.exports = {
|
||||||
name: assetsPath('fonts/[name].[hash:7].[ext]'),
|
name: assetsPath('fonts/[name].[hash:7].[ext]'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
styleRule(false), // css rule
|
{
|
||||||
styleRule(true), // sass rule
|
test: /\.s?css$/,
|
||||||
|
use: [
|
||||||
|
isDev ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
|
||||||
|
'css-loader',
|
||||||
|
'postcss-loader',
|
||||||
|
'sass-loader'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
// styleRule(false), // css rule
|
||||||
|
// styleRule(true), // sass rule
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new VueLoaderPlugin(),
|
new VueLoaderPlugin(),
|
||||||
],
|
],
|
||||||
node: {
|
|
||||||
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
// node: {
|
||||||
// source contains it (although only uses it if it's native).
|
// // prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
setImmediate: false,
|
// // source contains it (although only uses it if it's native).
|
||||||
// prevent webpack from injecting mocks to Node native modules
|
// setImmediate: false,
|
||||||
// that does not make sense for the client
|
// // prevent webpack from injecting mocks to Node native modules
|
||||||
dgram: 'empty',
|
// // that does not make sense for the client
|
||||||
fs: 'empty',
|
// dgram: 'empty',
|
||||||
net: 'empty',
|
// fs: 'empty',
|
||||||
tls: 'empty',
|
// net: 'empty',
|
||||||
child_process: 'empty',
|
// tls: 'empty',
|
||||||
},
|
// child_process: 'empty',
|
||||||
|
// },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,93 +1,99 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const utils = require('./utils')
|
const utils = require('./utils');
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack');
|
||||||
const config = require('../config')
|
const config = require('../config');
|
||||||
const merge = require('webpack-merge')
|
const path = require('path');
|
||||||
const path = require('path')
|
const baseWebpackConfig = require('./webpack.base.conf');
|
||||||
const baseWebpackConfig = require('./webpack.base.conf')
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
const portfinder = require('portfinder');
|
||||||
const portfinder = require('portfinder')
|
const {merge} = require('webpack-merge');
|
||||||
|
|
||||||
const HOST = process.env.HOST
|
const HOST = process.env.HOST;
|
||||||
const PORT = process.env.PORT && Number(process.env.PORT)
|
const PORT = process.env.PORT && Number(process.env.PORT);
|
||||||
|
|
||||||
const devWebpackConfig = merge(baseWebpackConfig, {
|
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
// cheap-module-eval-source-map is faster for development
|
// cheap-module-eval-source-map is faster for development
|
||||||
devtool: config.dev.devtool,
|
devtool: config.dev.devtool,
|
||||||
|
mode: 'development',
|
||||||
// these devServer options should be customized in /config/index.js
|
// these devServer options should be customized in /config/index.js
|
||||||
devServer: {
|
devServer: {
|
||||||
clientLogLevel: 'warning',
|
client: {
|
||||||
|
logging: 'warn',
|
||||||
|
overlay: config.dev.errorOverlay ? {errors: true, warnings: false} : false,
|
||||||
|
progress: true,
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
rewrites: [
|
rewrites: [
|
||||||
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
|
{from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html')},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
hot: true,
|
hot: true,
|
||||||
contentBase: false, // since we use CopyWebpackPlugin.
|
|
||||||
compress: true,
|
compress: true,
|
||||||
host: HOST || config.dev.host,
|
host: HOST || config.dev.host,
|
||||||
port: PORT || config.dev.port,
|
port: PORT || config.dev.port,
|
||||||
open: config.dev.autoOpenBrowser,
|
open: config.dev.autoOpenBrowser,
|
||||||
overlay: config.dev.errorOverlay
|
// publicPath: config.dev.assetsPublicPath,
|
||||||
? { warnings: false, errors: true }
|
|
||||||
: false,
|
|
||||||
publicPath: config.dev.assetsPublicPath,
|
|
||||||
proxy: config.dev.proxyTable,
|
proxy: config.dev.proxyTable,
|
||||||
quiet: true, // necessary for FriendlyErrorsPlugin
|
// quiet: true, // necessary for FriendlyErrorsPlugin
|
||||||
watchOptions: {
|
|
||||||
poll: config.dev.poll,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': require('../config/dev.env')
|
'process.env': require('../config/dev.env'),
|
||||||
|
// bundler feature flags https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
|
||||||
|
__VUE_OPTIONS_API__: true, // default, but explicit
|
||||||
|
__VUE_PROD_DEVTOOLS__: false, // default, but explicit
|
||||||
}),
|
}),
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
|
||||||
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
|
||||||
new webpack.NoEmitOnErrorsPlugin(),
|
|
||||||
// https://github.com/ampedandwired/html-webpack-plugin
|
// https://github.com/ampedandwired/html-webpack-plugin
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: 'index.html',
|
template: 'index.html',
|
||||||
inject: true,
|
...require('../config/dev.env'),
|
||||||
...require('../config/dev.env')
|
|
||||||
}),
|
}),
|
||||||
// copy custom static assets
|
// copy custom static assets
|
||||||
new CopyWebpackPlugin([
|
new CopyPlugin({
|
||||||
|
patterns: [
|
||||||
{
|
{
|
||||||
from: path.resolve(__dirname, '../static'),
|
from: path.resolve(__dirname, '../static'),
|
||||||
to: config.dev.assetsSubDirectory,
|
to: config.dev.assetsSubDirectory,
|
||||||
ignore: ['.*']
|
globOptions: {
|
||||||
}
|
ignore: ['.*'],
|
||||||
])
|
},
|
||||||
]
|
},
|
||||||
})
|
],
|
||||||
|
}),
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: 'disabled' // do nothing by default, but be able to generate stats with --profile
|
||||||
|
})
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = new Promise((resolve, reject) => {
|
module.exports = new Promise((resolve, reject) => {
|
||||||
portfinder.basePort = process.env.PORT || config.dev.port
|
portfinder.basePort = process.env.PORT || config.dev.port;
|
||||||
portfinder.getPort((err, port) => {
|
portfinder.getPort((err, port) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err)
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
// publish the new Port, necessary for e2e tests
|
// publish the new Port, necessary for e2e tests
|
||||||
process.env.PORT = port
|
process.env.PORT = port;
|
||||||
// add port to devServer config
|
// add port to devServer config
|
||||||
devWebpackConfig.devServer.port = port
|
devWebpackConfig.devServer.port = port;
|
||||||
|
|
||||||
// Add FriendlyErrorsPlugin
|
// Add FriendlyErrorsPlugin
|
||||||
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
// todo: seems to not be maintained anymore, disable for now
|
||||||
compilationSuccessInfo: {
|
// devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||||
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
// compilationSuccessInfo: {
|
||||||
},
|
// messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||||
onErrors: config.dev.notifyOnErrors
|
// },
|
||||||
? utils.createNotifierCallback()
|
// onErrors: config.dev.notifyOnErrors
|
||||||
: undefined
|
// ? utils.createNotifierCallback()
|
||||||
}))
|
// : undefined,
|
||||||
|
// }));
|
||||||
|
|
||||||
resolve(devWebpackConfig)
|
resolve(devWebpackConfig);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,43 @@
|
||||||
'use strict'
|
'use strict';
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const utils = require('./utils')
|
const utils = require('./utils');
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack');
|
||||||
const config = require('../config')
|
const config = require('../config');
|
||||||
const merge = require('webpack-merge')
|
const {merge} = require('webpack-merge');
|
||||||
const baseWebpackConfig = require('./webpack.base.conf')
|
const baseWebpackConfig = require('./webpack.base.conf');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
|
||||||
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
|
||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
|
||||||
|
|
||||||
const env = require('../config/prod.env')
|
const env = require('../config/prod.env');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
|
||||||
const webpackConfig = merge(baseWebpackConfig, {
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||||
|
mode: 'production',
|
||||||
output: {
|
output: {
|
||||||
path: config.build.assetsRoot,
|
path: config.build.assetsRoot,
|
||||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': env
|
'process.env': env,
|
||||||
}),
|
// bundler feature flags https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
|
||||||
new UglifyJsPlugin({
|
__VUE_OPTIONS_API__: true, // default, but explicit
|
||||||
uglifyOptions: {
|
__VUE_PROD_DEVTOOLS__: false, // default, but explicit
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sourceMap: config.build.productionSourceMap,
|
|
||||||
parallel: true
|
|
||||||
}),
|
}),
|
||||||
// extract css into its own file
|
// extract css into its own file
|
||||||
new ExtractTextPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||||
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
|
||||||
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
|
||||||
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
|
|
||||||
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
|
||||||
allChunks: true,
|
|
||||||
}),
|
}),
|
||||||
// Compress extracted CSS. We are using this plugin so that possible
|
// Compress extracted CSS. We are using this plugin so that possible
|
||||||
// duplicated CSS from different components can be deduped.
|
// duplicated CSS from different components can be deduped.
|
||||||
new OptimizeCSSPlugin({
|
new OptimizeCSSPlugin({
|
||||||
cssProcessorOptions: config.build.productionSourceMap
|
cssProcessorOptions: config.build.productionSourceMap
|
||||||
? { safe: true, map: { inline: false } }
|
? {safe: true, map: {inline: false}}
|
||||||
: { safe: true }
|
: {safe: true},
|
||||||
}),
|
}),
|
||||||
// generate dist index.html with correct asset hash for caching.
|
// generate dist index.html with correct asset hash for caching.
|
||||||
// you can customize output by editing /index.html
|
// you can customize output by editing /index.html
|
||||||
|
|
@ -56,65 +45,70 @@ const webpackConfig = merge(baseWebpackConfig, {
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: config.build.index,
|
filename: config.build.index,
|
||||||
template: 'index.html',
|
template: 'index.html',
|
||||||
inject: true,
|
|
||||||
...require('../config/prod.env'),
|
...require('../config/prod.env'),
|
||||||
minify: {
|
minify: { // defaults from https://github.com/jantimon/html-webpack-plugin#minification
|
||||||
removeComments: true,
|
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
removeAttributeQuotes: true
|
keepClosingSlash: true,
|
||||||
// more options:
|
removeComments: true,
|
||||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
removeRedundantAttributes: true,
|
||||||
|
removeScriptTypeAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
useShortDoctype: true,
|
||||||
},
|
},
|
||||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||||
chunksSortMode: 'dependency'
|
chunksSortMode: 'auto',
|
||||||
}),
|
}),
|
||||||
// keep module.id stable when vendor modules does not change
|
// keep module.id stable when vendor modules does not change
|
||||||
new webpack.HashedModuleIdsPlugin(),
|
new webpack.ids.HashedModuleIdsPlugin(),
|
||||||
// enable scope hoisting
|
|
||||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
|
||||||
// split vendor js into its own file
|
// split vendor js into its own file
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
// todo: https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693
|
||||||
name: 'vendor',
|
// todo: do we need this? probably default is fine
|
||||||
minChunks (module) {
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
// any required modules inside node_modules are extracted to vendor
|
// name: 'vendor',
|
||||||
return (
|
// minChunks (module) {
|
||||||
module.resource &&
|
// // any required modules inside node_modules are extracted to vendor
|
||||||
/\.js$/.test(module.resource) &&
|
// return (
|
||||||
module.resource.indexOf(
|
// module.resource &&
|
||||||
path.join(__dirname, '../node_modules')
|
// /\.js$/.test(module.resource) &&
|
||||||
) === 0
|
// module.resource.indexOf(
|
||||||
)
|
// path.join(__dirname, '../node_modules')
|
||||||
}
|
// ) === 0
|
||||||
}),
|
// )
|
||||||
|
// }
|
||||||
|
// }),
|
||||||
// extract webpack runtime and module manifest to its own file in order to
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
// prevent vendor hash from being updated whenever app bundle is updated
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'manifest',
|
// name: 'manifest',
|
||||||
minChunks: Infinity
|
// minChunks: Infinity
|
||||||
}),
|
// }),
|
||||||
// This instance extracts shared chunks from code splitted chunks and bundles them
|
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||||
// in a separate chunk, similar to the vendor chunk
|
// in a separate chunk, similar to the vendor chunk
|
||||||
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
// new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'app',
|
// name: 'app',
|
||||||
async: 'vendor-async',
|
// async: 'vendor-async',
|
||||||
children: true,
|
// children: true,
|
||||||
minChunks: 3
|
// minChunks: 3
|
||||||
}),
|
// }),
|
||||||
|
|
||||||
// copy custom static assets
|
// copy custom static assets
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
{
|
{
|
||||||
from: path.resolve(__dirname, '../static'),
|
from: path.resolve(__dirname, '../static'),
|
||||||
to: config.build.assetsSubDirectory,
|
to: config.build.assetsSubDirectory,
|
||||||
ignore: ['.*']
|
globOptions: {
|
||||||
}
|
ignore: ['.*'],
|
||||||
])
|
},
|
||||||
]
|
},
|
||||||
})
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
if (config.build.productionGzip) {
|
if (config.build.productionGzip) {
|
||||||
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
const CompressionWebpackPlugin = require('compression-webpack-plugin');
|
||||||
|
|
||||||
webpackConfig.plugins.push(
|
webpackConfig.plugins.push(
|
||||||
new CompressionWebpackPlugin({
|
new CompressionWebpackPlugin({
|
||||||
|
|
@ -123,17 +117,17 @@ if (config.build.productionGzip) {
|
||||||
test: new RegExp(
|
test: new RegExp(
|
||||||
'\\.(' +
|
'\\.(' +
|
||||||
config.build.productionGzipExtensions.join('|') +
|
config.build.productionGzipExtensions.join('|') +
|
||||||
')$'
|
')$',
|
||||||
),
|
),
|
||||||
threshold: 10240,
|
threshold: 10240,
|
||||||
minRatio: 0.8
|
minRatio: 0.8,
|
||||||
})
|
}),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.build.bundleAnalyzerReport) {
|
if (config.build.bundleAnalyzerReport) {
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = webpackConfig
|
module.exports = webpackConfig;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
const merge = require('webpack-merge')
|
const {merge} = require('webpack-merge')
|
||||||
const prodEnv = require('./prod.env')
|
const prodEnv = require('./prod.env')
|
||||||
|
|
||||||
module.exports = merge(prodEnv, {
|
module.exports = merge(prodEnv, {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// https://webpack.js.org/configuration/devtool/#development
|
// https://webpack.js.org/configuration/devtool/#development
|
||||||
devtool: 'cheap-module-eval-source-map',
|
// devtool: 'cheap-module-eval-source-map',
|
||||||
|
devtool: 'eval-cheap-module-source-map',
|
||||||
|
|
||||||
// If you have problems debugging vue-files in devtools,
|
// If you have problems debugging vue-files in devtools,
|
||||||
// set this to false - it *may* help
|
// set this to false - it *may* help
|
||||||
|
|
@ -57,7 +58,7 @@ module.exports = {
|
||||||
|
|
||||||
productionSourceMap: true,
|
productionSourceMap: true,
|
||||||
// https://webpack.js.org/configuration/devtool/#production
|
// https://webpack.js.org/configuration/devtool/#production
|
||||||
devtool: '#source-map',
|
devtool: 'source-map',
|
||||||
|
|
||||||
// Gzip off by default as many popular static hosts such as
|
// Gzip off by default as many popular static hosts such as
|
||||||
// Surge or Netlify already gzip all static assets for you.
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
|
|
|
||||||
|
|
@ -24,19 +24,11 @@
|
||||||
"slug": "geld-und-kauf",
|
"slug": "geld-und-kauf",
|
||||||
"__typename": "TopicNode"
|
"__typename": "TopicNode"
|
||||||
},
|
},
|
||||||
"schoolClasses": {
|
"schoolClasses": [{
|
||||||
"edges": [
|
|
||||||
{
|
|
||||||
"node": {
|
|
||||||
"id": "U2Nob29sQ2xhc3NOb2RlOjE=",
|
"id": "U2Nob29sQ2xhc3NOb2RlOjE=",
|
||||||
"name": "FLID2018a",
|
"name": "FLID2018a",
|
||||||
"__typename": "SchoolClassNode"
|
"__typename": "SchoolClassNode"
|
||||||
},
|
}],
|
||||||
"__typename": "SchoolClassNodeEdge"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"__typename": "SchoolClassNodeConnection"
|
|
||||||
},
|
|
||||||
"__typename": "UserNode",
|
"__typename": "UserNode",
|
||||||
"onboardingVisited": true,
|
"onboardingVisited": true,
|
||||||
"permissions": []
|
"permissions": []
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
export const SELECTED_CLASS_ID = 987;
|
||||||
|
export const SELECTED_CLASS_ID_ENCODED = btoa(`SchoolClassNode:${SELECTED_CLASS_ID}`);
|
||||||
const selectedClass = {
|
const selectedClass = {
|
||||||
id: btoa('SchoolClassNode:selectedClassId'),
|
id: SELECTED_CLASS_ID_ENCODED,
|
||||||
name: 'Moordale',
|
name: 'Moordale',
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
code: 'XXXX',
|
code: 'XXXX',
|
||||||
|
|
@ -42,7 +44,7 @@ export default {
|
||||||
id: getChapterId(),
|
id: getChapterId(),
|
||||||
title: 'chapter-title',
|
title: 'chapter-title',
|
||||||
description: 'chapter-description',
|
description: 'chapter-description',
|
||||||
|
bookmark: null
|
||||||
}),
|
}),
|
||||||
ContentBlockNode: () => ({
|
ContentBlockNode: () => ({
|
||||||
contents: [],
|
contents: [],
|
||||||
|
|
@ -62,11 +64,7 @@ export default {
|
||||||
readOnly: false,
|
readOnly: false,
|
||||||
onboardingVisited: true,
|
onboardingVisited: true,
|
||||||
selectedClass,
|
selectedClass,
|
||||||
schoolClasses: {
|
schoolClasses: [selectedClass],
|
||||||
edges: [
|
|
||||||
{node: selectedClass},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
recentModules: {
|
recentModules: {
|
||||||
edges: [],
|
edges: [],
|
||||||
},
|
},
|
||||||
|
|
@ -84,19 +82,18 @@ export default {
|
||||||
}),
|
}),
|
||||||
ModuleNode: () => ({
|
ModuleNode: () => ({
|
||||||
title: 'Module Title',
|
title: 'Module Title',
|
||||||
slug: 'some slug',
|
slug: 'some-slug',
|
||||||
metaTitle: 'Meta Title',
|
metaTitle: 'Meta Title',
|
||||||
heroImage: '',
|
heroImage: '',
|
||||||
teaser: '',
|
teaser: '',
|
||||||
intro: '',
|
intro: '',
|
||||||
assignments: {nodes: []},
|
assignments: [],
|
||||||
objectiveGroups: [],
|
objectiveGroups: [],
|
||||||
id: getModuleId(),
|
id: getModuleId(),
|
||||||
|
bookmark: null
|
||||||
}),
|
}),
|
||||||
TopicNode: () => ({
|
TopicNode: () => ({
|
||||||
modules: {
|
modules: [],
|
||||||
edges: [],
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
RoomNode: () => ({
|
RoomNode: () => ({
|
||||||
title: 'A Room',
|
title: 'A Room',
|
||||||
|
|
@ -104,7 +101,7 @@ export default {
|
||||||
appearance: 'blue',
|
appearance: 'blue',
|
||||||
description: 'A Room description',
|
description: 'A Room description',
|
||||||
schoolClass: {
|
schoolClass: {
|
||||||
id: 'selectedClassId',
|
id: SELECTED_CLASS_ID_ENCODED,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
RoomEntryNode: () => ({
|
RoomEntryNode: () => ({
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ export default {
|
||||||
heroImage: 'heroImage',
|
heroImage: 'heroImage',
|
||||||
teaser: 'A Module Mock Teaser',
|
teaser: 'A Module Mock Teaser',
|
||||||
intro: 'intro',
|
intro: 'intro',
|
||||||
assignments: {},
|
assignments: [],
|
||||||
objectiveGroups: [],
|
objectiveGroups: [],
|
||||||
id: '',
|
id: 'TW9kdWxlTm9kZToxMjM=',
|
||||||
chapters: [],
|
chapters: [],
|
||||||
topic: {
|
topic: {
|
||||||
title: 'A Topic Mock Title',
|
title: 'A Topic Mock Title',
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
describe('Bookmarks', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
// todo: mock all the graphql queries and mutations
|
|
||||||
cy.exec('python ../server/manage.py prepare_bookmarks_for_cypress');
|
|
||||||
|
|
||||||
cy.viewport('macbook-15');
|
|
||||||
cy.apolloLogin('rachel.green', 'test');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should bookmark content block', () => {
|
|
||||||
cy.visit('/module/lohn-und-budget/');
|
|
||||||
|
|
||||||
cy.get('.content-component').contains('Das folgende Interview').parent().parent().as('interviewContent');
|
|
||||||
|
|
||||||
cy.get('@interviewContent').within(() => {
|
|
||||||
cy.get('.bookmark-actions__bookmark').click();
|
|
||||||
cy.get('.bookmark-actions__add-note').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('[data-cy=bookmark-note]').within(() => {
|
|
||||||
cy.get('.skillbox-input').type('Hallo Velo');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('[data-cy=modal-save-button]').click();
|
|
||||||
|
|
||||||
cy.get('@interviewContent').within(() => {
|
|
||||||
cy.get('.bookmark-actions__edit-note').click();
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('[data-cy=bookmark-note]').within(() => {
|
|
||||||
cy.get('.skillbox-input').clear().type('Hello Bike');
|
|
||||||
});
|
|
||||||
|
|
||||||
cy.get('[data-cy=modal-save-button]').click();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -40,7 +40,7 @@ describe('Email Verification', () => {
|
||||||
|
|
||||||
cy.visit('/license-activation');
|
cy.visit('/license-activation');
|
||||||
redeemCoupon('');
|
redeemCoupon('');
|
||||||
cy.get('[data-cy="coupon-local-errors"]').contains('Coupon ist ein Pflichtfeld');
|
cy.get('[data-cy="coupon-local-errors"]').contains('Coupon-Code ist ein Pflichtfeld');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays error if coupon input is wrong', () => {
|
it('displays error if coupon input is wrong', () => {
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ describe('Apply module visibility', () => {
|
||||||
const {me: minimalMe} = getMinimalMe({});
|
const {me: minimalMe} = getMinimalMe({});
|
||||||
const me = {
|
const me = {
|
||||||
...minimalMe,
|
...minimalMe,
|
||||||
schoolClasses: {
|
schoolClasses
|
||||||
edges: schoolClasses.map(scn => ({node: scn}))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// name: '[\'FLID2018a\', \'Andere Klasse\']'
|
// name: '[\'FLID2018a\', \'Andere Klasse\']'
|
||||||
const operations = {
|
const operations = {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
import {getMinimalMe} from '../../support/helpers';
|
||||||
|
import minimalModule from '../../fixtures/module.minimal';
|
||||||
|
|
||||||
|
const {me: minimalMe} = getMinimalMe({});
|
||||||
|
|
||||||
|
|
||||||
|
describe('Bookmarks', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.setup();
|
||||||
|
cy.mockGraphqlOps({
|
||||||
|
operations: {
|
||||||
|
MeQuery: {
|
||||||
|
me: minimalMe
|
||||||
|
},
|
||||||
|
ModuleDetailsQuery: {
|
||||||
|
module: {
|
||||||
|
...minimalModule,
|
||||||
|
slug: 'my-module-slug',
|
||||||
|
chapters: [
|
||||||
|
{
|
||||||
|
title: 'My super Chapter',
|
||||||
|
contentBlocks: [
|
||||||
|
{
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
type: 'text_block',
|
||||||
|
value: {
|
||||||
|
text: 'Das folgende Interview'
|
||||||
|
},
|
||||||
|
id: "df8212ee-3e82-49fa-977e-c4b60789163e"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateLastModule: {},
|
||||||
|
UpdateContentBookmark: {
|
||||||
|
updateContentBookmark: {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateModuleBookmark: {
|
||||||
|
updateModuleBookmark: {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpdateChapterBookmark: {
|
||||||
|
updateChapterBookmark: {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AddNote: ({input: {note}}) => ({
|
||||||
|
addNote: {
|
||||||
|
note
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
UpdateNote: ({input: {note}}) => ({
|
||||||
|
updateNote: {
|
||||||
|
note
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bookmark instrument', () => {
|
||||||
|
cy.visit();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bookmark module', () => {
|
||||||
|
cy.visit('/module/lohn-und-budget/');
|
||||||
|
cy.getByDataCy('module-bookmark-actions').as('moduleBookmark');
|
||||||
|
|
||||||
|
cy.get('@moduleBookmark').within(() => {
|
||||||
|
cy.getByDataCy('bookmark-action').click();
|
||||||
|
cy.getByDataCy('add-note-action').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').type('Hallo Velo');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
|
||||||
|
cy.get('@moduleBookmark').within(() => {
|
||||||
|
cy.getByDataCy('edit-note-action').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').clear().type('Hello Bike');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bookmark chapter', () => {
|
||||||
|
cy.visit('/module/lohn-und-budget/');
|
||||||
|
|
||||||
|
cy.getByDataCy('chapter-bookmark-actions').as('chapterBookmark');
|
||||||
|
|
||||||
|
cy.get('@chapterBookmark').within(() => {
|
||||||
|
cy.getByDataCy('bookmark-action').click();
|
||||||
|
cy.getByDataCy('add-note-action').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').type('Hallo Velo');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
|
||||||
|
cy.get('@chapterBookmark').within(() => {
|
||||||
|
cy.getByDataCy('edit-note-action').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').clear().type('Hello Bike');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should bookmark content block', () => {
|
||||||
|
cy.visit('/module/lohn-und-budget/');
|
||||||
|
|
||||||
|
cy.getByDataCy('content-component').contains('Das folgende Interview').parent().parent().as('interviewContent');
|
||||||
|
|
||||||
|
cy.get('@interviewContent').within(() => {
|
||||||
|
cy.get('.bookmark-actions__bookmark').click();
|
||||||
|
cy.get('.bookmark-actions__add-note').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').type('Hallo Velo');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
|
||||||
|
cy.get('@interviewContent').within(() => {
|
||||||
|
cy.get('.bookmark-actions__edit-note').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=bookmark-note]').within(() => {
|
||||||
|
cy.get('.skillbox-input').clear().type('Hello Bike');
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('[data-cy=modal-save-button]').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
describe('Create Content Block', () => {
|
||||||
|
it('visits the page', () => {
|
||||||
|
// todo:
|
||||||
|
// add mocks
|
||||||
|
// cy.visit('/module/some-module/add/bliblablub');
|
||||||
|
// add title
|
||||||
|
// add text element
|
||||||
|
// add list item
|
||||||
|
// add text element to list item
|
||||||
|
// add second list item
|
||||||
|
// add text element to second list item
|
||||||
|
// add another text element to second list item
|
||||||
|
// save
|
||||||
|
|
||||||
|
// another test
|
||||||
|
// go to pase
|
||||||
|
// click cancel, go back
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// todo: another test
|
||||||
|
// edit existing content block
|
||||||
|
|
@ -28,7 +28,7 @@ describe('New student', () => {
|
||||||
return {
|
return {
|
||||||
...me,
|
...me,
|
||||||
onboardingVisited,
|
onboardingVisited,
|
||||||
schoolClasses: {edges: schoolClasses},
|
schoolClasses,
|
||||||
selectedClass: getSelectedClass(),
|
selectedClass: getSelectedClass(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,8 @@ describe('Objective Visibility', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the correct objectives', () => {
|
//todo: finish writing this test, this does nothing
|
||||||
|
it.skip('should display the correct objectives', () => {
|
||||||
cy.fakeLogin('rachel.green', 'test');
|
cy.fakeLogin('rachel.green', 'test');
|
||||||
|
|
||||||
cy.visit('/module/lohn-und-budget');
|
cy.visit('/module/lohn-und-budget');
|
||||||
|
|
|
||||||
|
|
@ -95,12 +95,10 @@ describe('Project Page', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.setup();
|
cy.setup();
|
||||||
|
|
||||||
cy.task('getSchema').then(schema => {
|
|
||||||
cy.mockGraphqlOps({
|
cy.mockGraphqlOps({
|
||||||
operations,
|
operations,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('has the correct layout', () => {
|
it('has the correct layout', () => {
|
||||||
cy.visit('/portfolio/groot');
|
cy.visit('/portfolio/groot');
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ const getOperations = ({final, readOnly, classReadOnly = false}) => ({
|
||||||
ModuleDetailsQuery: {
|
ModuleDetailsQuery: {
|
||||||
module,
|
module,
|
||||||
},
|
},
|
||||||
|
UpdateLastModule: {},
|
||||||
AssignmentQuery: {
|
AssignmentQuery: {
|
||||||
assignment: {
|
assignment: {
|
||||||
submission: {
|
submission: {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const getOperations = ({readOnly, classReadOnly = false}) => ({
|
||||||
...minimalModule,
|
...minimalModule,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdateLastModule: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleNavigationTest = ({readOnly, classReadOnly = false, displayMenu}) => {
|
const moduleNavigationTest = ({readOnly, classReadOnly = false, displayMenu}) => {
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ import {getMinimalMe} from '../../../support/helpers';
|
||||||
const getOperations = ({readOnly}) => ({
|
const getOperations = ({readOnly}) => ({
|
||||||
MeQuery: getMinimalMe({readOnly}),
|
MeQuery: getMinimalMe({readOnly}),
|
||||||
NewsTeasers: {
|
NewsTeasers: {
|
||||||
newsTeasers: {
|
newsTeasers: [
|
||||||
edges: [
|
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Read Only News', () => {
|
describe('Read Only News', () => {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ const getOperations = ({readOnly = false, classReadOnly = false}) => ({
|
||||||
ProjectQuery: {
|
ProjectQuery: {
|
||||||
project: {
|
project: {
|
||||||
id: 'projectId',
|
id: 'projectId',
|
||||||
|
slug: 'project-name',
|
||||||
final: false,
|
final: false,
|
||||||
student: {
|
student: {
|
||||||
id: btoa('PrivateUserNode:1'),
|
id: btoa('PrivateUserNode:1'),
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,7 @@ describe('Room Team Management - Read only', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RoomsQuery: {
|
RoomsQuery: {
|
||||||
rooms: {
|
rooms: [{
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: '',
|
id: '',
|
||||||
slug: '',
|
slug: '',
|
||||||
title: 'some room',
|
title: 'some room',
|
||||||
|
|
@ -27,10 +24,7 @@ describe('Room Team Management - Read only', () => {
|
||||||
id: SELECTED_CLASS_ID,
|
id: SELECTED_CLASS_ID,
|
||||||
name: 'bla',
|
name: 'bla',
|
||||||
},
|
},
|
||||||
},
|
}],
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@ describe('Article page', () => {
|
||||||
slug,
|
slug,
|
||||||
id: 'room-entry-id',
|
id: 'room-entry-id',
|
||||||
title: 'Some Room Entry, yay!',
|
title: 'Some Room Entry, yay!',
|
||||||
comments: {
|
comments: [],
|
||||||
edges: [],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const operations = {
|
const operations = {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,8 @@ describe('The Room Page', () => {
|
||||||
cy.getByDataCy('room-actions').should('not.exist');
|
cy.getByDataCy('room-actions').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes visibility of a room', () => {
|
// todo: re-enable once cypress can do it correctly
|
||||||
|
it.skip('changes visibility of a room', () => {
|
||||||
const MeQuery = getMinimalMe({
|
const MeQuery = getMinimalMe({
|
||||||
isTeacher: true,
|
isTeacher: true,
|
||||||
});
|
});
|
||||||
|
|
@ -155,9 +156,7 @@ describe('The Room Page', () => {
|
||||||
MeQuery,
|
MeQuery,
|
||||||
RoomsQuery() {
|
RoomsQuery() {
|
||||||
return {
|
return {
|
||||||
rooms: {
|
rooms
|
||||||
edges: rooms.map(room => ({node: room})),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
RoomEntriesQuery: {
|
RoomEntriesQuery: {
|
||||||
|
|
@ -244,23 +243,18 @@ describe('The Room Page', () => {
|
||||||
cy.getByDataCy('add-room-entry-modal').should('exist');
|
cy.getByDataCy('add-room-entry-modal').should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('changes class while on room page', () => {
|
it.only('changes class while on room page', () => {
|
||||||
const {me} = MeQuery;
|
const {me} = MeQuery;
|
||||||
|
const otherClass = {
|
||||||
|
id: btoa('SchoolClassNode:34'),
|
||||||
|
name: 'Other Class',
|
||||||
|
readOnly: false
|
||||||
|
};
|
||||||
const operations = {
|
const operations = {
|
||||||
MeQuery: {
|
MeQuery: {
|
||||||
me: {
|
me: {
|
||||||
...me,
|
...me,
|
||||||
schoolClasses: {
|
schoolClasses: [...me.schoolClasses, otherClass],
|
||||||
edges: [
|
|
||||||
...me.schoolClasses.edges,
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
id: btoa('SchoolClassNode:other-class'),
|
|
||||||
name: 'Other Class'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RoomEntriesQuery,
|
RoomEntriesQuery,
|
||||||
|
|
@ -268,6 +262,15 @@ describe('The Room Page', () => {
|
||||||
updateSettings: {
|
updateSettings: {
|
||||||
success: true
|
success: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ModuleDetailsQuery: {
|
||||||
|
me: {
|
||||||
|
selectedClass: otherClass
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MySchoolClassQuery: {},
|
||||||
|
RoomsQuery: {
|
||||||
|
rooms: []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -278,5 +281,6 @@ describe('The Room Page', () => {
|
||||||
cy.getByDataCy('room-title').should('contain', 'A Room');
|
cy.getByDataCy('room-title').should('contain', 'A Room');
|
||||||
cy.selectClass('Other Class');
|
cy.selectClass('Other Class');
|
||||||
cy.url().should('include', 'rooms');
|
cy.url().should('include', 'rooms');
|
||||||
|
cy.getByDataCy('selected-class-name').should('contain', 'Other Class');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
import {getMinimalMe} from '../../../support/helpers';
|
import {getMinimalMe} from '../../../support/helpers';
|
||||||
|
import {SELECTED_CLASS_ID_ENCODED} from '../../../fixtures/mocks';
|
||||||
|
|
||||||
describe('The Rooms Page', () => {
|
describe('The Rooms Page', () => {
|
||||||
const getOperations = (isTeacher) => ({
|
const getOperations = (isTeacher) => ({
|
||||||
MeQuery: getMinimalMe({isTeacher}),
|
MeQuery: getMinimalMe({isTeacher}),
|
||||||
RoomsQuery: {
|
RoomsQuery: {
|
||||||
rooms: {
|
rooms: [{
|
||||||
edges: [
|
|
||||||
{
|
|
||||||
node: {
|
|
||||||
schoolClass: {
|
schoolClass: {
|
||||||
id: btoa('SchoolClassNode:selectedClassId'),
|
id: SELECTED_CLASS_ID_ENCODED,
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
}],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -23,9 +18,7 @@ describe('The Rooms Page', () => {
|
||||||
return {
|
return {
|
||||||
...operations,
|
...operations,
|
||||||
RoomsQuery: {
|
RoomsQuery: {
|
||||||
rooms: {
|
rooms: [],
|
||||||
edges: [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -105,9 +98,7 @@ describe('The Rooms Page', () => {
|
||||||
MeQuery,
|
MeQuery,
|
||||||
RoomsQuery() {
|
RoomsQuery() {
|
||||||
return {
|
return {
|
||||||
rooms: {
|
rooms
|
||||||
edges: rooms.map(room => ({node: room})),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
AddRoom({input: {room: {title, appearance, description}}}) {
|
AddRoom({input: {room: {title, appearance, description}}}) {
|
||||||
|
|
|
||||||
|
|
@ -254,17 +254,13 @@ describe('Teacher Class Management', () => {
|
||||||
let selectedClass = teacher.selectedClass;
|
let selectedClass = teacher.selectedClass;
|
||||||
|
|
||||||
const schoolClasses = [
|
const schoolClasses = [
|
||||||
{
|
teacher.selectedClass
|
||||||
node: teacher.selectedClass
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const me = () => ({
|
const me = () => ({
|
||||||
...teacher,
|
...teacher,
|
||||||
selectedClass,
|
selectedClass,
|
||||||
schoolClasses: {
|
schoolClasses
|
||||||
edges: schoolClasses
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.mockGraphqlOps({
|
cy.mockGraphqlOps({
|
||||||
|
|
@ -278,9 +274,7 @@ describe('Teacher Class Management', () => {
|
||||||
name,
|
name,
|
||||||
readOnly: false
|
readOnly: false
|
||||||
};
|
};
|
||||||
schoolClasses.push({
|
schoolClasses.push(schoolClass);
|
||||||
node: schoolClass
|
|
||||||
});
|
|
||||||
selectedClass = schoolClass;
|
selectedClass = schoolClass;
|
||||||
return {
|
return {
|
||||||
createSchoolClass: {
|
createSchoolClass: {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,7 @@ describe('Sidebar', () => {
|
||||||
MeQuery: {
|
MeQuery: {
|
||||||
me: {
|
me: {
|
||||||
...me,
|
...me,
|
||||||
schoolClasses: {
|
schoolClasses: [...me.schoolClasses, {}],
|
||||||
edges: [
|
|
||||||
...me.schoolClasses.edges,
|
|
||||||
{node: {}},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ProjectsQuery: {
|
ProjectsQuery: {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ describe('Snapshot', () => {
|
||||||
success: true,
|
success: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
UpdateLastModule: {},
|
||||||
ModuleSnapshotsQuery: {
|
ModuleSnapshotsQuery: {
|
||||||
module: {
|
module: {
|
||||||
...module,
|
...module,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
export const getMinimalMe = ({readOnly = false, classReadOnly = false, isTeacher = true} = {}) => {
|
export const getMinimalMe = ({readOnly = false, classReadOnly = false, isTeacher = true} = {}) => {
|
||||||
const selectedClass = {
|
const selectedClass = {
|
||||||
name: 'Selected Class',
|
name: 'Selected Class',
|
||||||
id: btoa('SchoolClassNode:selectedClassId'),
|
id: btoa('SchoolClassNode:987'),
|
||||||
readOnly: classReadOnly,
|
readOnly: classReadOnly,
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
|
|
@ -12,11 +12,7 @@ export const getMinimalMe = ({readOnly = false, classReadOnly = false, isTeacher
|
||||||
readOnly,
|
readOnly,
|
||||||
isTeacher,
|
isTeacher,
|
||||||
selectedClass,
|
selectedClass,
|
||||||
schoolClasses: {
|
schoolClasses: [selectedClass],
|
||||||
edges: [
|
|
||||||
{node: selectedClass},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -69,13 +65,7 @@ export const getMe = ({schoolClasses, teacher}) => {
|
||||||
'slug': 'geld-und-kauf',
|
'slug': 'geld-und-kauf',
|
||||||
'__typename': 'TopicNode',
|
'__typename': 'TopicNode',
|
||||||
},
|
},
|
||||||
'schoolClasses': {
|
'schoolClasses': schoolClassNodes,
|
||||||
'edges': schoolClassNodes.map(scn => ({
|
|
||||||
node: scn,
|
|
||||||
'__typename': 'SchoolClassNodeEdge',
|
|
||||||
})),
|
|
||||||
'__typename': 'SchoolClassNodeConnection',
|
|
||||||
},
|
|
||||||
'__typename': 'UserNode',
|
'__typename': 'UserNode',
|
||||||
'onboardingVisited': true,
|
'onboardingVisited': true,
|
||||||
'permissions': teacher ? ['users.can_manage_school_class_content'] : [],
|
'permissions': teacher ? ['users.can_manage_school_class_content'] : [],
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,10 +5,11 @@
|
||||||
"author": "ramon / chrigu",
|
"author": "ramon / chrigu",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
"dev": "webpack serve --progress --config build/webpack.dev.conf.js",
|
||||||
|
"analyze": "webpack --profile --json --config build/webpack.dev.conf.js > dist/stats.json && webpack-bundle-analyzer dist/stats.json",
|
||||||
"start": ". ../server/.env && npm run dev",
|
"start": ". ../server/.env && npm run dev",
|
||||||
"lint": "eslint --ext .js,.vue src",
|
"lint": "eslint --ext .js,.vue,.ts src",
|
||||||
"fix-lint": "eslint --ext .js,.vue --fix src",
|
"fix-lint": "eslint --ext .js,.vue,.ts --fix src",
|
||||||
"build": "node build/build.js",
|
"build": "node build/build.js",
|
||||||
"open:cypress:e2e": "npm run cypress:e2e:open",
|
"open:cypress:e2e": "npm run cypress:e2e:open",
|
||||||
"open:cypress:frontend": "npm run cypress:frontend:open",
|
"open:cypress:frontend": "npm run cypress:frontend:open",
|
||||||
|
|
@ -24,52 +25,48 @@
|
||||||
"cypress:parallel:run": "cy2 run --parallel --record --config-file cypress.frontend.json --ci-build-id "
|
"cypress:parallel:run": "cy2 run --parallel --record --config-file cypress.frontend.json --ci-build-id "
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.5.4",
|
"@apollo/client": "^3.5.8",
|
||||||
|
"@babel/core": "^7.16.7",
|
||||||
|
"@babel/eslint-plugin": "^7.16.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.5.0",
|
"@babel/plugin-transform-runtime": "^7.5.0",
|
||||||
"@babel/polyfill": "^7.4.4",
|
"@babel/polyfill": "^7.4.4",
|
||||||
"@babel/preset-env": "^7.5.4",
|
"@babel/preset-env": "^7.5.4",
|
||||||
"@babel/preset-stage-2": "^7.0.0",
|
"@babel/preset-stage-2": "^7.0.0",
|
||||||
"@babel/runtime": "^7.5.4",
|
"@babel/runtime": "^7.5.4",
|
||||||
"@iam4x/cypress-graphql-mock": "0.0.1",
|
"@iam4x/cypress-graphql-mock": "0.0.1",
|
||||||
"apollo-cache-inmemory": "^1.6.5",
|
"@vue/composition-api": "^1.4.2",
|
||||||
"apollo-client": "^2.6.8",
|
|
||||||
"apollo-link": "^1.2.13",
|
|
||||||
"apollo-link-error": "^1.1.12",
|
|
||||||
"apollo-link-http": "^1.5.16",
|
|
||||||
"appolo": "^6.0.19",
|
"appolo": "^6.0.19",
|
||||||
"autoprefixer": "^7.1.2",
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-eslint": "^8.2.1",
|
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
||||||
"chalk": "^2.0.1",
|
"chalk": "^2.0.1",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^10.1.0",
|
||||||
"css-loader": "^0.28.0",
|
"css-loader": "^0.28.0",
|
||||||
"cy2": "^1.2.1",
|
"cy2": "^1.2.1",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.7",
|
||||||
"debounce": "^1.2.0",
|
"debounce": "^1.2.0",
|
||||||
"eslint": "^4.15.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-standard": "^10.2.1",
|
"eslint-config-standard": "^16.0.3",
|
||||||
"eslint-friendly-formatter": "^3.0.0",
|
"eslint-friendly-formatter": "^4.0.1",
|
||||||
"eslint-loader": "^1.7.1",
|
"eslint-loader": "^4.0.2",
|
||||||
"eslint-plugin-cypress": "^2.11.2",
|
"eslint-plugin-cypress": "^2.12.1",
|
||||||
"eslint-plugin-import": "^2.7.0",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-node": "^5.2.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^3.4.0",
|
"eslint-plugin-promise": "^6.0.0",
|
||||||
"eslint-plugin-standard": "^3.0.1",
|
"eslint-plugin-standard": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^4.0.0",
|
"eslint-plugin-vue": "^8.3.0",
|
||||||
"extract-text-webpack-plugin": "^3.0.0",
|
|
||||||
"file-loader": "^1.1.4",
|
"file-loader": "^1.1.4",
|
||||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||||
"graphql": "^0.13.2",
|
"graphql": "^16.1.0",
|
||||||
"graphql-tag": "^2.10.1",
|
"graphql-tag": "^2.10.1",
|
||||||
"html-webpack-plugin": "^2.30.1",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
"moment": "^2.24.0",
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
"node-notifier": "^5.1.2",
|
"node-notifier": "^5.1.2",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
"optimize-css-assets-webpack-plugin": "^6.0.1",
|
||||||
"ora": "^1.2.0",
|
"ora": "^1.2.0",
|
||||||
"portfinder": "^1.0.13",
|
"portfinder": "^1.0.13",
|
||||||
"postcss-import": "^11.0.0",
|
"postcss-import": "^11.0.0",
|
||||||
|
|
@ -79,31 +76,30 @@
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"shelljs": "^0.7.6",
|
"shelljs": "^0.7.6",
|
||||||
"survey-vue": "^1.8.77",
|
"survey-vue": "^1.9.2",
|
||||||
"uglifyjs-webpack-plugin": "^1.1.1",
|
|
||||||
"unfetch": "^3.1.1",
|
"unfetch": "^3.1.1",
|
||||||
"uploadcare-widget": "^3.6.0",
|
"uploadcare-widget": "^3.6.0",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
"uuid": "^3.2.1",
|
"uuid": "^3.2.1",
|
||||||
"vee-validate": "^2.2.0",
|
"vee-validate": "^3.4.14",
|
||||||
"vue": "^2.5.17",
|
"vue": "^2.6.14",
|
||||||
"vue-analytics": "^5.16.2",
|
"vue-analytics": "^5.16.2",
|
||||||
"vue-apollo": "^3.0.0-beta.16",
|
"vue-apollo": "^3.1.0",
|
||||||
"vue-loader": "^15.9.6",
|
"vue-loader": "^15.9.8",
|
||||||
"vue-matomo": "^3.13.4-0",
|
"vue-matomo": "^3.13.4-0",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.5.3",
|
||||||
"vue-scrollto": "^2.11.0",
|
"vue-scrollto": "^2.11.0",
|
||||||
"vue-style-loader": "^3.0.1",
|
"vue-style-loader": "^3.0.1",
|
||||||
"vue-template-compiler": "^2.5.17",
|
"vue-template-compiler": "^2.6.14",
|
||||||
"vue-toast-notification": "^0.4.1",
|
"vue-toast-notification": "^0.4.1",
|
||||||
"vue-vimeo-player": "0.0.6",
|
"vue-vimeo-player": "0.0.6",
|
||||||
"vuejs-logger": "1.5.5",
|
"vuejs-logger": "1.5.5",
|
||||||
"vuetify": "^1.1.8",
|
"vuetify": "^1.1.8",
|
||||||
"vuex": "^3.0.1",
|
"vuex": "^3.0.1",
|
||||||
"webpack": "^3.6.0",
|
"webpack": "^5.65.0",
|
||||||
"webpack-bundle-analyzer": "^2.9.0",
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
"webpack-dev-server": "^2.9.1",
|
"webpack-dev-server": "^4.6.0",
|
||||||
"webpack-merge": "^4.1.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"whatwg-fetch": "^3.0.0"
|
"whatwg-fetch": "^3.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -116,6 +112,8 @@
|
||||||
"not ie <= 8"
|
"not ie <= 8"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||||
|
"@typescript-eslint/parser": "^5.10.0",
|
||||||
"@vue/test-utils": "^1.0.0-beta.29",
|
"@vue/test-utils": "^1.0.0-beta.29",
|
||||||
"babel-bridge": "^1.12.11",
|
"babel-bridge": "^1.12.11",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
|
|
@ -128,9 +126,10 @@
|
||||||
"jest-transform-graphql": "^2.1.0",
|
"jest-transform-graphql": "^2.1.0",
|
||||||
"jest-transform-stub": "^2.0.0",
|
"jest-transform-stub": "^2.0.0",
|
||||||
"jest-watch-typeahead": "^0.3.1",
|
"jest-watch-typeahead": "^0.3.1",
|
||||||
"mock-apollo-client": "^0.7.0",
|
"mock-apollo-client": "^1.2.0",
|
||||||
"ts-loader": "^8.3.0",
|
"ts-loader": "^8.3.0",
|
||||||
"typescript": "^4.4.3",
|
"typescript": "^4.5.4",
|
||||||
"vue-jest": "^3.0.4"
|
"vue-jest": "^3.0.4",
|
||||||
|
"webpack-cli": "^4.9.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,48 +2,52 @@
|
||||||
<div
|
<div
|
||||||
:class="{'no-scroll': showModal || showMobileNavigation}"
|
:class="{'no-scroll': showModal || showMobileNavigation}"
|
||||||
class="app"
|
class="app"
|
||||||
id="app">
|
id="app"
|
||||||
<read-only-banner/>
|
>
|
||||||
<scroll-up/>
|
<read-only-banner />
|
||||||
|
<scroll-up />
|
||||||
<component
|
<component
|
||||||
:is="showModalDeprecated"
|
:is="showModalDeprecated"
|
||||||
v-if="showModalDeprecated"/>
|
v-if="showModalDeprecated"
|
||||||
|
/>
|
||||||
<component
|
<component
|
||||||
:is="showModal"
|
:is="showModal"
|
||||||
v-if="showModal"/>
|
v-if="showModal"
|
||||||
<component :is="layout"/>
|
/>
|
||||||
|
<component :is="layout" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DefaultLayout from '@/layouts/DefaultLayout';
|
|
||||||
import SimpleLayout from '@/layouts/SimpleLayout';
|
|
||||||
import FullScreenLayout from '@/layouts/FullScreenLayout';
|
|
||||||
import PublicLayout from '@/layouts/PublicLayout';
|
|
||||||
import BlankLayout from '@/layouts/BlankLayout';
|
|
||||||
import SplitLayout from '@/layouts/SplitLayout';
|
|
||||||
import Modal from '@/components/Modal';
|
|
||||||
import NewContentBlockWizard from '@/components/content-block-form/NewContentBlockWizard';
|
|
||||||
import EditContentBlockWizard from '@/components/content-block-form/EditContentBlockWizard';
|
|
||||||
import NewRoomEntryWizard from '@/components/rooms/room-entries/NewRoomEntryWizard';
|
|
||||||
import EditRoomEntryWizard from '@/components/rooms/room-entries/EditRoomEntryWizard';
|
|
||||||
import NewProjectEntryWizard from '@/components/portfolio/NewProjectEntryWizard';
|
|
||||||
import EditProjectEntryWizard from '@/components/portfolio/EditProjectEntryWizard';
|
|
||||||
import NewObjectiveWizard from '@/components/objective-groups/NewObjectiveWizard';
|
|
||||||
import NewNoteWizard from '@/components/notes/NewNoteWizard';
|
|
||||||
import EditNoteWizard from '@/components/notes/EditNoteWizard';
|
|
||||||
import EditClassNameWizard from '@/components/school-class/EditClassNameWizard';
|
|
||||||
import EditTeamNameWizard from '@/components/profile/EditTeamNameWizard';
|
|
||||||
import FullscreenImage from '@/components/FullscreenImage';
|
|
||||||
import FullscreenInfographic from '@/components/FullscreenInfographic';
|
|
||||||
import FullscreenVideo from '@/components/FullscreenVideo';
|
|
||||||
import DeactivatePerson from '@/components/profile/DeactivatePerson';
|
|
||||||
import SnapshotCreated from '@/components/modules/SnapshotCreated';
|
|
||||||
import ChangeVisibility from '@/components/rooms/ChangeVisibility';
|
|
||||||
import {mapGetters} from 'vuex';
|
import {mapGetters} from 'vuex';
|
||||||
import ScrollUp from '@/components/ScrollUp';
|
import ScrollUp from '@/components/ScrollUp';
|
||||||
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
import ReadOnlyBanner from '@/components/ReadOnlyBanner';
|
||||||
|
|
||||||
|
const Modal = () => import(/* webpackChunkName: "modals" */'@/components/Modal');
|
||||||
|
const FullscreenImage = () => import(/* webpackChunkName: "modals" */'@/components/FullscreenImage');
|
||||||
|
const FullscreenInfographic = () => import(/* webpackChunkName: "modals" */'@/components/FullscreenInfographic');
|
||||||
|
const FullscreenVideo = () => import(/* webpackChunkName: "modals" */'@/components/FullscreenVideo');
|
||||||
|
const DeactivatePerson = () => import(/* webpackChunkName: "modals" */'@/components/profile/DeactivatePerson');
|
||||||
|
const SnapshotCreated = () => import(/* webpackChunkName: "modals" */'@/components/modules/SnapshotCreated');
|
||||||
|
const ChangeVisibility = () => import(/* webpackChunkName: "modals" */'@/components/rooms/ChangeVisibility');
|
||||||
|
const NewContentBlockWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/NewContentBlockWizard');
|
||||||
|
const EditContentBlockWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/EditContentBlockWizard');
|
||||||
|
const NewRoomEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/rooms/room-entries/NewRoomEntryWizard');
|
||||||
|
const EditRoomEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/rooms/room-entries/EditRoomEntryWizard');
|
||||||
|
const NewProjectEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/portfolio/NewProjectEntryWizard');
|
||||||
|
const EditProjectEntryWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/portfolio/EditProjectEntryWizard');
|
||||||
|
const NewObjectiveWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/objective-groups/NewObjectiveWizard');
|
||||||
|
const NewNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/NewNoteWizard');
|
||||||
|
const EditNoteWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/notes/EditNoteWizard');
|
||||||
|
const EditClassNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/school-class/EditClassNameWizard');
|
||||||
|
const EditTeamNameWizard = () => import(/* webpackChunkName: "content-forms" */'@/components/profile/EditTeamNameWizard');
|
||||||
|
const DefaultLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/DefaultLayout');
|
||||||
|
const SimpleLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SimpleLayout');
|
||||||
|
const FullScreenLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/FullScreenLayout');
|
||||||
|
const PublicLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/PublicLayout');
|
||||||
|
const BlankLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/BlankLayout');
|
||||||
|
const SplitLayout = () => import(/* webpackChunkName: "layouts" */'@/layouts/SplitLayout');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
||||||
|
|
@ -93,6 +97,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/main.scss";
|
@import "~styles/main.scss";
|
||||||
|
@import "~styles/helpers";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,20 @@
|
||||||
<div class="add-content">
|
<div class="add-content">
|
||||||
<a
|
<a
|
||||||
class="add-content__button"
|
class="add-content__button"
|
||||||
@click="addContent">
|
@click="addContent"
|
||||||
<add-pointer class="add-content__icon"/>
|
>
|
||||||
|
<add-pointer class="add-content__icon" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AddPointer from '@/components/icons/AddPointer';
|
import {
|
||||||
|
CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
||||||
|
CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
||||||
|
} from '@/router/module.names';
|
||||||
|
|
||||||
|
const AddPointer = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddPointer');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['after', 'parent'],
|
props: ['after', 'parent'],
|
||||||
|
|
@ -18,15 +24,31 @@
|
||||||
AddPointer
|
AddPointer
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
addContent() {
|
addContent() {
|
||||||
if (this.parent && this.parent.__typename === 'ObjectiveGroupNode') {
|
if (this.parent && this.parent.__typename === 'ObjectiveGroupNode') {
|
||||||
this.$store.dispatch('addObjective', this.parent.id);
|
this.$store.dispatch('addObjective', this.parent.id);
|
||||||
} else {
|
} else {
|
||||||
this.$store.dispatch('addContentBlock', {
|
let route;
|
||||||
after: this.after ? this.after.id : undefined,
|
const slug = this.$route.params.slug;
|
||||||
parent: this.parent ? this.parent.id : undefined
|
if (this.after.id) {
|
||||||
});
|
route = {
|
||||||
|
name: CREATE_CONTENT_BLOCK_AFTER_PAGE,
|
||||||
|
params: {
|
||||||
|
after: this.after.id,
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
route = {
|
||||||
|
name: CREATE_CONTENT_BLOCK_UNDER_PARENT_PAGE,
|
||||||
|
params: {
|
||||||
|
parent: this.parent.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,8 +56,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
@import "@/styles/_mixins.scss";
|
|
||||||
|
|
||||||
.add-content {
|
.add-content {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="add-content-element"
|
class="add-content-element"
|
||||||
@click="$emit('add-element', index)">
|
@click="$emit('add-element', index)"
|
||||||
<add-icon class="add-content-element__icon"/>
|
>
|
||||||
|
<add-icon class="add-content-element__icon" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AddIcon from '@/components/icons/AddIcon';
|
const AddIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['index'],
|
props: ['index'],
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
:is="component"
|
|
||||||
v-bind="properties"
|
v-bind="properties"
|
||||||
:class="{ 'add-widget--reverse': reverse }"
|
:class="{ 'add-widget--reverse': reverse }"
|
||||||
class="add-widget"
|
class="add-widget"
|
||||||
@click="$emit('click')">
|
:is="component"
|
||||||
<add-icon class="add-widget__add"/>
|
@click="$emit('click')"
|
||||||
|
>
|
||||||
|
<add-icon class="add-widget__add" />
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AddIcon from '@/components/icons/AddIcon.vue';
|
const AddIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/AddIcon.vue');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,64 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="assignment-with-submissions">
|
<div class="assignment-with-submissions">
|
||||||
<p class="assignment-with-submissions__text">{{ assignment.assignment }}</p>
|
<p class="assignment-with-submissions__text">
|
||||||
|
{{ assignment.assignment }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="button button--primary submissions-page__back"
|
class="button button--primary submissions-page__back"
|
||||||
@click="$emit('back')">Aufgabe im Modul anzeigen</a>
|
@click="$emit('back')"
|
||||||
|
>Aufgabe im Modul anzeigen</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="assignment-with-submissions__solution"
|
class="assignment-with-submissions__solution"
|
||||||
v-if="assignment.solution">
|
v-if="assignment.solution"
|
||||||
<h4 class="assignment-with-submissions__heading">Lösung</h4>
|
>
|
||||||
|
<h4 class="assignment-with-submissions__heading">
|
||||||
|
Lösung
|
||||||
|
</h4>
|
||||||
<p
|
<p
|
||||||
class="assignment-with-submissions__solution-text"
|
class="assignment-with-submissions__solution-text"
|
||||||
data-cy="assignment-solution"
|
data-cy="assignment-solution"
|
||||||
v-html="assignment.solution" />
|
v-html="assignment.solution"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
class="assignment-with-submissions__no-submissions"
|
class="assignment-with-submissions__no-submissions"
|
||||||
v-if="!assignment.submissions.length">Zu diesem Auftrag sind noch keine Ergebnisse vorhanden.</p>
|
v-if="!assignment.submissions.length"
|
||||||
|
>
|
||||||
|
Zu diesem Auftrag sind noch keine Ergebnisse vorhanden.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="assignment-with-submissions__submissions submissions"
|
class="assignment-with-submissions__submissions submissions"
|
||||||
v-if="assignment.submissions.length">
|
v-if="assignment.submissions.length"
|
||||||
|
>
|
||||||
<div class="submissions__header student-submission-row submission-header">
|
<div class="submissions__header student-submission-row submission-header">
|
||||||
<p class="submission-header__title">Lernende</p>
|
<p class="submission-header__title">
|
||||||
<p class="submission-header__title">Ergebnisse</p>
|
Lernende
|
||||||
<p class="submission-header__title">Feedback</p>
|
</p>
|
||||||
|
<p class="submission-header__title">
|
||||||
|
Ergebnisse
|
||||||
|
</p>
|
||||||
|
<p class="submission-header__title">
|
||||||
|
Feedback
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
:to="submissionLink(submission)"
|
:to="submissionLink(submission)"
|
||||||
:key="submission.id"
|
|
||||||
class="assignment-with-submissions__link"
|
class="assignment-with-submissions__link"
|
||||||
v-for="submission in submissions">
|
v-for="submission in submissions"
|
||||||
|
:key="submission.id"
|
||||||
|
>
|
||||||
<student-submission
|
<student-submission
|
||||||
:submission="submission"
|
:submission="submission"
|
||||||
class="assignment-with-submissions__submission"
|
class="assignment-with-submissions__submission"
|
||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -81,7 +99,7 @@
|
||||||
if (this.currentFilter.id === '') {
|
if (this.currentFilter.id === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return submission.student.schoolClasses.edges.some(edge => edge.node.id === this.currentFilter.id);
|
return submission.student.schoolClasses.some(schoolClass => schoolClass .id === this.currentFilter.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<router-link
|
<router-link
|
||||||
:to="to"
|
:to="to"
|
||||||
class="sub-navigation-item back-link">
|
class="sub-navigation-item back-link"
|
||||||
<chevron-left class="back-link__icon sub-navigation-item__icon"/>
|
>
|
||||||
|
<chevron-left class="back-link__icon sub-navigation-item__icon" />
|
||||||
{{ fullTitle }}
|
{{ fullTitle }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ChevronLeft from '@/components/icons/ChevronLeft';
|
|
||||||
import {MODULE_PAGE} from '@/router/module.names';
|
import {MODULE_PAGE} from '@/router/module.names';
|
||||||
import {ROOMS_PAGE} from '@/router/room.names';
|
import {ROOMS_PAGE} from '@/router/room.names';
|
||||||
import {PROJECTS_PAGE} from '@/router/portfolio.names';
|
import {PROJECTS_PAGE} from '@/router/portfolio.names';
|
||||||
|
|
||||||
|
const ChevronLeft = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronLeft');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
title: {
|
title: {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:data-scrollto="chapter.id"
|
:data-scrollto="chapter.id"
|
||||||
class="chapter">
|
class="chapter"
|
||||||
|
data-cy="chapter"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
:class="{'hideable-element--greyed-out': titleGreyedOut}"
|
:class="{'hideable-element--greyed-out': titleGreyedOut}"
|
||||||
class="hideable-element"
|
class="hideable-element"
|
||||||
v-if="!titleHidden">
|
v-if="!titleHidden"
|
||||||
|
>
|
||||||
<h3
|
<h3
|
||||||
:id="'chapter-' + index"
|
:id="'chapter-' + index"
|
||||||
>{{ chapter.title }}</h3>
|
>
|
||||||
|
{{ chapter.title }}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<visibility-action
|
<visibility-action
|
||||||
|
|
@ -21,6 +26,7 @@
|
||||||
:bookmarked="chapter.bookmark"
|
:bookmarked="chapter.bookmark"
|
||||||
:note="note"
|
:note="note"
|
||||||
class="chapter__bookmark-actions"
|
class="chapter__bookmark-actions"
|
||||||
|
data-cy="chapter-bookmark-actions"
|
||||||
@add-note="addNote"
|
@add-note="addNote"
|
||||||
@edit-note="editNote"
|
@edit-note="editNote"
|
||||||
@bookmark="bookmark(!chapter.bookmark)"
|
@bookmark="bookmark(!chapter.bookmark)"
|
||||||
|
|
@ -37,20 +43,23 @@
|
||||||
v-if="editModule"
|
v-if="editModule"
|
||||||
/>
|
/>
|
||||||
<p
|
<p
|
||||||
class="chapter__description">
|
class="chapter__description"
|
||||||
|
>
|
||||||
{{ chapter.description }}
|
{{ chapter.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-content-button
|
<add-content-button
|
||||||
:parent="chapter"
|
:parent="chapter"
|
||||||
v-if="editModule"/>
|
v-if="editModule"
|
||||||
|
/>
|
||||||
|
|
||||||
<content-block
|
<content-block
|
||||||
:content-block="contentBlock"
|
:content-block="contentBlock"
|
||||||
:parent="chapter.id"
|
:parent="chapter.id"
|
||||||
|
v-for="contentBlock in filteredContentBlocks"
|
||||||
:key="contentBlock.id"
|
:key="contentBlock.id"
|
||||||
v-for="contentBlock in filteredContentBlocks"/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -100,6 +109,7 @@
|
||||||
if (this.chapter && this.chapter.bookmark) {
|
if (this.chapter && this.chapter.bookmark) {
|
||||||
return this.chapter.bookmark.note;
|
return this.chapter.bookmark.note;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
titleGreyedOut() {
|
titleGreyedOut() {
|
||||||
return this.textHidden(CHAPTER_TITLE_TYPE) && this.editModule;
|
return this.textHidden(CHAPTER_TITLE_TYPE) && this.editModule;
|
||||||
|
|
@ -134,26 +144,31 @@
|
||||||
bookmarked,
|
bookmarked,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: (store, response) => {
|
update: (store) => {
|
||||||
const query = CHAPTER_QUERY;
|
const query = CHAPTER_QUERY;
|
||||||
const variables = {id};
|
const variables = {id};
|
||||||
const data = store.readQuery({
|
const {chapter} = store.readQuery({
|
||||||
query,
|
query,
|
||||||
variables,
|
variables,
|
||||||
});
|
});
|
||||||
|
|
||||||
const chapter = data.chapter;
|
let bookmark;
|
||||||
|
|
||||||
if (bookmarked) {
|
if (bookmarked) {
|
||||||
chapter.bookmark = {
|
bookmark = {
|
||||||
__typename: 'ChapterBookmarkNode',
|
__typename: 'ChapterBookmarkNode',
|
||||||
note: null,
|
note: null,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
chapter.bookmark = null;
|
bookmark = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.chapter = chapter;
|
const data = {
|
||||||
|
chapter: {
|
||||||
|
...chapter,
|
||||||
|
bookmark
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
store.writeQuery({
|
store.writeQuery({
|
||||||
data,
|
data,
|
||||||
|
|
@ -192,7 +207,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_mixins.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.chapter {
|
.chapter {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="color-chooser">
|
<div class="color-chooser">
|
||||||
<div
|
<div
|
||||||
:key="index"
|
|
||||||
:class="{'color-chooser__color-wrapper--selected': selectedColor === color.name}"
|
:class="{'color-chooser__color-wrapper--selected': selectedColor === color.name}"
|
||||||
class="color-chooser__color-wrapper"
|
class="color-chooser__color-wrapper"
|
||||||
data-cy="color-select"
|
data-cy="color-select"
|
||||||
v-for="(color, index) in colors"
|
v-for="(color, index) in colors"
|
||||||
@click="$emit('input', color.name)">
|
:key="index"
|
||||||
|
@click="$emit('input', color.name)"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
:class="'color-chooser__color--' + color.name"
|
:class="'color-chooser__color--' + color.name"
|
||||||
class="color-chooser__color">
|
class="color-chooser__color"
|
||||||
|
>
|
||||||
<tick
|
<tick
|
||||||
class="color-chooser__selected-icon"
|
class="color-chooser__selected-icon"
|
||||||
v-if="selectedColor === color.name"/>
|
v-if="selectedColor === color.name"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Tick from '@/components/icons/Tick';
|
const Tick = () => import(/* webpackChunkName: "icons" */'@/components/icons/Tick');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['selected-color'],
|
props: ['selectedColor'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Tick
|
Tick
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,73 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{'hideable-element--greyed-out': hidden}"
|
:class="{'hideable-element--greyed-out': hidden}"
|
||||||
class="content-block__container hideable-element">
|
class="content-block__container hideable-element content-list__parent"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
:class="specialClass"
|
:class="specialClass"
|
||||||
class="content-block">
|
class="content-block"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="block-actions"
|
class="block-actions"
|
||||||
v-if="canEditContentBlock && editModule">
|
v-if="canEditContentBlock && editModule"
|
||||||
|
>
|
||||||
<user-widget
|
<user-widget
|
||||||
v-bind="me"
|
v-bind="me"
|
||||||
class="block-actions__user-widget content-block__user-widget"/>
|
class="block-actions__user-widget content-block__user-widget"
|
||||||
|
/>
|
||||||
<more-options-widget>
|
<more-options-widget>
|
||||||
<li class="popover-links__link">
|
<li class="popover-links__link">
|
||||||
<popover-link
|
<popover-link
|
||||||
data-cy="delete-content-block-link"
|
data-cy="delete-content-block-link"
|
||||||
text="Löschen"
|
text="Löschen"
|
||||||
@link-action="deleteContentBlock(contentBlock)" />
|
@link-action="deleteContentBlock(contentBlock)"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="popover-links__link">
|
<li class="popover-links__link">
|
||||||
<popover-link
|
<popover-link
|
||||||
text="Bearbeiten"
|
text="Bearbeiten"
|
||||||
@link-action="editContentBlock(contentBlock)" />
|
@link-action="editContentBlock(contentBlock)"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
</more-options-widget>
|
</more-options-widget>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-block__visibility">
|
<div class="content-block__visibility">
|
||||||
<visibility-action
|
<visibility-action
|
||||||
:block="contentBlock"
|
:block="contentBlock"
|
||||||
v-if="canEditModule"/>
|
v-if="canEditModule"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3
|
<h3
|
||||||
class="content-block__instrument-label"
|
class="content-block__instrument-label"
|
||||||
v-if="instrumentLabel !== ''">{{ instrumentLabel }}</h3>
|
v-if="instrumentLabel !== ''"
|
||||||
|
>
|
||||||
|
{{ instrumentLabel }}
|
||||||
|
</h3>
|
||||||
<h4
|
<h4
|
||||||
class="content-block__title"
|
class="content-block__title"
|
||||||
v-if="!contentBlock.indent">{{ contentBlock.title }}</h4>
|
v-if="!contentBlock.indent"
|
||||||
|
>
|
||||||
|
{{ contentBlock.title }}
|
||||||
|
</h4>
|
||||||
|
|
||||||
<content-component
|
<content-component
|
||||||
:key="component.id"
|
|
||||||
:component="component"
|
:component="component"
|
||||||
:root="root"
|
:root="root"
|
||||||
:parent="contentBlock"
|
:parent="contentBlock"
|
||||||
:bookmarks="contentBlock.bookmarks"
|
:bookmarks="contentBlock.bookmarks"
|
||||||
:notes="contentBlock.notes"
|
:notes="contentBlock.notes"
|
||||||
v-for="component in contentBlocksWithContentLists.contents"
|
v-for="component in contentBlocksWithContentLists.contents"
|
||||||
|
:key="component.id"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-content-button
|
<add-content-button
|
||||||
:after="contentBlock"
|
:after="contentBlock"
|
||||||
v-if="canEditModule"/>
|
v-if="canEditModule"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -65,7 +75,6 @@
|
||||||
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
|
||||||
import UserWidget from '@/components/UserWidget';
|
import UserWidget from '@/components/UserWidget';
|
||||||
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
import VisibilityAction from '@/components/visibility/VisibilityAction';
|
||||||
import ContentComponent from '@/components/content-blocks/ContentComponent';
|
|
||||||
|
|
||||||
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
|
||||||
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
|
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
|
||||||
|
|
@ -76,6 +85,7 @@
|
||||||
import {hidden} from '@/helpers/visibility';
|
import {hidden} from '@/helpers/visibility';
|
||||||
import {CONTENT_TYPE} from '@/consts/types';
|
import {CONTENT_TYPE} from '@/consts/types';
|
||||||
import PopoverLink from '@/components/ui/PopoverLink';
|
import PopoverLink from '@/components/ui/PopoverLink';
|
||||||
|
const ContentComponent = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentComponent');
|
||||||
|
|
||||||
const instruments = {
|
const instruments = {
|
||||||
base_communication: 'Sprache & Kommunikation',
|
base_communication: 'Sprache & Kommunikation',
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@
|
||||||
<modal
|
<modal
|
||||||
:hide-header="true"
|
:hide-header="true"
|
||||||
:fullscreen="true"
|
:fullscreen="true"
|
||||||
class="fullscreen-image">
|
class="fullscreen-image"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="imageUrl"
|
:src="imageUrl"
|
||||||
class="fullscreen-image__image">
|
class="fullscreen-image__image"
|
||||||
|
>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<modal :fullscreen="true">
|
<modal :fullscreen="true">
|
||||||
<component
|
<component
|
||||||
|
:value="value"
|
||||||
:is="type"
|
:is="type"
|
||||||
:value="value"/>
|
/>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import InfogramBlock from '@/components/content-blocks/InfogramBlock';
|
const InfogramBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock');
|
||||||
import GeniallyBlock from '@/components/content-blocks/GeniallyBlock';
|
const GeniallyBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
<modal
|
<modal
|
||||||
:hide-header="true"
|
:hide-header="true"
|
||||||
:fullscreen="true"
|
:fullscreen="true"
|
||||||
class="fullscreen-video">
|
class="fullscreen-video"
|
||||||
|
>
|
||||||
<iframe
|
<iframe
|
||||||
:src="src"
|
:src="src"
|
||||||
width="2000"
|
width="2000"
|
||||||
|
|
@ -11,9 +12,9 @@
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
webkitallowfullscreen
|
webkitallowfullscreen
|
||||||
mozallowfullscreen
|
mozallowfullscreen
|
||||||
allowfullscreen/>
|
allowfullscreen
|
||||||
|
/>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,26 @@
|
||||||
<a
|
<a
|
||||||
class="header-bar__sidebar-link"
|
class="header-bar__sidebar-link"
|
||||||
data-cy="open-sidebar-link"
|
data-cy="open-sidebar-link"
|
||||||
@click.stop="openSidebar('navigation')">
|
@click.stop="openSidebar('navigation')"
|
||||||
<hamburger class="header-bar__sidebar-icon"/>
|
>
|
||||||
|
<hamburger class="header-bar__sidebar-icon" />
|
||||||
</a>
|
</a>
|
||||||
<content-navigation class="header-bar__content-navigation"/>
|
<content-navigation class="header-bar__content-navigation" />
|
||||||
<div class="user-header">
|
<div class="user-header">
|
||||||
<a
|
<a
|
||||||
class="user-header__sidebar-link" >
|
class="user-header__sidebar-link"
|
||||||
|
>
|
||||||
<current-class
|
<current-class
|
||||||
class="user-header__current-class"
|
class="user-header__current-class"
|
||||||
@click.native.stop="openSidebar('profile')"/>
|
@click.native.stop="openSidebar('profile')"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<user-widget
|
<user-widget
|
||||||
v-bind="me"
|
v-bind="me"
|
||||||
data-cy="header-user-widget"
|
data-cy="header-user-widget"
|
||||||
@click.native.stop="openSidebar('profile')"/>
|
@click.native.stop="openSidebar('profile')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -26,20 +30,19 @@
|
||||||
<script>
|
<script>
|
||||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
import ContentNavigation from '@/components/book-navigation/ContentNavigation.vue';
|
||||||
import UserWidget from '@/components/UserWidget.vue';
|
import UserWidget from '@/components/UserWidget.vue';
|
||||||
import Logo from '@/components/icons/Logo';
|
|
||||||
import CurrentClass from '@/components/school-class/CurrentClass';
|
import CurrentClass from '@/components/school-class/CurrentClass';
|
||||||
import Hamburger from '@/components/icons/Hamburger';
|
|
||||||
|
|
||||||
import openSidebar from '@/mixins/open-sidebar';
|
import openSidebar from '@/mixins/open-sidebar';
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
|
|
||||||
|
const Hamburger = () => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [openSidebar, me],
|
mixins: [openSidebar, me],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
ContentNavigation,
|
ContentNavigation,
|
||||||
UserWidget,
|
UserWidget,
|
||||||
Logo,
|
|
||||||
CurrentClass,
|
CurrentClass,
|
||||||
Hamburger,
|
Hamburger,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="helpful-tooltip">
|
<div class="helpful-tooltip">
|
||||||
<info-icon class="helpful-tooltip__icon"/>
|
<info-icon class="helpful-tooltip__icon" />
|
||||||
<div class="helpful-tooltip__tooltip">
|
<div class="helpful-tooltip__tooltip">
|
||||||
<div class="helpful-tooltip__text">
|
<div class="helpful-tooltip__text">
|
||||||
{{ text }}
|
{{ text }}
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InfoIcon from '@/components/icons/InfoIcon';
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['text'],
|
props: ['text'],
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
:disabled="loading"
|
:disabled="loading || disabled"
|
||||||
class="loading-button button button--primary button--big">
|
class="loading-button button button--primary button--big"
|
||||||
<template v-if="!loading">{{ label }}</template>
|
>
|
||||||
|
<template v-if="!loading">
|
||||||
|
{{ label }}
|
||||||
|
</template>
|
||||||
<loading-icon
|
<loading-icon
|
||||||
class="loading-button__icon"
|
class="loading-button__icon"
|
||||||
v-else/>
|
v-else
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LoadingIcon from '@/components/icons/LoadingIcon';
|
const LoadingIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/LoadingIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -18,6 +22,10 @@
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
|
@ -30,7 +38,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_helpers.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.loading-button {
|
.loading-button {
|
||||||
height: 52px;
|
height: 52px;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
<a
|
<a
|
||||||
class="logout-widget__logout"
|
class="logout-widget__logout"
|
||||||
data-cy="logout"
|
data-cy="logout"
|
||||||
@click="logout()">Abmelden</a>
|
@click="logout()"
|
||||||
|
>Abmelden</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mobile-header">
|
<div class="mobile-header">
|
||||||
<a @click="showMobileNavigation">
|
<a @click="showMobileNavigation">
|
||||||
<hamburger class="mobile-header__hamburger"/>
|
<hamburger class="mobile-header__hamburger" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
to="/"
|
to="/"
|
||||||
data-cy="mobile-home-link">
|
data-cy="mobile-home-link"
|
||||||
<logo/>
|
>
|
||||||
|
<logo />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<user-widget
|
<user-widget
|
||||||
v-bind="me"
|
v-bind="me"
|
||||||
@click.native.stop="openSidebar('profile')"/>
|
@click.native.stop="openSidebar('profile')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Logo from '@/components/icons/Logo';
|
|
||||||
import Hamburger from '@/components/icons/Hamburger';
|
|
||||||
import UserWidget from '@/components/UserWidget';
|
import UserWidget from '@/components/UserWidget';
|
||||||
|
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
import openSidebar from '@/mixins/open-sidebar';
|
import openSidebar from '@/mixins/open-sidebar';
|
||||||
|
|
||||||
|
const Logo = () => import(/* webpackChunkName: "icons" */'@/components/icons/Logo');
|
||||||
|
const Hamburger = () => import(/* webpackChunkName: "icons" */'@/components/icons/Hamburger');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [me, openSidebar],
|
mixins: [me, openSidebar],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,18 @@
|
||||||
<div class="modal__backdrop">
|
<div class="modal__backdrop">
|
||||||
<div
|
<div
|
||||||
:class="{'modal--hide-header': hideHeader || fullscreen, 'modal--fullscreen': fullscreen, 'modal--small': small}"
|
:class="{'modal--hide-header': hideHeader || fullscreen, 'modal--fullscreen': fullscreen, 'modal--small': small}"
|
||||||
class="modal">
|
class="modal"
|
||||||
|
>
|
||||||
<div class="modal__header">
|
<div class="modal__header">
|
||||||
<slot name="header"/>
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__body">
|
<div class="modal__body">
|
||||||
<slot/>
|
<slot />
|
||||||
<div
|
<div
|
||||||
class="modal__close-button"
|
class="modal__close-button"
|
||||||
@click="hideModal">
|
@click="hideModal"
|
||||||
<cross class="modal__close-icon"/>
|
>
|
||||||
|
<cross class="modal__close-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal__footer">
|
<div class="modal__footer">
|
||||||
|
|
@ -19,7 +21,8 @@
|
||||||
<!--<a class="button button--active">Speichern</a>-->
|
<!--<a class="button button--active">Speichern</a>-->
|
||||||
<a
|
<a
|
||||||
class="button"
|
class="button"
|
||||||
@click="hideModal">Abbrechen</a>
|
@click="hideModal"
|
||||||
|
>Abbrechen</a>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,7 +30,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Cross from '@/components/icons/Cross';
|
const Cross = () => import(/* webpackChunkName: "icons" */'@/components/icons/Cross');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@
|
||||||
:class="{'skillbox-input--error': error}"
|
:class="{'skillbox-input--error': error}"
|
||||||
:value="value"
|
:value="value"
|
||||||
class="modal-input__inputfield skillbox-input"
|
class="modal-input__inputfield skillbox-input"
|
||||||
@input="$emit('input', $event.target.value)">
|
@input="$emit('input', $event.target.value)"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="modal-input__error"
|
class="modal-input__error"
|
||||||
v-if="error">
|
v-if="error"
|
||||||
|
>
|
||||||
Für Inhaltsblöcke muss zwingend ein Titel erfasst werden.
|
Für Inhaltsblöcke muss zwingend ein Titel erfasst werden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,24 @@
|
||||||
<a
|
<a
|
||||||
class="more-options__more-link"
|
class="more-options__more-link"
|
||||||
data-cy="more-options-link"
|
data-cy="more-options-link"
|
||||||
@click.stop="showMenu = !showMenu">
|
@click.stop="showMenu = !showMenu"
|
||||||
<ellipses class="more-options__ellipses"/>
|
>
|
||||||
|
<ellipses class="more-options__ellipses" />
|
||||||
</a>
|
</a>
|
||||||
<widget-popover
|
<widget-popover
|
||||||
class="more-options__popover"
|
class="more-options__popover"
|
||||||
v-if="showMenu"
|
v-if="showMenu"
|
||||||
@hide-me="showMenu = false">
|
@hide-me="showMenu = false"
|
||||||
<slot/>
|
>
|
||||||
|
<slot />
|
||||||
</widget-popover>
|
</widget-popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import WidgetPopover from '@/components/ui/WidgetPopover';
|
import WidgetPopover from '@/components/ui/WidgetPopover';
|
||||||
import Ellipses from '@/components/icons/Ellipses.vue';
|
|
||||||
|
const Ellipses = () => import(/* webpackChunkName: "icons" */'@/components/icons/Ellipses.vue');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
<div
|
<div
|
||||||
class="read-only-banner"
|
class="read-only-banner"
|
||||||
data-cy="read-only-banner"
|
data-cy="read-only-banner"
|
||||||
v-if="me.readOnly || me.selectedClass.readOnly">
|
v-if="me.readOnly || me.selectedClass.readOnly"
|
||||||
|
>
|
||||||
<div class="read-only-banner__content">
|
<div class="read-only-banner__content">
|
||||||
<p class="read-only-banner__text">
|
<p class="read-only-banner__text">
|
||||||
{{ readOnlyText }} Sie können Inhalte lesen, aber nicht
|
{{ readOnlyText }} Sie können Inhalte lesen, aber nicht
|
||||||
|
|
@ -13,14 +14,16 @@
|
||||||
:to="licenseActivationLink"
|
:to="licenseActivationLink"
|
||||||
data-cy="license-activation-link"
|
data-cy="license-activation-link"
|
||||||
class="read-only-banner__link button button--primary"
|
class="read-only-banner__link button button--primary"
|
||||||
v-if="me.readOnly">Neuen Lizenzcode eingeben
|
v-if="me.readOnly"
|
||||||
|
>
|
||||||
|
Neuen Lizenzcode eingeben
|
||||||
</router-link>
|
</router-link>
|
||||||
<a
|
<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href="https://myskillbox.ch/lesemodus"
|
href="https://myskillbox.ch/lesemodus"
|
||||||
class="button button--secondary">Mehr Informationen zum Lesemodus</a>
|
class="button button--secondary"
|
||||||
|
>Mehr Informationen zum Lesemodus</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,15 @@
|
||||||
<a
|
<a
|
||||||
class="scroll-up"
|
class="scroll-up"
|
||||||
v-if="scroll>200"
|
v-if="scroll>200"
|
||||||
@click="scrollTop">
|
@click="scrollTop"
|
||||||
<arrow-up class="scroll-up__icon"/>
|
>
|
||||||
|
<arrow-up class="scroll-up__icon" />
|
||||||
</a>
|
</a>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ArrowUp from '@/components/icons/ArrowUp';
|
const ArrowUp = () => import(/* webpackChunkName: "icons" */'@/components/icons/ArrowUp');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,22 @@
|
||||||
<div
|
<div
|
||||||
:class="{'section-block--navigatable': route}"
|
:class="{'section-block--navigatable': route}"
|
||||||
class="section-block__illustration"
|
class="section-block__illustration"
|
||||||
@click="navigate()">
|
@click="navigate()"
|
||||||
<slot/>
|
>
|
||||||
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:class="{'section-block--navigatable': route}"
|
:class="{'section-block--navigatable': route}"
|
||||||
class="section-block__title block-title"
|
class="section-block__title block-title"
|
||||||
@click="navigate()">
|
@click="navigate()"
|
||||||
<h2 class="block-title__title">{{ title }}</h2>
|
>
|
||||||
<h3 class="block-title__subtitle small-emph">{{ subtitle }}</h3>
|
<h2 class="block-title__title">
|
||||||
|
{{ title }}
|
||||||
|
</h2>
|
||||||
|
<h3 class="block-title__subtitle small-emph">
|
||||||
|
{{ subtitle }}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-block__content section-content">
|
<div class="section-block__content section-content">
|
||||||
<div class="section-content__subsection subsection">
|
<div class="section-content__subsection subsection">
|
||||||
|
|
@ -20,12 +26,14 @@
|
||||||
:class="{'section-block--navigatable': route}"
|
:class="{'section-block--navigatable': route}"
|
||||||
class="subsection__content button button--primary"
|
class="subsection__content button button--primary"
|
||||||
v-if="route"
|
v-if="route"
|
||||||
@click="navigate()">
|
@click="navigate()"
|
||||||
|
>
|
||||||
{{ linkText }}
|
{{ linkText }}
|
||||||
</a>
|
</a>
|
||||||
<span
|
<span
|
||||||
class="subsection__content subsection__content--disabled"
|
class="subsection__content subsection__content--disabled"
|
||||||
v-if="!route">Noch nicht verfügbar</span>
|
v-if="!route"
|
||||||
|
>Noch nicht verfügbar</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -33,7 +41,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ['title', 'subtitle', 'route', 'link-text'],
|
props: ['title', 'subtitle', 'route', 'linkText'],
|
||||||
methods: {
|
methods: {
|
||||||
navigate() {
|
navigate() {
|
||||||
if (this.route) {
|
if (this.route) {
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,24 @@
|
||||||
<p>{{ submission.text | trimToLength(50) }}</p>
|
<p>{{ submission.text | trimToLength(50) }}</p>
|
||||||
<p
|
<p
|
||||||
class="entry__document"
|
class="entry__document"
|
||||||
v-if="submission.document && submission.document.length > 0">
|
v-if="submission.document && submission.document.length > 0"
|
||||||
|
>
|
||||||
<student-submission-document
|
<student-submission-document
|
||||||
:document="submission.document"
|
:document="submission.document"
|
||||||
class="entry-document"/>
|
class="entry-document"
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="student-submission__feedback entry"
|
class="student-submission__feedback entry"
|
||||||
v-if="submission.submissionFeedback">
|
v-if="submission.submissionFeedback"
|
||||||
|
>
|
||||||
<p
|
<p
|
||||||
:class="{'entry__text--final': submission.submissionFeedback.final}"
|
:class="{'entry__text--final': submission.submissionFeedback.final}"
|
||||||
class="entry__text">{{ submission.submissionFeedback.text | trimToLength(50) }}</p>
|
class="entry__text"
|
||||||
|
>
|
||||||
|
{{ submission.submissionFeedback.text | trimToLength(50) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,17 @@
|
||||||
<div class="submission-document">
|
<div class="submission-document">
|
||||||
<p
|
<p
|
||||||
class="submission-document__content content"
|
class="submission-document__content content"
|
||||||
v-if="document && document.length > 0">
|
v-if="document && document.length > 0"
|
||||||
<document-icon class="content__icon"/><span class="content__text">{{ filename }}</span>
|
>
|
||||||
|
<document-icon class="content__icon" /><span class="content__text">{{ filename }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import DocumentIcon from '@/components/icons/DocumentIcon';
|
|
||||||
import filenameFromUrl from '@/helpers/urls';
|
import filenameFromUrl from '@/helpers/urls';
|
||||||
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'StudentSubmissionDocument',
|
name: 'StudentSubmissionDocument',
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
<span class="user-widget__name">{{ firstName }} {{ lastName }}</span>
|
<span class="user-widget__name">{{ firstName }} {{ lastName }}</span>
|
||||||
<span
|
<span
|
||||||
class="user-widget__date"
|
class="user-widget__date"
|
||||||
v-if="date">{{ date }}</span>
|
v-if="date"
|
||||||
|
>{{ date }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{'user-widget--is-profile': isProfile}"
|
:class="{'user-widget--is-profile': isProfile}"
|
||||||
class="user-widget">
|
class="user-widget"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="user-widget__avatar"
|
class="user-widget__avatar"
|
||||||
data-cy="user-widget-avatar">
|
data-cy="user-widget-avatar"
|
||||||
|
>
|
||||||
<avatar
|
<avatar
|
||||||
:avatar-url="avatarUrl"
|
:avatar-url="avatarUrl"
|
||||||
:icon-highlighted="isProfile"
|
:icon-highlighted="isProfile"
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'topic', params: {topicSlug: topic.slug}}"
|
:to="{name: 'topic', params: {topicSlug: topic.slug}}"
|
||||||
:class="{'book-topics__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile}"
|
:class="{'book-topics__topic--active': topic.active, 'book-subnavigation__item--mobile': mobile}"
|
||||||
:key="topic.id"
|
|
||||||
tag="div"
|
tag="div"
|
||||||
active-class="book-subnavigation__item--active"
|
active-class="book-subnavigation__item--active"
|
||||||
class="book-topics__topic book-subnavigation__item"
|
class="book-topics__topic book-subnavigation__item"
|
||||||
v-for="topic in topics"
|
v-for="topic in topics"
|
||||||
@click.native="closeSidebar('navigation')">
|
:key="topic.id"
|
||||||
|
@click.native="closeSidebar('navigation')"
|
||||||
|
>
|
||||||
{{ topic.order }}.
|
{{ topic.order }}.
|
||||||
{{ topic.title }}
|
{{ topic.title }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
@ -44,7 +45,7 @@
|
||||||
topics: {
|
topics: {
|
||||||
query: ALL_TOPICS_QUERY,
|
query: ALL_TOPICS_QUERY,
|
||||||
manual: true,
|
manual: true,
|
||||||
result({data, loading, networkStatus}) {
|
result({data, loading}) {
|
||||||
if (!loading) {
|
if (!loading) {
|
||||||
this.topics = this.$getRidOfEdges(data).topics;
|
this.topics = this.$getRidOfEdges(data).topics;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<nav
|
<nav
|
||||||
:class="{'content-navigation--sidebar': isSidebar}"
|
:class="{'content-navigation--sidebar': isSidebar}"
|
||||||
class="content-navigation">
|
class="content-navigation"
|
||||||
|
>
|
||||||
<div class="content-navigation__primary">
|
<div class="content-navigation__primary">
|
||||||
<div class="content-navigation__item">
|
<div class="content-navigation__item">
|
||||||
<router-link
|
<router-link
|
||||||
|
|
@ -9,13 +10,14 @@
|
||||||
:to="topicRoute"
|
:to="topicRoute"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
@click.native="close">Themen
|
@click.native="close"
|
||||||
|
>
|
||||||
|
Themen
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<book-topic-navigation
|
<book-topic-navigation
|
||||||
v-if="isSidebar"
|
v-if="isSidebar"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-navigation__item">
|
<div class="content-navigation__item">
|
||||||
|
|
@ -23,7 +25,9 @@
|
||||||
to="/instruments"
|
to="/instruments"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
@click.native="close">Instrumente
|
@click.native="close"
|
||||||
|
>
|
||||||
|
Instrumente
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -34,7 +38,9 @@
|
||||||
class="content-navigation__link"
|
class="content-navigation__link"
|
||||||
data-cy="news-navigation-link"
|
data-cy="news-navigation-link"
|
||||||
v-if="!me.readOnly"
|
v-if="!me.readOnly"
|
||||||
@click.native="close">News
|
@click.native="close"
|
||||||
|
>
|
||||||
|
News
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -45,7 +51,7 @@
|
||||||
data-cy="home-link"
|
data-cy="home-link"
|
||||||
v-if="!isSidebar"
|
v-if="!isSidebar"
|
||||||
>
|
>
|
||||||
<logo class="content-navigation__logo-icon"/>
|
<logo class="content-navigation__logo-icon" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<div class="content-navigation__secondary">
|
<div class="content-navigation__secondary">
|
||||||
|
|
@ -55,28 +61,35 @@
|
||||||
to="/rooms"
|
to="/rooms"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click.native="close">Räume
|
@click.native="close"
|
||||||
|
>
|
||||||
|
Räume
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="content-navigation__item content-navigation__item--secondary"
|
class="content-navigation__item content-navigation__item--secondary"
|
||||||
v-if="showPortfolio">
|
v-if="showPortfolio"
|
||||||
|
>
|
||||||
<router-link
|
<router-link
|
||||||
to="/portfolio"
|
to="/portfolio"
|
||||||
active-class="content-navigation__link--active"
|
active-class="content-navigation__link--active"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click.native="close">Portfolio
|
@click.native="close"
|
||||||
|
>
|
||||||
|
Portfolio
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="content-navigation__item content-navigation__item--secondary"
|
class="content-navigation__item content-navigation__item--secondary"
|
||||||
v-if="isSidebar">
|
v-if="isSidebar"
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
href="https://myskillbox.ch/support"
|
href="https://myskillbox.ch/support"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="content-navigation__link content-navigation__link--secondary"
|
class="content-navigation__link content-navigation__link--secondary"
|
||||||
@click="close">Support
|
@click="close"
|
||||||
|
>Support
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -84,12 +97,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Logo from '@/components/icons/Logo';
|
|
||||||
import BookTopicNavigation from '@/components/book-navigation/BookTopicNavigation';
|
import BookTopicNavigation from '@/components/book-navigation/BookTopicNavigation';
|
||||||
|
|
||||||
import sidebarMixin from '@/mixins/sidebar';
|
import sidebarMixin from '@/mixins/sidebar';
|
||||||
import meMixin from '@/mixins/me';
|
import meMixin from '@/mixins/me';
|
||||||
|
|
||||||
|
const Logo = () => import(/* webpackChunkName: "icons" */'@/components/icons/Logo');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
isSidebar: {
|
isSidebar: {
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,30 @@
|
||||||
<template>
|
<template>
|
||||||
<transition name="slide">
|
<transition name="slide">
|
||||||
<div
|
<div
|
||||||
v-click-outside="close"
|
|
||||||
class="navigation-sidebar"
|
class="navigation-sidebar"
|
||||||
v-if="sidebar.navigation"
|
v-if="sidebar.navigation"
|
||||||
|
v-click-outside="close"
|
||||||
>
|
>
|
||||||
<content-navigation
|
<content-navigation
|
||||||
:is-sidebar="true"
|
:is-sidebar="true"
|
||||||
class="navigation-sidebar__main"/>
|
class="navigation-sidebar__main"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="navigation-sidebar__close-button"
|
class="navigation-sidebar__close-button"
|
||||||
@click="close">
|
@click="close"
|
||||||
<cross class="navigation-sidebar__close-icon"/>
|
>
|
||||||
|
<cross class="navigation-sidebar__close-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Cross from '@/components/icons/Cross';
|
|
||||||
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
import ContentNavigation from '@/components/book-navigation/ContentNavigation';
|
||||||
|
|
||||||
import sidebarMixin from '@/mixins/sidebar';
|
import sidebarMixin from '@/mixins/sidebar';
|
||||||
|
|
||||||
import {meQuery} from '@/graphql/queries';
|
const Cross = () => import(/* webpackChunkName: "icons" */'@/components/icons/Cross');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [sidebarMixin],
|
mixins: [sidebarMixin],
|
||||||
|
|
@ -33,21 +34,12 @@
|
||||||
Cross
|
Cross
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
me: {}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
this.closeSidebar('navigation');
|
this.closeSidebar('navigation');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
apollo: {
|
|
||||||
me: meQuery
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{ 'sub-navigation-item--active': show}"
|
:class="{ 'sub-navigation-item--active': show}"
|
||||||
|
class="sub-navigation-item"
|
||||||
v-click-outside="close"
|
v-click-outside="close"
|
||||||
class="sub-navigation-item">
|
>
|
||||||
<div
|
<div
|
||||||
class="sub-navigation-item__title"
|
class="sub-navigation-item__title"
|
||||||
@click="show = !show">
|
@click="show = !show"
|
||||||
|
>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
<chevron-down class="sub-navigation-item__icon sub-navigation-item__chevron-down"/>
|
<chevron-down class="sub-navigation-item__icon sub-navigation-item__chevron-down" />
|
||||||
<chevron-up class="sub-navigation-item__icon sub-navigation-item__chevron-up"/>
|
<chevron-up class="sub-navigation-item__icon sub-navigation-item__chevron-up" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="sub-navigation-item__nav-items book-subnavigation"
|
class="sub-navigation-item__nav-items book-subnavigation"
|
||||||
v-if="show">
|
v-if="show"
|
||||||
<slot/>
|
>
|
||||||
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ChevronDown from '@/components/icons/ChevronDown';
|
const ChevronDown = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronDown');
|
||||||
import ChevronUp from '@/components/icons/ChevronUp';
|
const ChevronUp = () => import(/* webpackChunkName: "icons" */'@/components/icons/ChevronUp');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['title'],
|
props: ['title'],
|
||||||
|
|
@ -37,7 +40,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
$route(to, from) {
|
$route() {
|
||||||
this.show = false;
|
this.show = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
class="add-content-link"
|
||||||
|
@click="$emit('click')"
|
||||||
|
><plus-icon class="add-content-link__icon" /> <span class="add-content-link__text">Neuer Inhalt</span></a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import PlusIcon from '@/components/icons/PlusIcon';
|
||||||
|
export default {
|
||||||
|
components: { PlusIcon }
|
||||||
|
|
||||||
|
//
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
$color: $color-silver-dark;
|
||||||
|
|
||||||
|
.add-content-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
margin-right: $small-spacing;
|
||||||
|
fill: $color;
|
||||||
|
}
|
||||||
|
&__text {
|
||||||
|
// custom style, because the view needs this
|
||||||
|
@include link-base;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
<template>
|
||||||
|
<div class="content-element">
|
||||||
|
<content-block-element-chooser-widget
|
||||||
|
:class="['content-element__component', 'content-element__chooser']"
|
||||||
|
v-bind="element"
|
||||||
|
v-if="isChooser"
|
||||||
|
|
||||||
|
@change-type="changeType"
|
||||||
|
/>
|
||||||
|
<content-form-section
|
||||||
|
:title="title"
|
||||||
|
:icon="icon"
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
<div class="content-element__section">
|
||||||
|
<component
|
||||||
|
:class="['content-element__component']"
|
||||||
|
v-bind="element"
|
||||||
|
:is="component"
|
||||||
|
|
||||||
|
@change-text="changeText"
|
||||||
|
|
||||||
|
@link-change-url="changeUrl"
|
||||||
|
@change-url="changeUrl"
|
||||||
|
|
||||||
|
@switch-to-document="switchToDocument"
|
||||||
|
|
||||||
|
@assignment-change-title="changeAssignmentTitle"
|
||||||
|
@assignment-change-assignment="changeAssignmentAssignment"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="contents-form__remove icon-button"
|
||||||
|
@click="$emit('remove')"
|
||||||
|
>
|
||||||
|
<trash-icon
|
||||||
|
class="contents-form__trash-icon icon-button__icon"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</content-form-section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ContentFormSection from '@/components/content-block-form/ContentFormSection';
|
||||||
|
const TrashIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon');
|
||||||
|
const ContentBlockElementChooserWidget = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ContentBlockElementChooserWidget');
|
||||||
|
const LinkForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/LinkForm');
|
||||||
|
const VideoForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/VideoForm');
|
||||||
|
const ImageForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ImageForm');
|
||||||
|
const DocumentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/DocumentForm');
|
||||||
|
const AssignmentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/AssignmentForm');
|
||||||
|
const TextForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/TextForm');
|
||||||
|
|
||||||
|
const CHOOSER = 'content-block-element-chooser-widget';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
element: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ContentFormSection,
|
||||||
|
TrashIcon,
|
||||||
|
ContentBlockElementChooserWidget,
|
||||||
|
LinkForm,
|
||||||
|
VideoForm,
|
||||||
|
ImageForm,
|
||||||
|
DocumentForm,
|
||||||
|
AssignmentForm,
|
||||||
|
TextForm,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isChooser() {
|
||||||
|
return this.component === CHOOSER;
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
return this.getType(this.element);
|
||||||
|
},
|
||||||
|
component() {
|
||||||
|
return this.type.component;
|
||||||
|
},
|
||||||
|
title() {
|
||||||
|
return this.type.title;
|
||||||
|
},
|
||||||
|
icon() {
|
||||||
|
return this.type.icon;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getType(element) {
|
||||||
|
switch (element.type) {
|
||||||
|
case 'link_block':
|
||||||
|
return {
|
||||||
|
component: 'link-form',
|
||||||
|
title: 'Link',
|
||||||
|
icon: 'link-icon'
|
||||||
|
};
|
||||||
|
case 'video_block':
|
||||||
|
return {
|
||||||
|
component: 'video-form',
|
||||||
|
title: 'Video',
|
||||||
|
icon: 'video-icon'
|
||||||
|
};
|
||||||
|
case 'image_url_block':
|
||||||
|
return {
|
||||||
|
component: 'image-form',
|
||||||
|
title: 'Bild',
|
||||||
|
icon: 'image-icon'
|
||||||
|
};
|
||||||
|
case 'text_block':
|
||||||
|
return {
|
||||||
|
component: 'text-form',
|
||||||
|
title: 'Text',
|
||||||
|
icon: 'text-icon'
|
||||||
|
};
|
||||||
|
case 'assignment':
|
||||||
|
return {
|
||||||
|
component: 'assignment-form',
|
||||||
|
title: 'Aufgabe & Ergebnis',
|
||||||
|
icon: 'speech-bubble-icon'
|
||||||
|
};
|
||||||
|
case 'document_block':
|
||||||
|
return {
|
||||||
|
component: 'document-form',
|
||||||
|
title: 'Dokument',
|
||||||
|
icon: 'document-icon'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
component: CHOOSER,
|
||||||
|
title: '',
|
||||||
|
icon: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
_updateProperty(value, key) {
|
||||||
|
// const content = this.localContentBlock.contents[index];
|
||||||
|
const content = this.element;
|
||||||
|
this.update({
|
||||||
|
...content,
|
||||||
|
value: {
|
||||||
|
...content.value,
|
||||||
|
[key]: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
changeUrl(value) {
|
||||||
|
this._updateProperty(value, 'url');
|
||||||
|
},
|
||||||
|
changeText(value) {
|
||||||
|
this._updateProperty(value, 'text');
|
||||||
|
},
|
||||||
|
changeAssignmentTitle(value) {
|
||||||
|
this._updateProperty(value, 'title');
|
||||||
|
},
|
||||||
|
changeAssignmentAssignment(value) {
|
||||||
|
this._updateProperty(value, 'assignment');
|
||||||
|
},
|
||||||
|
changeType({type, convertToList}, value) {
|
||||||
|
let el = {
|
||||||
|
type: type,
|
||||||
|
value: Object.assign({}, value),
|
||||||
|
};
|
||||||
|
switch (type) {
|
||||||
|
case 'text_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
value: {
|
||||||
|
text: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'link_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
value: {
|
||||||
|
text: '',
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'video_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
value: {
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'document_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
value: Object.assign({
|
||||||
|
url: '',
|
||||||
|
}, value),
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'image_url_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
value: {
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convertToList) {
|
||||||
|
el = {
|
||||||
|
type: 'content_list_item',
|
||||||
|
contents: [el]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.update(el);
|
||||||
|
},
|
||||||
|
update(element) {
|
||||||
|
this.$emit('update', element);
|
||||||
|
},
|
||||||
|
switchToDocument(value) {
|
||||||
|
this.changeType('document_block', value);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.content-element {
|
||||||
|
&__section {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 50px;
|
||||||
|
grid-auto-rows: auto;
|
||||||
|
/*width: 95%; // reserve space for scrollbar*/
|
||||||
|
}
|
||||||
|
|
||||||
|
&__chooser {
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<template>
|
||||||
|
<div class="content-form-section">
|
||||||
|
<h2 class="content-form-section__heading">
|
||||||
|
<component
|
||||||
|
class="content-form-section__icon"
|
||||||
|
:is="icon"
|
||||||
|
/> <span class="content-form-section__title">{{ title }}</span>
|
||||||
|
</h2>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import formElementIcons from '@/components/ui/form-element-icons';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
...formElementIcons
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~styles/helpers';
|
||||||
|
|
||||||
|
.content-form-section {
|
||||||
|
@include default-box-shadow;
|
||||||
|
border-radius: $default-border-radius;
|
||||||
|
padding: $small-spacing $medium-spacing;
|
||||||
|
margin-bottom: $medium-spacing;
|
||||||
|
|
||||||
|
&__heading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
@include heading-4;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin-right: $small-spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<modal>
|
<modal>
|
||||||
<template slot="header">
|
<template #header>
|
||||||
<modal-input
|
<modal-input
|
||||||
:placeholder="titlePlaceholder"
|
:placeholder="titlePlaceholder"
|
||||||
:value="localContentBlock.title"
|
:value="localContentBlock.title"
|
||||||
|
|
@ -24,40 +24,15 @@
|
||||||
@add-element="addElement"
|
@add-element="addElement"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
:key="index"
|
|
||||||
class="contents-form__element"
|
class="contents-form__element"
|
||||||
v-for="(element, index) in localContentBlock.contents">
|
v-for="(element, index) in localContentBlock.contents"
|
||||||
<component
|
:key="index"
|
||||||
:is="type(element)"
|
>
|
||||||
:class="{'contents-form__chooser': type(element) === 'content-block-element-chooser-widget'}"
|
<content-element
|
||||||
v-bind="element"
|
:element="element"
|
||||||
:index="index"
|
@update="update(index, $event)"
|
||||||
class="contents-form__element-component"
|
@remove="remove(index)"
|
||||||
@change-type="changeType"
|
|
||||||
|
|
||||||
@link-change-url="changeLinkUrl"
|
|
||||||
@link-change-text="changeLinkText"
|
|
||||||
|
|
||||||
@text-change-value="changeTextValue"
|
|
||||||
|
|
||||||
@document-change-url="changeDocumentUrl"
|
|
||||||
|
|
||||||
@image-change-url="changeImageUrl"
|
|
||||||
|
|
||||||
@video-change-url="changeVideoUrl"
|
|
||||||
|
|
||||||
@switch-to-document="switchToDocument"
|
|
||||||
|
|
||||||
@assignment-change-title="changeAssignmentTitle"
|
|
||||||
@assignment-change-assignment="changeAssignmentAssignment"
|
|
||||||
/>
|
/>
|
||||||
<a
|
|
||||||
class="contents-form__remove icon-button"
|
|
||||||
@click="removeElement(index)">
|
|
||||||
<trash-icon
|
|
||||||
class="contents-form__trash-icon icon-button__icon"
|
|
||||||
v-if="type(element) !== 'content-block-element-chooser-widget'"/>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<add-content-element
|
<add-content-element
|
||||||
:index="index"
|
:index="index"
|
||||||
|
|
@ -66,65 +41,56 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div slot="footer">
|
<template #footer>
|
||||||
|
<div>
|
||||||
<a
|
<a
|
||||||
:class="{'button--disabled': disableSave}"
|
:class="{'button--disabled': disableSave}"
|
||||||
class="button button--primary"
|
class="button button--primary"
|
||||||
data-cy="modal-save-button"
|
data-cy="modal-save-button"
|
||||||
@click="save">Speichern</a>
|
@click="save"
|
||||||
|
>Speichern</a>
|
||||||
<a
|
<a
|
||||||
class="button"
|
class="button"
|
||||||
@click="$emit('hide')">Abbrechen</a>
|
@click="$emit('hide')"
|
||||||
|
>Abbrechen</a>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
|
||||||
import ContentBlockElementChooserWidget from '@/components/content-forms/ContentBlockElementChooserWidget';
|
|
||||||
import ModalInput from '@/components/ModalInput';
|
|
||||||
import AddContentElement from '@/components/AddContentElement';
|
|
||||||
import LinkForm from '@/components/content-forms/LinkForm';
|
|
||||||
import VideoForm from '@/components/content-forms/VideoForm';
|
|
||||||
import ImageForm from '@/components/content-forms/ImageForm';
|
|
||||||
import DocumentForm from '@/components/content-forms/DocumentForm';
|
|
||||||
import AssignmentForm from '@/components/content-forms/AssignmentForm';
|
|
||||||
import TextForm from '@/components/content-forms/TextForm';
|
|
||||||
import TrashIcon from '@/components/icons/TrashIcon';
|
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
|
||||||
|
|
||||||
import {meQuery} from '@/graphql/queries';
|
import {meQuery} from '@/graphql/queries';
|
||||||
|
|
||||||
|
const ModalInput = () => import(/* webpackChunkName: "content-forms" */'@/components/ModalInput');
|
||||||
|
const AddContentElement = () => import(/* webpackChunkName: "content-forms" */'@/components/AddContentElement');
|
||||||
|
const ContentElement = () => import(/* webpackChunkName: "content-forms" */'@/components/content-block-form/ContentElement');
|
||||||
|
|
||||||
|
const Modal = () => import('@/components/Modal');
|
||||||
|
const Checkbox = () => import('@/components/ui/Checkbox');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
'content-block': Object,
|
contentBlock: Object,
|
||||||
'block-type': {
|
blockType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'ContentBlock'
|
default: 'ContentBlock',
|
||||||
},
|
},
|
||||||
'show-task-selection': {
|
showTaskSelection: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
'disable-save': {
|
disableSave: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
ContentElement,
|
||||||
Modal,
|
Modal,
|
||||||
ContentBlockElementChooserWidget,
|
|
||||||
ModalInput,
|
ModalInput,
|
||||||
AddContentElement,
|
AddContentElement,
|
||||||
LinkForm,
|
Checkbox,
|
||||||
VideoForm,
|
|
||||||
ImageForm,
|
|
||||||
DocumentForm,
|
|
||||||
AssignmentForm,
|
|
||||||
TextForm,
|
|
||||||
TrashIcon,
|
|
||||||
Checkbox
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -134,14 +100,14 @@
|
||||||
title: this.contentBlock.title,
|
title: this.contentBlock.title,
|
||||||
contents: [...this.contentBlock.contents],
|
contents: [...this.contentBlock.contents],
|
||||||
id: this.contentBlock.id || undefined,
|
id: this.contentBlock.id || undefined,
|
||||||
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task'
|
isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
|
||||||
}),
|
}),
|
||||||
me: {}
|
me: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
apollo: {
|
apollo: {
|
||||||
me: meQuery
|
me: meQuery,
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -150,123 +116,15 @@
|
||||||
},
|
},
|
||||||
taskSelection() {
|
taskSelection() {
|
||||||
return this.showTaskSelection && this.me.permissions.includes('users.can_manage_school_class_content');
|
return this.showTaskSelection && this.me.permissions.includes('users.can_manage_school_class_content');
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
type(element) {
|
setContentBlockType(checked) {
|
||||||
switch (element.type) {
|
this.localContentBlock.isAssignment = checked;
|
||||||
case 'link_block':
|
|
||||||
return 'link-form';
|
|
||||||
case 'video_block':
|
|
||||||
return 'video-form';
|
|
||||||
case 'image_url_block':
|
|
||||||
return 'image-form';
|
|
||||||
case 'text_block':
|
|
||||||
return 'text-form';
|
|
||||||
case 'assignment':
|
|
||||||
return 'assignment-form';
|
|
||||||
case 'document_block':
|
|
||||||
return 'document-form';
|
|
||||||
}
|
|
||||||
return 'content-block-element-chooser-widget';
|
|
||||||
},
|
},
|
||||||
_updateProperty(value, index, key) {
|
update(index, element) {
|
||||||
const content = this.localContentBlock.contents[index];
|
this.localContentBlock.contents.splice(index, 1, element);
|
||||||
this.localContentBlock.contents.splice(index, 1, {
|
|
||||||
...content,
|
|
||||||
value: {
|
|
||||||
...content.value,
|
|
||||||
[key]: value
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
changeLinkUrl(value, index) {
|
|
||||||
this._updateProperty(value, index, 'url');
|
|
||||||
},
|
|
||||||
changeLinkText(value, index) {
|
|
||||||
this._updateProperty(value, index, 'text');
|
|
||||||
},
|
|
||||||
changeVideoUrl(value, index) {
|
|
||||||
this._updateProperty(value, index, 'url');
|
|
||||||
},
|
|
||||||
changeImageUrl(value, index) {
|
|
||||||
this._updateProperty(value, index, 'url');
|
|
||||||
},
|
|
||||||
changeDocumentUrl(value, index) {
|
|
||||||
this._updateProperty(value, index, 'url');
|
|
||||||
},
|
|
||||||
changeTextValue(value, index) {
|
|
||||||
this._updateProperty(value, index, 'text');
|
|
||||||
},
|
|
||||||
changeAssignmentTitle(value, index) {
|
|
||||||
this._updateProperty(value, index, 'title');
|
|
||||||
},
|
|
||||||
changeAssignmentAssignment(value, index) {
|
|
||||||
this._updateProperty(value, index, 'assignment');
|
|
||||||
},
|
|
||||||
removeElement(index) {
|
|
||||||
this.localContentBlock.contents.splice(index, 1);
|
|
||||||
},
|
|
||||||
addElement(index) {
|
|
||||||
this.localContentBlock.contents.splice(index + 1, 0, {
|
|
||||||
hideAssignment: this.blockType !== 'ContentBlock'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateTitle(title) {
|
|
||||||
this.localContentBlock.title = title;
|
|
||||||
this.error = false;
|
|
||||||
},
|
|
||||||
changeType(index, type, value) {
|
|
||||||
let el = {
|
|
||||||
type: type,
|
|
||||||
value: Object.assign({}, value)
|
|
||||||
};
|
|
||||||
switch (type) {
|
|
||||||
case 'text_block':
|
|
||||||
el = {
|
|
||||||
...el,
|
|
||||||
value: {
|
|
||||||
text: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'link_block':
|
|
||||||
el = {
|
|
||||||
...el,
|
|
||||||
value: {
|
|
||||||
text: '',
|
|
||||||
url: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'video_block':
|
|
||||||
el = {
|
|
||||||
...el,
|
|
||||||
value: {
|
|
||||||
url: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'document_block':
|
|
||||||
el = {
|
|
||||||
...el,
|
|
||||||
value: Object.assign({
|
|
||||||
url: ''
|
|
||||||
}, value)
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case 'image_url_block':
|
|
||||||
el = {
|
|
||||||
...el,
|
|
||||||
value: {
|
|
||||||
url: ''
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.localContentBlock.contents.splice(index, 1, el);
|
|
||||||
},
|
},
|
||||||
save() {
|
save() {
|
||||||
if (!this.disableSave) {
|
if (!this.disableSave) {
|
||||||
|
|
@ -277,27 +135,31 @@
|
||||||
this.$emit('save', this.localContentBlock);
|
this.$emit('save', this.localContentBlock);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setContentBlockType(checked, localContentBlock) {
|
updateTitle(title) {
|
||||||
this.localContentBlock.isAssignment = checked;
|
this.localContentBlock.title = title;
|
||||||
|
this.error = false;
|
||||||
|
},
|
||||||
|
addElement(index) {
|
||||||
|
this.localContentBlock.contents.splice(index + 1, 0, {
|
||||||
|
hideAssignment: this.blockType !== 'ContentBlock',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
remove(index) {
|
||||||
|
this.localContentBlock.contents.splice(index, 1);
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
switchToDocument(index, value) {
|
|
||||||
this.changeType(index, 'document_block', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
|
|
||||||
.contents-form {
|
.contents-form {
|
||||||
/* top level does not exist, because of the modal */
|
/* top level does not exist, because of the modal */
|
||||||
|
|
||||||
&__element {
|
&__element {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 50px;
|
|
||||||
grid-auto-rows: auto;
|
|
||||||
/*width: 95%; // reserve space for scrollbar*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__element-component {
|
&__element-component {
|
||||||
|
|
@ -310,10 +172,6 @@
|
||||||
&__trash-icon {
|
&__trash-icon {
|
||||||
}
|
}
|
||||||
|
|
||||||
&__chooser {
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__add {
|
&__add {
|
||||||
grid-column: 1 / span 2;
|
grid-column: 1 / span 2;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<div
|
<div
|
||||||
:class="componentClass"
|
:class="componentClass"
|
||||||
:data-scrollto="component.id"
|
:data-scrollto="component.id"
|
||||||
|
data-cy="content-component"
|
||||||
>
|
>
|
||||||
<bookmark-actions
|
<bookmark-actions
|
||||||
:bookmarked="bookmarked"
|
:bookmarked="bookmarked"
|
||||||
|
|
@ -9,11 +10,12 @@
|
||||||
v-if="showBookmarkActions"
|
v-if="showBookmarkActions"
|
||||||
@add-note="addNote(component.id)"
|
@add-note="addNote(component.id)"
|
||||||
@edit-note="editNote"
|
@edit-note="editNote"
|
||||||
@bookmark="bookmarkContent(component.id, !bookmarked)"/>
|
@bookmark="bookmarkContent(component.id, !bookmarked)"
|
||||||
|
/>
|
||||||
<component
|
<component
|
||||||
:is="component.type"
|
|
||||||
v-bind="component"
|
v-bind="component"
|
||||||
:parent="parent"
|
:parent="parent"
|
||||||
|
:is="component.type"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -21,28 +23,28 @@
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from 'vuex';
|
import {mapState} from 'vuex';
|
||||||
|
|
||||||
import TextBlock from '@/components/content-blocks/TextBlock';
|
|
||||||
import InstrumentWidget from '@/components/content-blocks/InstrumentWidget';
|
|
||||||
import ImageBlock from '@/components/content-blocks/ImageBlock';
|
|
||||||
import ImageUrlBlock from '@/components/content-blocks/ImageUrlBlock';
|
|
||||||
import VideoBlock from '@/components/content-blocks/VideoBlock';
|
|
||||||
import LinkBlock from '@/components/content-blocks/LinkBlock';
|
|
||||||
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
|
||||||
import InfogramBlock from '@/components/content-blocks/InfogramBlock';
|
|
||||||
import ThinglinkBlock from '@/components/content-blocks/ThinglinkBlock';
|
|
||||||
import GeniallyBlock from '@/components/content-blocks/GeniallyBlock';
|
|
||||||
import SubtitleBlock from '@/components/content-blocks/SubtitleBlock';
|
|
||||||
import SectionTitleBlock from '@/components/content-blocks/SectionTitleBlock';
|
|
||||||
import ContentListBlock from '@/components/content-blocks/ContentListBlock';
|
|
||||||
import ModuleRoomSlug from '@/components/content-blocks/ModuleRoomSlug';
|
|
||||||
import Assignment from '@/components/content-blocks/assignment/Assignment';
|
|
||||||
import Survey from '@/components/content-blocks/SurveyBlock';
|
|
||||||
import Solution from '@/components/content-blocks/Solution';
|
|
||||||
import Instruction from '@/components/content-blocks/Instruction';
|
|
||||||
import BookmarkActions from '@/components/notes/BookmarkActions';
|
|
||||||
|
|
||||||
import {constructContentComponentBookmarkMutation} from '@/helpers/update-content-bookmark-mutation';
|
import {constructContentComponentBookmarkMutation} from '@/helpers/update-content-bookmark-mutation';
|
||||||
|
|
||||||
|
const TextBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/TextBlock');
|
||||||
|
const InstrumentWidget = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InstrumentWidget');
|
||||||
|
const ImageBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ImageBlock');
|
||||||
|
const ImageUrlBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ImageUrlBlock');
|
||||||
|
const VideoBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/VideoBlock');
|
||||||
|
const LinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/LinkBlock');
|
||||||
|
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');
|
||||||
|
const InfogramBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/InfogramBlock');
|
||||||
|
const ThinglinkBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ThinglinkBlock');
|
||||||
|
const GeniallyBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/GeniallyBlock');
|
||||||
|
const SubtitleBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SubtitleBlock');
|
||||||
|
const SectionTitleBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SectionTitleBlock');
|
||||||
|
const ContentListBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ContentListBlock');
|
||||||
|
const ModuleRoomSlug = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/ModuleRoomSlug');
|
||||||
|
const Assignment = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/Assignment');
|
||||||
|
const Survey = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/SurveyBlock');
|
||||||
|
const Solution = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Solution');
|
||||||
|
const Instruction = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Instruction');
|
||||||
|
const BookmarkActions = () => import(/* webpackChunkName: "content-components" */'@/components/notes/BookmarkActions');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['component', 'parent', 'bookmarks', 'notes', 'root'],
|
props: ['component', 'parent', 'bookmarks', 'notes', 'root'],
|
||||||
|
|
||||||
|
|
@ -92,13 +94,12 @@ export default {
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
addNote(id) {
|
addNote(id) {
|
||||||
if (!this.parent.hasOwnProperty('__typename')) {
|
const type = Object.prototype.hasOwnProperty.call(this.parent, '__typename')
|
||||||
this.parent.__typename = 'ContentBlockNode';
|
? this.parent.__typename : 'ContentBlockNode';
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.dispatch('addNote', {
|
this.$store.dispatch('addNote', {
|
||||||
content: id,
|
content: id,
|
||||||
type: this.parent.__typename,
|
type,
|
||||||
block: this.root
|
block: this.root
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<template>
|
||||||
|
<ol class="content-list">
|
||||||
|
<li
|
||||||
|
class="content-list__item"
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="item.id"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
:item="item"
|
||||||
|
:index="index"
|
||||||
|
>
|
||||||
|
{{ item.id }}
|
||||||
|
</slot>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
//
|
||||||
|
props: {
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -1,32 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content-list-block__container">
|
<content-list
|
||||||
<div class="content-list-wrapper">
|
:items="contentBlocks"
|
||||||
<ol class="content-list">
|
:starting-index="startingIndex"
|
||||||
<li
|
>
|
||||||
:key="contentBlock.id"
|
<template #default="{ item }">
|
||||||
class="content-list__item contentlist-item"
|
|
||||||
v-for="(contentBlock, index) in contentBlocks">
|
|
||||||
<p class="content-list__numbering">{{ alphaIndex(index) }})</p>
|
|
||||||
<content-block
|
<content-block
|
||||||
:content-block="contentBlock"
|
:content-block="item"
|
||||||
:parent="parent"
|
:parent="parent"
|
||||||
/>
|
/>
|
||||||
</li>
|
</template>
|
||||||
</ol>
|
</content-list>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const lowerAsciiA = 97;
|
import ContentList from '@/components/content-blocks/ContentList';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ContentBlockList',
|
name: 'ContentBlockList',
|
||||||
props: ['contents', 'parent', 'startingIndex'],
|
props: ['contents', 'parent', 'startingIndex'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
|
ContentList,
|
||||||
// https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
// https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
||||||
ContentBlock: () => import('@/components/ContentBlock')
|
ContentBlock: () => import('@/components/ContentBlock')
|
||||||
},
|
},
|
||||||
|
|
@ -34,8 +28,9 @@
|
||||||
computed: {
|
computed: {
|
||||||
contentBlocks() {
|
contentBlocks() {
|
||||||
return this.contents.map(contentBlock => {
|
return this.contents.map(contentBlock => {
|
||||||
|
const contents = contentBlock.value ? [...contentBlock.value] : [];
|
||||||
return Object.assign({}, contentBlock, {
|
return Object.assign({}, contentBlock, {
|
||||||
contents: [...contentBlock.value],
|
contents,
|
||||||
indent: true,
|
indent: true,
|
||||||
bookmarks: this.parent.bookmarks,
|
bookmarks: this.parent.bookmarks,
|
||||||
notes: this.parent.notes,
|
notes: this.parent.notes,
|
||||||
|
|
@ -45,36 +40,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
};
|
||||||
alphaIndex(index) {
|
|
||||||
return String.fromCharCode(lowerAsciiA + this.startingIndex + index);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@/styles/_variables.scss";
|
@import "~styles/helpers";
|
||||||
@import "@/styles/_mixins.scss";
|
|
||||||
|
|
||||||
.content-list-wrapper {
|
|
||||||
.content-list {
|
|
||||||
/* https://stackoverflow.com/questions/1632005/ordered-list-html-lower-alpha-with-right-parentheses */
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
list-style: none;
|
|
||||||
position: relative;
|
|
||||||
padding: 0 0 0 2*15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__numbering {
|
|
||||||
position: absolute;
|
|
||||||
font-weight: 600;
|
|
||||||
left: 0;
|
|
||||||
color: $color-brand;
|
|
||||||
line-height: 27px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="document-block">
|
<div class="document-block">
|
||||||
<document-icon class="document-block__icon"/>
|
<document-icon class="document-block__icon" />
|
||||||
<a
|
<a
|
||||||
:href="value.url"
|
:href="value.url"
|
||||||
class="document-block__link"
|
class="document-block__link"
|
||||||
target="_blank">{{ urlName }}</a>
|
target="_blank"
|
||||||
|
>{{ urlName }}</a>
|
||||||
<a
|
<a
|
||||||
class="document-block__remove"
|
class="document-block__remove"
|
||||||
v-if="showTrashIcon"
|
v-if="showTrashIcon"
|
||||||
@click="$emit('trash')">
|
@click="$emit('trash')"
|
||||||
<trash-icon class="document-block__trash-icon"/>
|
>
|
||||||
|
<trash-icon class="document-block__trash-icon" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocumentIcon from '@/components/icons/DocumentIcon';
|
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
|
||||||
import TrashIcon from '@/components/icons/TrashIcon';
|
const TrashIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@
|
||||||
allowscriptaccess="always"
|
allowscriptaccess="always"
|
||||||
allowfullscreen="true"
|
allowfullscreen="true"
|
||||||
scrolling="yes"
|
scrolling="yes"
|
||||||
allownetworking="all"/>
|
allownetworking="all"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
:src="value.path"
|
:src="value.path"
|
||||||
alt=""
|
alt=""
|
||||||
class="image-block"
|
class="image-block"
|
||||||
@click="openFullscreen">
|
@click="openFullscreen"
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
:src="value.url"
|
:src="value.url"
|
||||||
alt=""
|
alt=""
|
||||||
class="image-block"
|
class="image-block"
|
||||||
@click="openFullscreen">
|
@click="openFullscreen"
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
class="infogram-block__iframe"
|
class="infogram-block__iframe"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
style="border:none;"/>
|
style="border:none;"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="instruction"
|
class="instruction"
|
||||||
v-if="me.isTeacher">
|
v-if="me.isTeacher"
|
||||||
<bulb-icon class="instruction__icon"/>
|
>
|
||||||
|
<bulb-icon class="instruction__icon" />
|
||||||
<a
|
<a
|
||||||
:href="value.url"
|
:href="value.url"
|
||||||
class="instruction__link">{{ text }}</a>
|
class="instruction__link"
|
||||||
|
>{{ text }}</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import me from '@/mixins/me';
|
import me from '@/mixins/me';
|
||||||
import BulbIcon from '@/components/icons/BulbIcon';
|
const BulbIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/BulbIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="instrument-widget">
|
<div class="instrument-widget">
|
||||||
<div
|
<div
|
||||||
class="instrument-widget__description"
|
class="instrument-widget__description"
|
||||||
v-html="value.description"/>
|
v-html="value.description"
|
||||||
|
/>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'instrument', params: { slug: value.slug }}"
|
:to="{name: 'instrument', params: { slug: value.slug }}"
|
||||||
class="instrument-widget__button button">Instrument anzeigen
|
class="instrument-widget__button button"
|
||||||
|
>
|
||||||
|
Instrument anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{ 'link-block--no-margin': noMargin}"
|
:class="{ 'link-block--no-margin': noMargin}"
|
||||||
class="link-block">
|
class="link-block"
|
||||||
<link-icon class="link-block__icon"/>
|
>
|
||||||
|
<link-icon class="link-block__icon" />
|
||||||
<a
|
<a
|
||||||
:href="href"
|
:href="href"
|
||||||
class="link-block__link"
|
class="link-block__link"
|
||||||
target="_blank">{{ value.text }}</a>
|
target="_blank"
|
||||||
|
>{{ value.text }}</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LinkIcon from '@/components/icons/LinkIcon';
|
const LinkIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/LinkIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: Object,
|
value: Object,
|
||||||
'no-margin': {
|
noMargin: {
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
<div class="module-slug">
|
<div class="module-slug">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'moduleRoom', params: { slug: value.slug }}"
|
:to="{name: 'moduleRoom', params: { slug: value.slug }}"
|
||||||
class="button button--primary">Raum anzeigen
|
class="button button--primary"
|
||||||
|
>
|
||||||
|
Raum anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<h4
|
<h4
|
||||||
class="section-title"
|
class="section-title"
|
||||||
v-html="value.text"/>
|
v-html="value.text"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="solution"
|
class="solution"
|
||||||
data-cy="solution">
|
data-cy="solution"
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
class="solution__toggle"
|
class="solution__toggle"
|
||||||
data-cy="show-solution"
|
data-cy="show-solution"
|
||||||
@click="toggle">Lösung
|
@click="toggle"
|
||||||
|
>Lösung
|
||||||
<template v-if="!visible">anzeigen</template>
|
<template v-if="!visible">anzeigen</template>
|
||||||
<template v-else>ausblenden</template>
|
<template v-else>ausblenden</template>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -15,7 +17,8 @@
|
||||||
data-cy="solution-text"
|
data-cy="solution-text"
|
||||||
|
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
v-html="value.text"/>
|
v-html="value.text"
|
||||||
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<h5
|
<h5
|
||||||
class="subtitle"
|
class="subtitle"
|
||||||
v-html="value.text"/>
|
v-html="value.text"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
//todo: esacpe value.text
|
||||||
export default {
|
export default {
|
||||||
props: ['value']
|
props: ['value']
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:data-scrollto="value.id"
|
:data-scrollto="value.id"
|
||||||
class="survey-block">
|
class="survey-block"
|
||||||
|
>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'survey', params: {id:value.id}}"
|
:to="{name: 'survey', params: {id:value.id}}"
|
||||||
class="button button--primary">Übung anzeigen
|
class="button button--primary"
|
||||||
|
>
|
||||||
|
Übung anzeigen
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div class="task">
|
<div class="task">
|
||||||
<div
|
<div
|
||||||
class="task__text"
|
class="task__text"
|
||||||
v-html="value.text"/>
|
v-html="value.text"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="text-block"
|
class="text-block"
|
||||||
v-html="value.text"/>
|
v-html="value.text"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// todo: escape text maybe
|
||||||
export default {
|
export default {
|
||||||
props: ['value']
|
props: ['value']
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
allowscriptaccess="always"
|
allowscriptaccess="always"
|
||||||
allowfullscreen="true"
|
allowfullscreen="true"
|
||||||
allownetworking="all"/>
|
allownetworking="all"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@
|
||||||
<div class="video-block">
|
<div class="video-block">
|
||||||
<youtube-embed
|
<youtube-embed
|
||||||
:url="value.url"
|
:url="value.url"
|
||||||
v-if="isYoutube"/>
|
v-if="isYoutube"
|
||||||
|
/>
|
||||||
<vimeo-embed
|
<vimeo-embed
|
||||||
:url="value.url"
|
:url="value.url"
|
||||||
v-if="isVimeo"/>
|
v-if="isVimeo"
|
||||||
|
/>
|
||||||
<srf-embed
|
<srf-embed
|
||||||
:url="value.url"
|
:url="value.url"
|
||||||
v-if="isSrf"/>
|
v-if="isSrf"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:data-scrollto="value.id"
|
:data-scrollto="value.id"
|
||||||
class="assignment">
|
class="assignment"
|
||||||
|
>
|
||||||
<p class="assignment__assignment-text">
|
<p class="assignment__assignment-text">
|
||||||
{{ assignment.assignment }}
|
{{ assignment.assignment }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<solution
|
<solution
|
||||||
:value="solution"
|
:value="solution"
|
||||||
v-if="assignment.solution"/>
|
v-if="assignment.solution"
|
||||||
|
/>
|
||||||
|
|
||||||
<template v-if="isStudent">
|
<template v-if="isStudent">
|
||||||
<submission-form
|
<submission-form
|
||||||
|
|
@ -30,17 +32,21 @@
|
||||||
|
|
||||||
<spell-check
|
<spell-check
|
||||||
:corrections="corrections"
|
:corrections="corrections"
|
||||||
:text="submission.text"/>
|
:text="submission.text"
|
||||||
|
/>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
class="assignment__feedback"
|
class="assignment__feedback"
|
||||||
v-if="assignment.submission.submissionFeedback"
|
v-if="assignment.submission.submissionFeedback"
|
||||||
v-html="feedbackText"/>
|
v-html="feedbackText"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!isStudent">
|
<template v-if="!isStudent">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{name: 'submissions', params: { id: assignment.id }}"
|
:to="{name: 'submissions', params: { id: assignment.id }}"
|
||||||
class="button button--primary">Zu den
|
class="button button--primary"
|
||||||
|
>
|
||||||
|
Zu den
|
||||||
Ergebnissen
|
Ergebnissen
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -57,9 +63,9 @@
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
|
||||||
import SubmissionForm from '@/components/content-blocks/assignment/SubmissionForm';
|
const SubmissionForm = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SubmissionForm');
|
||||||
import Solution from '@/components/content-blocks/Solution';
|
const Solution = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/Solution');
|
||||||
import SpellCheck from '@/components/content-blocks/assignment/SpellCheck';
|
const SpellCheck = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/assignment/SpellCheck');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
@ -106,6 +112,7 @@
|
||||||
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
|
return this.assignment.id ? this.assignment.id.replace(/=/g, '') : '';
|
||||||
},
|
},
|
||||||
feedbackText() {
|
feedbackText() {
|
||||||
|
// todo: should we maybe clean up this feedback text?
|
||||||
let feedback = this.assignment.submission.submissionFeedback;
|
let feedback = this.assignment.submission.submissionFeedback;
|
||||||
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${feedback.text}`;
|
return `<span class="inline-title">Feedback von ${feedback.teacher.firstName} ${feedback.teacher.lastName}:</span> ${feedback.text}`;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="final-submission"
|
class="final-submission"
|
||||||
data-cy="final-submission">
|
data-cy="final-submission"
|
||||||
|
>
|
||||||
<document-block
|
<document-block
|
||||||
:value="{url: userInput.document}"
|
:value="{url: userInput.document}"
|
||||||
class="final-submission__document"
|
class="final-submission__document"
|
||||||
v-if="userInput.document"
|
v-if="userInput.document"
|
||||||
/>
|
/>
|
||||||
<div class="final-submission__explanation">
|
<div class="final-submission__explanation">
|
||||||
<info-icon class="final-submission__explanation-icon"/>
|
<info-icon class="final-submission__explanation-icon" />
|
||||||
<span class="final-submission__explanation-text">{{ sharedMsg }}</span>
|
<span class="final-submission__explanation-text">{{ sharedMsg }}</span>
|
||||||
<a
|
<a
|
||||||
class="final-submission__reopen"
|
class="final-submission__reopen"
|
||||||
data-cy="final-submission-reopen"
|
data-cy="final-submission-reopen"
|
||||||
v-if="showReopen"
|
v-if="showReopen"
|
||||||
@click="$emit('reopen')">Bearbeiten</a>
|
@click="$emit('reopen')"
|
||||||
|
>Bearbeiten</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InfoIcon from '@/components/icons/InfoIcon';
|
|
||||||
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
|
||||||
import {newLineToParagraph} from '@/helpers/text';
|
import {newLineToParagraph} from '@/helpers/text';
|
||||||
|
const DocumentBlock = () => import(/* webpackChunkName: "content-components" */'@/components/content-blocks/DocumentBlock');
|
||||||
|
|
||||||
|
const InfoIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/InfoIcon');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<p
|
<p
|
||||||
class="spellcheck"
|
class="spellcheck"
|
||||||
v-if="corrections">
|
v-if="corrections"
|
||||||
<span class="inline-title">Rechtschreibung:</span> <span v-html="highlightedText"/>
|
>
|
||||||
|
<span class="inline-title">Rechtschreibung:</span> <span v-html="highlightedText" />
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,25 +12,29 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="submission-form-container__actions"
|
class="submission-form-container__actions"
|
||||||
v-if="!isFinalOrReadOnly">
|
v-if="!isFinalOrReadOnly"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
class="submission-form-container__submit button button--primary button--white-bg"
|
class="submission-form-container__submit button button--primary button--white-bg"
|
||||||
data-cy="submission-form-submit"
|
data-cy="submission-form-submit"
|
||||||
@click="$emit('turnIn')"
|
@click="$emit('turnIn')"
|
||||||
>{{ action }}
|
>
|
||||||
|
{{ action }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="submission-form-container__submit submission-form-container__spellcheck button button--primary button--white-bg"
|
class="submission-form-container__submit submission-form-container__spellcheck button button--primary button--white-bg"
|
||||||
data-cy="spellcheck-button"
|
data-cy="spellcheck-button"
|
||||||
v-if="showSpellcheckButton"
|
v-if="showSpellcheckButton"
|
||||||
@click="$emit('spellcheck')"
|
@click="$emit('spellcheck')"
|
||||||
>{{ spellcheckText }}
|
>
|
||||||
|
{{ spellcheckText }}
|
||||||
</button>
|
</button>
|
||||||
<file-upload
|
<file-upload
|
||||||
:document="userInput.document"
|
:document="userInput.document"
|
||||||
v-if="allowsDocuments"
|
v-if="allowsDocuments"
|
||||||
@change-document-url="changeDocumentUrl"/>
|
@change-document-url="changeDocumentUrl"
|
||||||
<slot/>
|
/>
|
||||||
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<final-submission
|
<final-submission
|
||||||
|
|
@ -38,15 +42,16 @@
|
||||||
:shared-msg="sharedMsg"
|
:shared-msg="sharedMsg"
|
||||||
:show-reopen="!readOnly"
|
:show-reopen="!readOnly"
|
||||||
v-if="isFinalOrReadOnly"
|
v-if="isFinalOrReadOnly"
|
||||||
@reopen="$emit('reopen')"/>
|
@reopen="$emit('reopen')"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SubmissionInput from '@/components/content-blocks/assignment/SubmissionInput';
|
const SubmissionInput = () => import('@/components/content-blocks/assignment/SubmissionInput');
|
||||||
import FinalSubmission from '@/components/content-blocks/assignment/FinalSubmission';
|
const FinalSubmission = () => import('@/components/content-blocks/assignment/FinalSubmission');
|
||||||
import DocumentBlock from '@/components/content-blocks/DocumentBlock';
|
const FileUpload = () => import('@/components/ui/file-upload/FileUpload');
|
||||||
import FileUpload from '@/components/ui/file-upload/FileUpload';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -75,7 +80,6 @@
|
||||||
FileUpload,
|
FileUpload,
|
||||||
SubmissionInput,
|
SubmissionInput,
|
||||||
FinalSubmission,
|
FinalSubmission,
|
||||||
DocumentBlock,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue