forked from kristjan/cjvt-valency
frontend_vue -- set up dev/prod container
This commit is contained in:
parent
2d4a6a152a
commit
e5b6f02abd
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
data/samples/
|
data/samples/
|
||||||
*egg-info/
|
*egg-info/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
src/frontend_vue/node_modules/
|
||||||
|
|
21
src/frontend_vue/README.md
Normal file
21
src/frontend_vue/README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# vue_frontend
|
||||||
|
|
||||||
|
> Frontend for Valency App.
|
||||||
|
|
||||||
|
## Build Setup
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
# install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# serve with hot reload at localhost:8080
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# build for production with minification
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# build for production and view the bundle analyzer report
|
||||||
|
npm run build --report
|
||||||
|
```
|
||||||
|
|
||||||
|
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
|
41
src/frontend_vue/build/build.js
Normal file
41
src/frontend_vue/build/build.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
'use strict'
|
||||||
|
require('./check-versions')()
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
const ora = require('ora')
|
||||||
|
const rm = require('rimraf')
|
||||||
|
const path = require('path')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const webpackConfig = require('./webpack.prod.conf')
|
||||||
|
|
||||||
|
const spinner = ora('building for production...')
|
||||||
|
spinner.start()
|
||||||
|
|
||||||
|
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||||
|
if (err) throw err
|
||||||
|
webpack(webpackConfig, (err, stats) => {
|
||||||
|
spinner.stop()
|
||||||
|
if (err) throw err
|
||||||
|
process.stdout.write(stats.toString({
|
||||||
|
colors: true,
|
||||||
|
modules: false,
|
||||||
|
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
|
||||||
|
chunks: false,
|
||||||
|
chunkModules: false
|
||||||
|
}) + '\n\n')
|
||||||
|
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
console.log(chalk.red(' Build failed with errors.\n'))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.cyan(' Build complete.\n'))
|
||||||
|
console.log(chalk.yellow(
|
||||||
|
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||||
|
' Opening index.html over file:// won\'t work.\n'
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
54
src/frontend_vue/build/check-versions.js
Normal file
54
src/frontend_vue/build/check-versions.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
'use strict'
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const semver = require('semver')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
const shell = require('shelljs')
|
||||||
|
|
||||||
|
function exec (cmd) {
|
||||||
|
return require('child_process').execSync(cmd).toString().trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
const versionRequirements = [
|
||||||
|
{
|
||||||
|
name: 'node',
|
||||||
|
currentVersion: semver.clean(process.version),
|
||||||
|
versionRequirement: packageConfig.engines.node
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if (shell.which('npm')) {
|
||||||
|
versionRequirements.push({
|
||||||
|
name: 'npm',
|
||||||
|
currentVersion: exec('npm --version'),
|
||||||
|
versionRequirement: packageConfig.engines.npm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
const warnings = []
|
||||||
|
|
||||||
|
for (let i = 0; i < versionRequirements.length; i++) {
|
||||||
|
const mod = versionRequirements[i]
|
||||||
|
|
||||||
|
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||||
|
warnings.push(mod.name + ': ' +
|
||||||
|
chalk.red(mod.currentVersion) + ' should be ' +
|
||||||
|
chalk.green(mod.versionRequirement)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log('')
|
||||||
|
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
for (let i = 0; i < warnings.length; i++) {
|
||||||
|
const warning = warnings[i]
|
||||||
|
console.log(' ' + warning)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log()
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
BIN
src/frontend_vue/build/logo.png
Normal file
BIN
src/frontend_vue/build/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
101
src/frontend_vue/build/utils.js
Normal file
101
src/frontend_vue/build/utils.js
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const config = require('../config')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
|
||||||
|
exports.assetsPath = function (_path) {
|
||||||
|
const assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||||
|
? config.build.assetsSubDirectory
|
||||||
|
: config.dev.assetsSubDirectory
|
||||||
|
|
||||||
|
return path.posix.join(assetsSubDirectory, _path)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.cssLoaders = function (options) {
|
||||||
|
options = options || {}
|
||||||
|
|
||||||
|
const cssLoader = {
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const postcssLoader = {
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate loader string to be used with extract text plugin
|
||||||
|
function generateLoaders (loader, loaderOptions) {
|
||||||
|
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
|
||||||
|
|
||||||
|
if (loader) {
|
||||||
|
loaders.push({
|
||||||
|
loader: loader + '-loader',
|
||||||
|
options: Object.assign({}, loaderOptions, {
|
||||||
|
sourceMap: options.sourceMap
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract CSS when that option is specified
|
||||||
|
// (which is the case during production build)
|
||||||
|
if (options.extract) {
|
||||||
|
return ExtractTextPlugin.extract({
|
||||||
|
use: loaders,
|
||||||
|
fallback: 'vue-style-loader'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return ['vue-style-loader'].concat(loaders)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||||
|
return {
|
||||||
|
css: generateLoaders(),
|
||||||
|
postcss: generateLoaders(),
|
||||||
|
less: generateLoaders('less'),
|
||||||
|
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||||
|
scss: generateLoaders('sass'),
|
||||||
|
stylus: generateLoaders('stylus'),
|
||||||
|
styl: generateLoaders('stylus')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate loaders for standalone style files (outside of .vue)
|
||||||
|
exports.styleLoaders = function (options) {
|
||||||
|
const output = []
|
||||||
|
const loaders = exports.cssLoaders(options)
|
||||||
|
|
||||||
|
for (const extension in loaders) {
|
||||||
|
const loader = loaders[extension]
|
||||||
|
output.push({
|
||||||
|
test: new RegExp('\\.' + extension + '$'),
|
||||||
|
use: loader
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createNotifierCallback = () => {
|
||||||
|
const notifier = require('node-notifier')
|
||||||
|
|
||||||
|
return (severity, errors) => {
|
||||||
|
if (severity !== 'error') return
|
||||||
|
|
||||||
|
const error = errors[0]
|
||||||
|
const filename = error.file && error.file.split('!').pop()
|
||||||
|
|
||||||
|
notifier.notify({
|
||||||
|
title: packageConfig.name,
|
||||||
|
message: severity + ': ' + error.name,
|
||||||
|
subtitle: filename || '',
|
||||||
|
icon: path.join(__dirname, 'logo.png')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
22
src/frontend_vue/build/vue-loader.conf.js
Normal file
22
src/frontend_vue/build/vue-loader.conf.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict'
|
||||||
|
const utils = require('./utils')
|
||||||
|
const config = require('../config')
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production'
|
||||||
|
const sourceMapEnabled = isProduction
|
||||||
|
? config.build.productionSourceMap
|
||||||
|
: config.dev.cssSourceMap
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loaders: utils.cssLoaders({
|
||||||
|
sourceMap: sourceMapEnabled,
|
||||||
|
extract: isProduction
|
||||||
|
}),
|
||||||
|
cssSourceMap: sourceMapEnabled,
|
||||||
|
cacheBusting: config.dev.cacheBusting,
|
||||||
|
transformToRequire: {
|
||||||
|
video: ['src', 'poster'],
|
||||||
|
source: 'src',
|
||||||
|
img: 'src',
|
||||||
|
image: 'xlink:href'
|
||||||
|
}
|
||||||
|
}
|
82
src/frontend_vue/build/webpack.base.conf.js
Normal file
82
src/frontend_vue/build/webpack.base.conf.js
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const utils = require('./utils')
|
||||||
|
const config = require('../config')
|
||||||
|
const vueLoaderConfig = require('./vue-loader.conf')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
context: path.resolve(__dirname, '../'),
|
||||||
|
entry: {
|
||||||
|
app: './src/main.js'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: config.build.assetsRoot,
|
||||||
|
filename: '[name].js',
|
||||||
|
publicPath: process.env.NODE_ENV === 'production'
|
||||||
|
? config.build.assetsPublicPath
|
||||||
|
: config.dev.assetsPublicPath
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.vue', '.json'],
|
||||||
|
alias: {
|
||||||
|
'vue$': 'vue/dist/vue.esm.js',
|
||||||
|
'@': resolve('src'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader',
|
||||||
|
options: vueLoaderConfig
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('media/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
|
// source contains it (although only uses it if it's native).
|
||||||
|
setImmediate: false,
|
||||||
|
// prevent webpack from injecting mocks to Node native modules
|
||||||
|
// that does not make sense for the client
|
||||||
|
dgram: 'empty',
|
||||||
|
fs: 'empty',
|
||||||
|
net: 'empty',
|
||||||
|
tls: 'empty',
|
||||||
|
child_process: 'empty'
|
||||||
|
}
|
||||||
|
}
|
95
src/frontend_vue/build/webpack.dev.conf.js
Executable file
95
src/frontend_vue/build/webpack.dev.conf.js
Executable file
|
@ -0,0 +1,95 @@
|
||||||
|
'use strict'
|
||||||
|
const utils = require('./utils')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const path = require('path')
|
||||||
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||||
|
const portfinder = require('portfinder')
|
||||||
|
|
||||||
|
const HOST = process.env.HOST
|
||||||
|
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||||
|
|
||||||
|
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
|
module: {
|
||||||
|
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
|
||||||
|
},
|
||||||
|
// cheap-module-eval-source-map is faster for development
|
||||||
|
devtool: config.dev.devtool,
|
||||||
|
|
||||||
|
// these devServer options should be customized in /config/index.js
|
||||||
|
devServer: {
|
||||||
|
clientLogLevel: 'warning',
|
||||||
|
historyApiFallback: {
|
||||||
|
rewrites: [
|
||||||
|
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
hot: true,
|
||||||
|
contentBase: false, // since we use CopyWebpackPlugin.
|
||||||
|
compress: true,
|
||||||
|
host: HOST || config.dev.host,
|
||||||
|
port: PORT || config.dev.port,
|
||||||
|
open: config.dev.autoOpenBrowser,
|
||||||
|
overlay: config.dev.errorOverlay
|
||||||
|
? { warnings: false, errors: true }
|
||||||
|
: false,
|
||||||
|
publicPath: config.dev.assetsPublicPath,
|
||||||
|
proxy: config.dev.proxyTable,
|
||||||
|
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||||
|
watchOptions: {
|
||||||
|
poll: config.dev.poll,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': require('../config/dev.env')
|
||||||
|
}),
|
||||||
|
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
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: 'index.html',
|
||||||
|
inject: true
|
||||||
|
}),
|
||||||
|
// copy custom static assets
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, '../static'),
|
||||||
|
to: config.dev.assetsSubDirectory,
|
||||||
|
ignore: ['.*']
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = new Promise((resolve, reject) => {
|
||||||
|
portfinder.basePort = process.env.PORT || config.dev.port
|
||||||
|
portfinder.getPort((err, port) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
// publish the new Port, necessary for e2e tests
|
||||||
|
process.env.PORT = port
|
||||||
|
// add port to devServer config
|
||||||
|
devWebpackConfig.devServer.port = port
|
||||||
|
|
||||||
|
// Add FriendlyErrorsPlugin
|
||||||
|
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||||
|
compilationSuccessInfo: {
|
||||||
|
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||||
|
},
|
||||||
|
onErrors: config.dev.notifyOnErrors
|
||||||
|
? utils.createNotifierCallback()
|
||||||
|
: undefined
|
||||||
|
}))
|
||||||
|
|
||||||
|
resolve(devWebpackConfig)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
145
src/frontend_vue/build/webpack.prod.conf.js
Normal file
145
src/frontend_vue/build/webpack.prod.conf.js
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
const utils = require('./utils')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
|
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||||
|
|
||||||
|
const env = require('../config/prod.env')
|
||||||
|
|
||||||
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
|
module: {
|
||||||
|
rules: utils.styleLoaders({
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
extract: true,
|
||||||
|
usePostCSS: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||||
|
output: {
|
||||||
|
path: config.build.assetsRoot,
|
||||||
|
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||||
|
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env': env
|
||||||
|
}),
|
||||||
|
new UglifyJsPlugin({
|
||||||
|
uglifyOptions: {
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
parallel: true
|
||||||
|
}),
|
||||||
|
// extract css into its own file
|
||||||
|
new ExtractTextPlugin({
|
||||||
|
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
|
||||||
|
// duplicated CSS from different components can be deduped.
|
||||||
|
new OptimizeCSSPlugin({
|
||||||
|
cssProcessorOptions: config.build.productionSourceMap
|
||||||
|
? { safe: true, map: { inline: false } }
|
||||||
|
: { safe: true }
|
||||||
|
}),
|
||||||
|
// generate dist index.html with correct asset hash for caching.
|
||||||
|
// you can customize output by editing /index.html
|
||||||
|
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: config.build.index,
|
||||||
|
template: 'index.html',
|
||||||
|
inject: true,
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true
|
||||||
|
// more options:
|
||||||
|
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||||
|
},
|
||||||
|
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||||
|
chunksSortMode: 'dependency'
|
||||||
|
}),
|
||||||
|
// keep module.id stable when vendor modules does not change
|
||||||
|
new webpack.HashedModuleIdsPlugin(),
|
||||||
|
// enable scope hoisting
|
||||||
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
|
// split vendor js into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'vendor',
|
||||||
|
minChunks (module) {
|
||||||
|
// any required modules inside node_modules are extracted to vendor
|
||||||
|
return (
|
||||||
|
module.resource &&
|
||||||
|
/\.js$/.test(module.resource) &&
|
||||||
|
module.resource.indexOf(
|
||||||
|
path.join(__dirname, '../node_modules')
|
||||||
|
) === 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'manifest',
|
||||||
|
minChunks: Infinity
|
||||||
|
}),
|
||||||
|
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||||
|
// in a separate chunk, similar to the vendor chunk
|
||||||
|
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'app',
|
||||||
|
async: 'vendor-async',
|
||||||
|
children: true,
|
||||||
|
minChunks: 3
|
||||||
|
}),
|
||||||
|
|
||||||
|
// copy custom static assets
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: path.resolve(__dirname, '../static'),
|
||||||
|
to: config.build.assetsSubDirectory,
|
||||||
|
ignore: ['.*']
|
||||||
|
}
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
if (config.build.productionGzip) {
|
||||||
|
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new CompressionWebpackPlugin({
|
||||||
|
asset: '[path].gz[query]',
|
||||||
|
algorithm: 'gzip',
|
||||||
|
test: new RegExp(
|
||||||
|
'\\.(' +
|
||||||
|
config.build.productionGzipExtensions.join('|') +
|
||||||
|
')$'
|
||||||
|
),
|
||||||
|
threshold: 10240,
|
||||||
|
minRatio: 0.8
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.build.bundleAnalyzerReport) {
|
||||||
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||||
|
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = webpackConfig
|
3
src/frontend_vue/config/config.json
Normal file
3
src/frontend_vue/config/config.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"api_addr": "http://localhost:5004"
|
||||||
|
}
|
3
src/frontend_vue/config/config_dev.json
Normal file
3
src/frontend_vue/config/config_dev.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"api_addr": "http://localhost:5004"
|
||||||
|
}
|
3
src/frontend_vue/config/config_pro.json
Normal file
3
src/frontend_vue/config/config_pro.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"api_addr": "http://193.2.76.103:5004"
|
||||||
|
}
|
7
src/frontend_vue/config/dev.env.js
Normal file
7
src/frontend_vue/config/dev.env.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
'use strict'
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const prodEnv = require('./prod.env')
|
||||||
|
|
||||||
|
module.exports = merge(prodEnv, {
|
||||||
|
NODE_ENV: '"development"'
|
||||||
|
})
|
69
src/frontend_vue/config/index.js
Normal file
69
src/frontend_vue/config/index.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
'use strict'
|
||||||
|
// Template version: 1.3.1
|
||||||
|
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dev: {
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
assetsPublicPath: '/',
|
||||||
|
proxyTable: {},
|
||||||
|
|
||||||
|
// Various Dev Server settings
|
||||||
|
host: 'localhost', // can be overwritten by process.env.HOST
|
||||||
|
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||||
|
autoOpenBrowser: false,
|
||||||
|
errorOverlay: true,
|
||||||
|
notifyOnErrors: true,
|
||||||
|
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://webpack.js.org/configuration/devtool/#development
|
||||||
|
devtool: 'cheap-module-eval-source-map',
|
||||||
|
|
||||||
|
// If you have problems debugging vue-files in devtools,
|
||||||
|
// set this to false - it *may* help
|
||||||
|
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||||
|
cacheBusting: true,
|
||||||
|
|
||||||
|
cssSourceMap: true
|
||||||
|
},
|
||||||
|
|
||||||
|
build: {
|
||||||
|
// Template for index.html
|
||||||
|
index: path.resolve(__dirname, '../dist/index.html'),
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
assetsPublicPath: '/',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
|
productionSourceMap: true,
|
||||||
|
// https://webpack.js.org/configuration/devtool/#production
|
||||||
|
devtool: '#source-map',
|
||||||
|
|
||||||
|
// Gzip off by default as many popular static hosts such as
|
||||||
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
|
// Before setting to `true`, make sure to:
|
||||||
|
// npm install --save-dev compression-webpack-plugin
|
||||||
|
productionGzip: false,
|
||||||
|
productionGzipExtensions: ['js', 'css'],
|
||||||
|
|
||||||
|
// Run the build command with an extra argument to
|
||||||
|
// View the bundle analyzer report after build finishes:
|
||||||
|
// `npm run build --report`
|
||||||
|
// Set to `true` or `false` to always turn it on or off
|
||||||
|
bundleAnalyzerReport: process.env.npm_config_report
|
||||||
|
}
|
||||||
|
}
|
4
src/frontend_vue/config/prod.env.js
Normal file
4
src/frontend_vue/config/prod.env.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
'use strict'
|
||||||
|
module.exports = {
|
||||||
|
NODE_ENV: '"production"'
|
||||||
|
}
|
12
src/frontend_vue/index.html
Normal file
12
src/frontend_vue/index.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>vue_frontend</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
10853
src/frontend_vue/package-lock.json
generated
Normal file
10853
src/frontend_vue/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
67
src/frontend_vue/package.json
Normal file
67
src/frontend_vue/package.json
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"name": "vue_frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Frontend for Valency App.",
|
||||||
|
"author": "voje <kristjan.voje@gmail.com>",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||||
|
"start": "npm run dev",
|
||||||
|
"build": "node build/build.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.18.0",
|
||||||
|
"bootstrap-vue": "^2.0.0-rc.11",
|
||||||
|
"sha256": "^0.2.0",
|
||||||
|
"vue": "^2.5.2",
|
||||||
|
"vue-cookies": "^1.5.6",
|
||||||
|
"vue-router": "^3.0.1",
|
||||||
|
"vue-spinner": "^1.0.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^7.1.2",
|
||||||
|
"babel-core": "^6.22.1",
|
||||||
|
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||||
|
"babel-loader": "^7.1.1",
|
||||||
|
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||||
|
"babel-plugin-transform-runtime": "^6.22.0",
|
||||||
|
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
||||||
|
"babel-preset-env": "^1.3.2",
|
||||||
|
"babel-preset-stage-2": "^6.22.0",
|
||||||
|
"chalk": "^2.0.1",
|
||||||
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
|
"css-loader": "^0.28.0",
|
||||||
|
"extract-text-webpack-plugin": "^3.0.0",
|
||||||
|
"file-loader": "^1.1.4",
|
||||||
|
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||||
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"node-notifier": "^5.1.2",
|
||||||
|
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
||||||
|
"ora": "^1.2.0",
|
||||||
|
"portfinder": "^1.0.13",
|
||||||
|
"postcss-import": "^11.0.0",
|
||||||
|
"postcss-loader": "^2.0.8",
|
||||||
|
"postcss-url": "^7.2.1",
|
||||||
|
"rimraf": "^2.6.0",
|
||||||
|
"semver": "^5.3.0",
|
||||||
|
"shelljs": "^0.7.6",
|
||||||
|
"uglifyjs-webpack-plugin": "^1.1.1",
|
||||||
|
"url-loader": "^0.5.8",
|
||||||
|
"vue-loader": "^13.3.0",
|
||||||
|
"vue-style-loader": "^3.0.1",
|
||||||
|
"vue-template-compiler": "^2.5.2",
|
||||||
|
"webpack": "^3.6.0",
|
||||||
|
"webpack-bundle-analyzer": "^2.9.0",
|
||||||
|
"webpack-dev-server": "^2.9.1",
|
||||||
|
"webpack-merge": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
1
src/frontend_vue/postcss.config.js
Normal file
1
src/frontend_vue/postcss.config.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = {};
|
9
src/frontend_vue/src/App.vue
Normal file
9
src/frontend_vue/src/App.vue
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<router-view/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
}
|
||||||
|
</script>
|
206
src/frontend_vue/src/components/EditSenses.vue
Normal file
206
src/frontend_vue/src/components/EditSenses.vue
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
<template>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<p class="pb-0 mb-0">Urejanje pomenov za besedo: <b>{{ hw }}</b>.</p>
|
||||||
|
<p><small>
|
||||||
|
Z miško kliknite na poved, nato kliknite na pomen, ki ga želite dodeliti povedi. Par poved‒pomen bo obarvan z modro. Pare lahko shranite s klikom na gumb "Shrani". Možno je dodajanje poljubnih pomenov.
|
||||||
|
</small></p>
|
||||||
|
<button v-on:click="cancel_all">Prekliči</button>
|
||||||
|
<button v-on:click="save_all">Shrani</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<!-- left column: sentences -->
|
||||||
|
<div class="my-sent col-sm-6">
|
||||||
|
<div
|
||||||
|
v-for="(sentence, ssj_id) in sentences"
|
||||||
|
v-on:click="pick_ssj_id(ssj_id)"
|
||||||
|
class="border rounded my-sentences my-pointer"
|
||||||
|
v-bind:class="{
|
||||||
|
'border-primary': ssj_id === picked_ssj_id
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
v-for="(word, index) in sentence.words"
|
||||||
|
v-bind:class="{
|
||||||
|
'text-primary': index === parseInt(sentence.hw_idx)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span v-if="$root.mkspace(index, word)"> </span>{{ word }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="col-sm-12"><small>
|
||||||
|
<div v-if="ssj_id in local_sense_map">
|
||||||
|
<Sense v-bind:sense="local_sense_map[ssj_id].sense"></Sense>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<Sense v-bind:sense="undefined"></Sense>
|
||||||
|
</div>
|
||||||
|
</small></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- right column: senses -->
|
||||||
|
<div class="col-sm-6 border rounded my-div-scroll sticky-top">
|
||||||
|
<div
|
||||||
|
v-for="sense in local_senses"
|
||||||
|
class="my-pointer"
|
||||||
|
v-on:click="picked_sense_id = sense.sense_id"
|
||||||
|
v-bind:class="{
|
||||||
|
'text-primary': sense.sense_id === picked_sense_id
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<Sense v-bind:sense="sense"></Sense>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<textarea class="my-textarea" v-model="new_sense_desc"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<button v-on:click="new_sense">Dodaj pomen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sense from "./Sense"
|
||||||
|
export default {
|
||||||
|
name: "EditSenses",
|
||||||
|
props: ["hw", "sentences", "sens"],
|
||||||
|
components: {
|
||||||
|
Sense: Sense
|
||||||
|
},
|
||||||
|
data () { return {
|
||||||
|
picked_ssj_id: null,
|
||||||
|
picked_sense_id: null,
|
||||||
|
local_senses: [], // make changes on a local copy
|
||||||
|
local_sense_map: {}, // make changes on a local copy
|
||||||
|
new_sense_desc: "",
|
||||||
|
new_senses: [], // only send changes to server
|
||||||
|
delta_sense_map: {}, // only send changes to server
|
||||||
|
}},
|
||||||
|
created: function() {
|
||||||
|
// not sure if needed, maybe move to data()
|
||||||
|
this.local_senses = this.sens.senses
|
||||||
|
var json = JSON.stringify(this.sens.sense_map)
|
||||||
|
this.local_sense_map = JSON.parse(json)
|
||||||
|
for (var ssj_id in this.local_sense_map) {
|
||||||
|
this.local_sense_map[ssj_id].sense = this.sense_id_to_sense(
|
||||||
|
this.local_sense_map[ssj_id].sense_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
picked_ssj_id: function() {
|
||||||
|
this.new_link()
|
||||||
|
},
|
||||||
|
picked_sense_id: function() {
|
||||||
|
this.new_link()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
pick_ssj_id: function(ssj_id) {
|
||||||
|
this.picked_ssj_id = ssj_id
|
||||||
|
if (ssj_id in this.local_sense_map) {
|
||||||
|
this.picked_sense_id = this.local_sense_map[ssj_id].sense_id
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
new_link: function() {
|
||||||
|
if (this.picked_ssj_id === null ||
|
||||||
|
this.picked_sense_id === null) { return }
|
||||||
|
this.local_sense_map[this.picked_ssj_id] = {
|
||||||
|
sense_id: this.picked_sense_id,
|
||||||
|
sense: this.sense_id_to_sense(this.picked_sense_id)
|
||||||
|
}
|
||||||
|
this.delta_sense_map[this.picked_ssj_id] = { sense_id: this.picked_sense_id }
|
||||||
|
},
|
||||||
|
new_sense: function(sense_id) {
|
||||||
|
if (this.new_sense_desc === "") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var new_sense = {
|
||||||
|
hw: this.hw,
|
||||||
|
author: this.$root.store.username,
|
||||||
|
desc: this.new_sense_desc,
|
||||||
|
sense_id: "tmp_sense_id" + (new Date().getTime()),
|
||||||
|
}
|
||||||
|
this.local_senses.push(new_sense)
|
||||||
|
this.new_senses.push(new_sense)
|
||||||
|
this.new_sense_desc = ""
|
||||||
|
},
|
||||||
|
sense_id_to_sense: function(sense_id) {
|
||||||
|
for (var i=0; i<this.local_senses.length; i++) {
|
||||||
|
if (this.local_senses[i].sense_id === sense_id) {
|
||||||
|
return this.local_senses[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
},
|
||||||
|
cancel_all: function() {
|
||||||
|
this.$parent.state = "normal"
|
||||||
|
},
|
||||||
|
save_all: function() {
|
||||||
|
const data = {
|
||||||
|
token: this.$root.store.token,
|
||||||
|
hw: this.hw,
|
||||||
|
sense_map: this.delta_sense_map,
|
||||||
|
new_senses: this.new_senses,
|
||||||
|
}
|
||||||
|
var component = this
|
||||||
|
function exit_edit(component) {
|
||||||
|
component.$parent.state = "normal"
|
||||||
|
component.$parent.request_reload = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't update if there are no changes
|
||||||
|
if (
|
||||||
|
Object.keys(data.sense_map).length === 0 &&
|
||||||
|
data.new_senses.length === 0
|
||||||
|
) { exit_edit(component); return }
|
||||||
|
|
||||||
|
// exit after update
|
||||||
|
this.$http.post(
|
||||||
|
this.$root.store.api_addr + "/api/senses/update",
|
||||||
|
data,
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/json',
|
||||||
|
}}
|
||||||
|
).then(function () {
|
||||||
|
exit_edit(component)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.my-div-scroll {
|
||||||
|
margin-top: 5px;
|
||||||
|
height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.my-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.my-textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.my-sentences {
|
||||||
|
margin: 5px 0px 20px 0px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.my-sent {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.my-sent span {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
208
src/frontend_vue/src/components/Frame.vue
Normal file
208
src/frontend_vue/src/components/Frame.vue
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
<template>
|
||||||
|
<!-- clicking on empty space clears highlights -->
|
||||||
|
<div v-on:click="clearOnClick" class="container-fluid">
|
||||||
|
<hr>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
št. povedi: {{ frameData.sentences.length }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--frame slots-->
|
||||||
|
<div class="row my-frames">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<span v-for="(slot, key) in frameData.slots">
|
||||||
|
<span
|
||||||
|
v-bind:class="{
|
||||||
|
'my-pointer text-danger': hasHoverTid(idx=key),
|
||||||
|
'my-underline text-danger': hasSelTid(idx=key)
|
||||||
|
}"
|
||||||
|
v-on:mouseover="setHid(idx=key)"
|
||||||
|
v-on:mouseleave="setHid()"
|
||||||
|
v-on:click="setSid(idx=key)"
|
||||||
|
>{{ slot.functor }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--sense information-->
|
||||||
|
<div v-if="$root.store.radio === 'three'" class="col-sm-5">
|
||||||
|
<Sense v-bind:sense="getSense()"></Sense>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--sentences-->
|
||||||
|
<div class="row">
|
||||||
|
<!-- fmode: prikaz->udelezenske vloge (drugacno razvrscanje povedi) -->
|
||||||
|
<div v-if="fmode" class="col-sm-12">
|
||||||
|
<div v-for="hw in getAggrHws()">
|
||||||
|
<blockquote v-for="sentence in getAggrSent(hw)">
|
||||||
|
<span class="text-secondary"> {{ hw }}</span><br>
|
||||||
|
<span
|
||||||
|
v-for="(token, index) in sentence"
|
||||||
|
v-bind:class="{
|
||||||
|
'my-pointer text-danger': hasHoverTid(idx=null, tid=token[0]), 'my-underline text-danger': hasSelTid(idx=null, tid=token[0]),
|
||||||
|
'text-primary': isHw(token[0]),
|
||||||
|
}"
|
||||||
|
v-on:mouseover="setHid(idx=null, tid=token[0])"
|
||||||
|
v-on:mouseleave="setHid()"
|
||||||
|
v-on:click="setSid(idx=null, tid=token[0])"
|
||||||
|
v-bind:title="token[1].msd"
|
||||||
|
><span v-if="$root.mkspace(index, token[1].word)"> </span>{{ token[1].word }}</span>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="col-sm-12">
|
||||||
|
<blockquote v-for="sentence in frameData.sentences">
|
||||||
|
<span
|
||||||
|
v-for="(token, index) in sentence"
|
||||||
|
v-bind:class="{
|
||||||
|
'my-pointer text-danger': hasHoverTid(idx=null, tid=token[0]), 'my-underline text-danger': hasSelTid(idx=null, tid=token[0]),
|
||||||
|
'text-primary': isHw(token[0]),
|
||||||
|
}"
|
||||||
|
v-on:mouseover="setHid(idx=null, tid=token[0])"
|
||||||
|
v-on:mouseleave="setHid()"
|
||||||
|
v-on:click="setSid(idx=null, tid=token[0])"
|
||||||
|
v-bind:title="token[1].msd"
|
||||||
|
><span v-if="$root.mkspace(index, token[1].word)"> </span>{{ token[1].word }}</span>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sense from "./Sense"
|
||||||
|
export default {
|
||||||
|
name: "Frame",
|
||||||
|
props: {
|
||||||
|
frameData: {},
|
||||||
|
sensData: {},
|
||||||
|
fmode: {
|
||||||
|
default: false,
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() { return {
|
||||||
|
hid: null, // hover functor index
|
||||||
|
sid: null, // select functor index (click)
|
||||||
|
}},
|
||||||
|
components: {
|
||||||
|
Sense: Sense
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
frameData: function () {
|
||||||
|
this.hid = null,
|
||||||
|
this.sid = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setHid: function (idx=null, tid=null) {
|
||||||
|
// calling this functoin without parameters
|
||||||
|
// resets hid
|
||||||
|
if (tid === null) {
|
||||||
|
this.hid = idx
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (var i=0; i<this.frameData.slots.length; i++) {
|
||||||
|
if (this.frameData.slots[i].tids.includes(tid)) {
|
||||||
|
this.hid = i
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearOnClick: function (event) {
|
||||||
|
if (event.target.tagName !== "SPAN") {
|
||||||
|
this.sid = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setSid: function (idx=null, tid=null) {
|
||||||
|
this.sid = null
|
||||||
|
if (tid === null) {
|
||||||
|
this.sid = idx
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (var i=0; i<this.frameData.slots.length; i++) {
|
||||||
|
if (this.frameData.slots[i].tids.includes(tid)) {
|
||||||
|
this.sid = i
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hasHoverTid: function(idx=null, tid=null) {
|
||||||
|
if (this.hid === null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (tid === null) {
|
||||||
|
if (idx == this.hid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return this.frameData.slots[this.hid].tids.includes(tid)
|
||||||
|
},
|
||||||
|
hasSelTid: function (idx=null, tid=null) {
|
||||||
|
if (this.sid === null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (tid === null) {
|
||||||
|
if (idx == this.sid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return this.frameData.slots[this.sid].tids.includes(tid)
|
||||||
|
},
|
||||||
|
isHw: function (tid) {
|
||||||
|
return this.frameData.tids.includes(tid)
|
||||||
|
},
|
||||||
|
getSense: function () {
|
||||||
|
for (var i in this.sensData.senses) {
|
||||||
|
if (this.sensData.senses[i].sense_id === this.frameData.sense_info.sense_id) {
|
||||||
|
return this.sensData.senses[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
},
|
||||||
|
getAggrHws: function() {
|
||||||
|
return (Object.keys(this.frameData.aggr_sent)).sort()
|
||||||
|
},
|
||||||
|
getAggrSent: function(hw) {
|
||||||
|
var sentences = []
|
||||||
|
for (var i=0; i<this.frameData.aggr_sent[hw].length; i++) {
|
||||||
|
sentences.push(
|
||||||
|
this.frameData.sentences[this.frameData.aggr_sent[hw][i]]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return sentences
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.my-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.my-underline {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.my-frames {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
background: #ffffff;
|
||||||
|
border-left: 4px solid #ccc;
|
||||||
|
margin: 10px 0px 10px 10px;
|
||||||
|
padding: 0px 0px 0px 5px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
blockquote span {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
50
src/frontend_vue/src/components/Home.vue
Normal file
50
src/frontend_vue/src/components/Home.vue
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p
|
||||||
|
v-if="this.$root.store.api_error !== null"
|
||||||
|
class="text-warning"
|
||||||
|
>
|
||||||
|
api_error: {{ this.$root.store.api_error }}
|
||||||
|
</p>
|
||||||
|
<Nav></Nav>
|
||||||
|
<div class="my-home container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div id="serach" class="col-sm-2 border-right fill">
|
||||||
|
<LWords v-if="navSS()"></LWords>
|
||||||
|
<LFunctors v-else></LFunctors>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<router-view></router-view>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Nav from "./Nav"
|
||||||
|
import LWords from "./LWords"
|
||||||
|
import LFunctors from "./LFunctors"
|
||||||
|
import MainDispl from "./MainDispl"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Home',
|
||||||
|
components: {
|
||||||
|
Nav: Nav,
|
||||||
|
LWords: LWords,
|
||||||
|
LFunctors: LFunctors,
|
||||||
|
MainDispl: MainDispl,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
navSS: function () {
|
||||||
|
return this.$root.storeGet("navSS") === "words"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.my-home {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
51
src/frontend_vue/src/components/LFunctors.vue
Normal file
51
src/frontend_vue/src/components/LFunctors.vue
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr v-for="functor in functors">
|
||||||
|
<td><a href="#" v-on:click="selectFunctor(functor)">{{ functor[0] }}</a></td>
|
||||||
|
<td>({{ functor[1] }})</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LWords",
|
||||||
|
props: ["appState"],
|
||||||
|
data() {return {
|
||||||
|
functors: []
|
||||||
|
}},
|
||||||
|
methods: {
|
||||||
|
apiGetFunctors: function () {
|
||||||
|
var component = this
|
||||||
|
this.$http.get(this.$root.store.api_addr + "/api/functors")
|
||||||
|
.then(function(response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
component.functors = response.data
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
component.$root.store.api_error = error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
selectFunctor: function (functor) {
|
||||||
|
this.$router.push({
|
||||||
|
name: "MainDispl",
|
||||||
|
params: {
|
||||||
|
hw: functor[0],
|
||||||
|
fmode: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
this.apiGetFunctors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
80
src/frontend_vue/src/components/LWords.vue
Normal file
80
src/frontend_vue/src/components/LWords.vue
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<select v-model="selectedLetter">
|
||||||
|
<option v-for="letter in alphabet" :value="letter">
|
||||||
|
{{ letter.toUpperCase() }} ({{ getNumWords(letter) }})
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<table>
|
||||||
|
<tr v-for="word in getWords()">
|
||||||
|
<td><a href="#" v-on:click="selectHw(word)">{{ word[0] }}
|
||||||
|
<span v-if="$root.store.has_se.includes(word[0])">se</span>
|
||||||
|
</a></td>
|
||||||
|
<td>({{ word[1] }})</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LWords",
|
||||||
|
data() {return {
|
||||||
|
alphabet: "abcčdefghijklmnoprsštuvzž",
|
||||||
|
letters: {},
|
||||||
|
selectedLetter: "a"
|
||||||
|
}},
|
||||||
|
methods: {
|
||||||
|
apiGetWords: function() {
|
||||||
|
var component = this
|
||||||
|
this.$http.get(this.$root.storeGet("api_addr") + "/api/words")
|
||||||
|
.then(function(response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
component.$root.store.has_se = response.data["has_se"]
|
||||||
|
component.letters = response.data["sorted_words"]
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
component.$root.store.api_error = error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getNumWords: function(letter) {
|
||||||
|
var entry = this.letters[letter]
|
||||||
|
if (entry) {
|
||||||
|
return entry.length
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getWords: function() {
|
||||||
|
var entry = this.letters[this.selectedLetter]
|
||||||
|
if (entry) {
|
||||||
|
return entry
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectHw: function(word) {
|
||||||
|
this.$router.push({
|
||||||
|
name: "MainDispl",
|
||||||
|
params: {
|
||||||
|
hw: word[0],
|
||||||
|
fmode: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
this.apiGetWords()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
120
src/frontend_vue/src/components/Login.vue
Normal file
120
src/frontend_vue/src/components/Login.vue
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<a href="#" v-on:click="this.$root.routeBack">Nazaj</a>
|
||||||
|
</div>
|
||||||
|
<div class="ev-login col-sm-4 offset-sm-4">
|
||||||
|
<div class="alert alert-danger" v-if="error">
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
data-id="login.username"
|
||||||
|
class="form-control js-login__username"
|
||||||
|
placeholder="Uporabnik"
|
||||||
|
v-model="credentials.username"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control js-login__password "
|
||||||
|
placeholder="Geslo"
|
||||||
|
v-model="credentials.password"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
data-id="login.submit"
|
||||||
|
class="btn btn-primary solid blank js-login__submit"
|
||||||
|
@click="submit()"
|
||||||
|
>
|
||||||
|
Prijava<i class="fa fa-arrow-circle-o-right"></i>
|
||||||
|
</button>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<router-link to="/new_pass">Ste pozabili geslo?</router-link>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Nov uporabnik?
|
||||||
|
<br>
|
||||||
|
<router-link to="/register">Ustvarite nov račun.</router-link>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Login',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
credentials: {
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
},
|
||||||
|
loggingIn: false,
|
||||||
|
error: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit () {
|
||||||
|
this.error = ""
|
||||||
|
//this.loggingIn = true
|
||||||
|
// Auth.login() returns a promise. A redirect will happen on success.
|
||||||
|
// For errors, use .then() to capture the response to output
|
||||||
|
// error_description (if exists) as shown below:
|
||||||
|
/*
|
||||||
|
this.$auth.login(credentials, 'dashboard').then((response) => {
|
||||||
|
this.loggingIn = false
|
||||||
|
this.error = utils.getError(response)
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( this.credentials.username === "" ||
|
||||||
|
this.credentials.password === ""
|
||||||
|
) {
|
||||||
|
this.error = "Izpolnite vsa polja."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
username: this.credentials.username,
|
||||||
|
password: this.credentials.password
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = this
|
||||||
|
this.$http.post(this.$root.storeGet("api_addr") + "/api/login",
|
||||||
|
data, // the data to post
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
var token = response.data.token
|
||||||
|
if (token === null) {
|
||||||
|
component.error = "Napačno uporabniško ime ali geslo."
|
||||||
|
} else {
|
||||||
|
// set cookies (if the page reloads)
|
||||||
|
component.$root.store.username = component.credentials.username
|
||||||
|
component.$root.store.token = token
|
||||||
|
component.$router.go(-1)
|
||||||
|
component.$cookies.set("valency_token", token, 60*60*48)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
component.$root.store.api_error = err
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ev-login {
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
256
src/frontend_vue/src/components/MainDispl.vue
Normal file
256
src/frontend_vue/src/components/MainDispl.vue
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
<template>
|
||||||
|
<!--load mode-->
|
||||||
|
<div v-if="show_loader">
|
||||||
|
<pulse-loader :color="loader_color"></pulse-loader>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--edit mode (button: razvrsti po pomenih)-->
|
||||||
|
<div v-else-if="state === 'editing'" class="container-fluid">
|
||||||
|
<EditSenses
|
||||||
|
v-bind:hw="hw"
|
||||||
|
v-bind:sentences="sentences"
|
||||||
|
v-bind:sens="sens"
|
||||||
|
></EditSenses>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--normal mode-->
|
||||||
|
<div v-else class="container-fluid" id="head">
|
||||||
|
|
||||||
|
<!--header (verb/adjective, radio buttons)-->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<table>
|
||||||
|
<tr><h4 id="main-displ-hw">{{ hw }}
|
||||||
|
<span v-if="$root.store.has_se.includes(hw)">se</span>
|
||||||
|
</h4></tr>
|
||||||
|
<tr>{{ calcPos() }}</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<table>
|
||||||
|
<tr>Združevanje vezljivostnih vzorcev:</tr>
|
||||||
|
<tr>
|
||||||
|
<label class="radio-inline"><input value="one" v-model="$root.store.radio" v-on:change="reload()" checked="" type="radio" name="optradio">posamezne povedi</label>
|
||||||
|
<label class="radio-inline"><input value="two" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">skupne udeleženske vloge</label>
|
||||||
|
<label v-if="this.$root.store.navSS === 'words'" class="radio-inline"><input value="three" v-model="$root.store.radio" v-on:change="reload()" type="radio" name="optradio">po meri</label>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--frames-->
|
||||||
|
<div v-if="$root.store.radio === 'three'" class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<button v-on:click="userEdit">razvrsti po pomenih</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" v-for="frame in frames">
|
||||||
|
<Frame
|
||||||
|
v-bind:frameData="frame"
|
||||||
|
v-bind:sensData="sens"
|
||||||
|
v-bind:fmode="fmode">
|
||||||
|
</Frame>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Frame from "./Frame"
|
||||||
|
import EditSenses from "./EditSenses"
|
||||||
|
import PulseLoader from 'vue-spinner/src/PulseLoader.vue'
|
||||||
|
export default {
|
||||||
|
name: "MainDispl",
|
||||||
|
components: {
|
||||||
|
Frame: Frame,
|
||||||
|
EditSenses: EditSenses,
|
||||||
|
PulseLoader: PulseLoader,
|
||||||
|
},
|
||||||
|
props: ["hw", "fmode"],
|
||||||
|
data () { return {
|
||||||
|
frames: [],
|
||||||
|
sentences: {},
|
||||||
|
sens: {
|
||||||
|
senses: [],
|
||||||
|
sense_map: {},
|
||||||
|
},
|
||||||
|
state: "loading", // editing, normal
|
||||||
|
request_reload: false,
|
||||||
|
loader_color: "#007bff",
|
||||||
|
}},
|
||||||
|
created: function () {
|
||||||
|
this.reload()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show_loader: function () {
|
||||||
|
return this.state === "loading" && this.$root.store.api_error !== null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
hw: function () {
|
||||||
|
this.reload()
|
||||||
|
},
|
||||||
|
frames: function () {
|
||||||
|
this.buildSentences()
|
||||||
|
},
|
||||||
|
request_reload: function () {
|
||||||
|
if (this.request_reload) {
|
||||||
|
this.request_reload = false
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getFFrames: function(functor, reduce_fun=null) {
|
||||||
|
// get frames in functor mode
|
||||||
|
if (functor === null || functor === undefined) return
|
||||||
|
if (reduce_fun === null) {
|
||||||
|
switch (this.$root.store.radio) {
|
||||||
|
case "one":
|
||||||
|
reduce_fun = "reduce_0"
|
||||||
|
break
|
||||||
|
case "two":
|
||||||
|
reduce_fun = "reduce_1"
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
reduce_fun = "reduce_0"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var component = this
|
||||||
|
this.$http.get(
|
||||||
|
this.$root.storeGet("api_addr") + "/api/functor-frames" +
|
||||||
|
"?functor=" + functor + "&rf=" + reduce_fun)
|
||||||
|
.then(function (response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
component.frames = response.data.frames
|
||||||
|
component.state = "normal"
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
component.$root.store.api_error = error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getFrames: function (hw, reduce_fun=null) {
|
||||||
|
if (hw === null || hw === undefined) return
|
||||||
|
if (reduce_fun === null) {
|
||||||
|
switch (this.$root.store.radio) {
|
||||||
|
case "one":
|
||||||
|
reduce_fun = "reduce_0"
|
||||||
|
break
|
||||||
|
case "two":
|
||||||
|
reduce_fun = "reduce_1"
|
||||||
|
break
|
||||||
|
case "three":
|
||||||
|
reduce_fun = "reduce_5"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var component = this
|
||||||
|
this.$http.get(
|
||||||
|
this.$root.storeGet("api_addr") + "/api/frames" +
|
||||||
|
"?hw=" + hw + "&rf=" + reduce_fun)
|
||||||
|
.then(function (response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
component.frames = response.data.frames
|
||||||
|
component.state = "normal"
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
component.$root.store.api_error = error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
buildSentences: function () {
|
||||||
|
if (this.frames.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.sentences = {}
|
||||||
|
for (var fi in this.frames) {
|
||||||
|
for (var si in this.frames[fi].sentences) {
|
||||||
|
var sentence = this.frames[fi].sentences[si]
|
||||||
|
// get ssj_id without .t123
|
||||||
|
var ssj_id = sentence[0][0].split(".")
|
||||||
|
ssj_id.splice(-1, 1) // removes last element
|
||||||
|
ssj_id = ssj_id.join(".")
|
||||||
|
var words = []
|
||||||
|
var hw_idx = -1
|
||||||
|
var tmp_hw = this.hw
|
||||||
|
if (tmp_hw[tmp_hw.length - 1] === "_") {
|
||||||
|
tmp_hw = tmp_hw.substr(0, tmp_hw.length - 1)
|
||||||
|
}
|
||||||
|
for (var i in sentence) {
|
||||||
|
words.push(sentence[i][1].word)
|
||||||
|
if (sentence[i][1].lemma === tmp_hw && hw_idx == -1) {
|
||||||
|
hw_idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.sentences[ssj_id] = {
|
||||||
|
hw_idx: hw_idx,
|
||||||
|
words: words
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSenses: function (hw, callback) {
|
||||||
|
if (hw === null || hw === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var component = this
|
||||||
|
this.$http.get(
|
||||||
|
this.$root.store.api_addr + "/api/senses/get" + "?hw=" + hw)
|
||||||
|
.then(function(response) {
|
||||||
|
// console.log(response.data)
|
||||||
|
component.sens.senses = response.data.senses
|
||||||
|
component.sens.sense_map = response.data.sense_map
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
reload: function () {
|
||||||
|
this.state = "loading"
|
||||||
|
this.sentences = {}
|
||||||
|
if (this.$root.store.navSS === "functors") this.getFFrames(this.hw)
|
||||||
|
else {
|
||||||
|
this.getFrames(this.hw)
|
||||||
|
if (this.$root.store.radio === "three") {
|
||||||
|
this.getSenses(this.hw, this.sortBySense)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.calcPos()
|
||||||
|
},
|
||||||
|
userEdit: function () {
|
||||||
|
// authenticate the user for this
|
||||||
|
var tthis = this
|
||||||
|
this.$root.checkToken()
|
||||||
|
.then(function (response) {tthis.state = "editing"})
|
||||||
|
.catch(function (err) {alert("Za urejanje je potrebna prijava.")}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
calcPos: function() {
|
||||||
|
var bfmode = this.fmode
|
||||||
|
if (typeof(bfmode) === "string") {
|
||||||
|
bfmode = (bfmode === "true")
|
||||||
|
}
|
||||||
|
if (bfmode) return "udeleženska vloga"
|
||||||
|
else if (this.hw.substr(this.hw.length-1) === "_") return "pridevnik"
|
||||||
|
return "glagol"
|
||||||
|
},
|
||||||
|
sortBySense: function() {
|
||||||
|
// frames with defined senses on top
|
||||||
|
var undefFrames = []
|
||||||
|
var defFrames = []
|
||||||
|
//console.log(Object.keys(this.sens.sense_map))
|
||||||
|
for (var i=0; i<this.frames.length; i++) {
|
||||||
|
var sense_id = this.frames[i].sense_info.sense_id
|
||||||
|
if (sense_id === "nedefinirano") undefFrames.push(this.frames[i])
|
||||||
|
else defFrames.push(this.frames[i])
|
||||||
|
}
|
||||||
|
this.frames = defFrames.concat(undefFrames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#main-displ-hw {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
74
src/frontend_vue/src/components/Nav.vue
Normal file
74
src/frontend_vue/src/components/Nav.vue
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<nav>
|
||||||
|
<b-navbar toggleable="md" type="light" variant="light">
|
||||||
|
<b-navbar-toggle target="nav_collapse"></b-navbar-toggle>
|
||||||
|
<b-navbar-brand>Vezljivostni vzorci slovenskih glagolov</b-navbar-brand>
|
||||||
|
<b-collapse is-nav id="nav_collapse">
|
||||||
|
|
||||||
|
<b-navbar-nav>
|
||||||
|
<b-nav-item-dropdown text="Prikaz" right>
|
||||||
|
<b-dropdown-item v-for="option in search_options"
|
||||||
|
:value="option.val"
|
||||||
|
:key="option.val"
|
||||||
|
v-on:click="setNavSS(option.val)">
|
||||||
|
{{ option.key }}
|
||||||
|
</b-dropdown-item>
|
||||||
|
</b-nav-item-dropdown>
|
||||||
|
</b-navbar-nav>
|
||||||
|
|
||||||
|
<!-- Right aligned nav items -->
|
||||||
|
<b-navbar-nav class="ml-auto" right v-if="this.loggedIn()">
|
||||||
|
<b-nav-item>
|
||||||
|
Uporabnik: {{ this.$root.store.username }}
|
||||||
|
<a href="#" v-on:click="logOut()">(odjava)</a>
|
||||||
|
</b-nav-item>
|
||||||
|
</b-navbar-nav>
|
||||||
|
<b-navbar-nav class="ml-auto" right v-else>
|
||||||
|
<b-nav-item>
|
||||||
|
<router-link to="/register">
|
||||||
|
Registracija
|
||||||
|
</router-link>
|
||||||
|
</b-nav-item>
|
||||||
|
<b-nav-item>
|
||||||
|
<router-link to="/login">
|
||||||
|
Prijava
|
||||||
|
</router-link>
|
||||||
|
</b-nav-item>
|
||||||
|
</b-navbar-nav>
|
||||||
|
|
||||||
|
</b-collapse>
|
||||||
|
</b-navbar>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Nav",
|
||||||
|
props: ["appState"],
|
||||||
|
data() {return {
|
||||||
|
search_options: [
|
||||||
|
{key: "besede", val: "words"},
|
||||||
|
{key: "udeleženske vloge", val: "functors"},
|
||||||
|
],
|
||||||
|
}},
|
||||||
|
methods: {
|
||||||
|
setNavSS(val) {
|
||||||
|
this.$root.store.radio = "one"
|
||||||
|
this.$root.store.navSS = val
|
||||||
|
this.$router.push({
|
||||||
|
name: "Home"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loggedIn() {
|
||||||
|
return (this.$root.store.token !== null)
|
||||||
|
},
|
||||||
|
logOut() {
|
||||||
|
this.$root.store.token = null
|
||||||
|
this.$root.store.username = null
|
||||||
|
this.$router.push({
|
||||||
|
name: "Home"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
106
src/frontend_vue/src/components/NewPass.vue
Normal file
106
src/frontend_vue/src/components/NewPass.vue
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<a href="#" v-on:click="this.$root.routeBack">Nazaj</a>
|
||||||
|
</div>
|
||||||
|
<div class="ev-login col-sm-4 offset-sm-4">
|
||||||
|
<div class="alert alert-danger" v-if="error">
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
data-id="login.username"
|
||||||
|
class="form-control js-login__username"
|
||||||
|
placeholder="Uporabnik"
|
||||||
|
v-model="credentials.username"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="e-pošta"
|
||||||
|
v-model="credentials.email"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>Novo geslo bo poslano na vaš e-poštni naslov.</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
data-id="new_pass.submit"
|
||||||
|
class="btn btn-primary solid blank js-login__submit"
|
||||||
|
@click="submit()"
|
||||||
|
>
|
||||||
|
Novo geslo<i class="fa fa-arrow-circle-o-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NewPass',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
credentials: {
|
||||||
|
username: '',
|
||||||
|
email: ''
|
||||||
|
},
|
||||||
|
error: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit () {
|
||||||
|
this.error = ""
|
||||||
|
//this.loggingIn = true
|
||||||
|
// Auth.login() returns a promise. A redirect will happen on success.
|
||||||
|
// For errors, use .then() to capture the response to output
|
||||||
|
// error_description (if exists) as shown below:
|
||||||
|
/*
|
||||||
|
this.$auth.login(credentials, 'dashboard').then((response) => {
|
||||||
|
this.loggingIn = false
|
||||||
|
this.error = utils.getError(response)
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( this.credentials.username === "" ||
|
||||||
|
this.credentials.email === ""
|
||||||
|
) {
|
||||||
|
this.error = "Izpolnite vsa polja."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
username: this.credentials.username,
|
||||||
|
email: this.credentials.email
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = this
|
||||||
|
this.$http.post(this.$root.storeGet("api_addr") + "/api/new_pass",
|
||||||
|
data, // the data to post
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
component.$root.store.api_error = null
|
||||||
|
var confirmation = response.data.confirmation
|
||||||
|
component.$router.push({
|
||||||
|
name: "Home"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
component.$root.store.api_error = err
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ev-login {
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
138
src/frontend_vue/src/components/Register.vue
Normal file
138
src/frontend_vue/src/components/Register.vue
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<a href="#" v-on:click="this.$root.routeBack">Nazaj</a>
|
||||||
|
</div>
|
||||||
|
<div class="ev-login col-sm-4 offset-sm-4">
|
||||||
|
<div class="alert alert-danger" v-if="error">
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="form-control js-login__username"
|
||||||
|
placeholder="Uporabnik"
|
||||||
|
v-model="credentials.username"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="e-pošta"
|
||||||
|
v-model="credentials.email"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control js-login__password "
|
||||||
|
placeholder="Geslo"
|
||||||
|
v-model="credentials.password"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control js-login__password "
|
||||||
|
placeholder="Ponovite geslo."
|
||||||
|
v-model="credentials.snd_password"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn btn-primary solid blank js-login__submit"
|
||||||
|
@click="submit()"
|
||||||
|
>
|
||||||
|
Registracija<i class="fa fa-arrow-circle-o-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Register',
|
||||||
|
data () { return {
|
||||||
|
credentials: {
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
snd_password: "",
|
||||||
|
email: ""
|
||||||
|
},
|
||||||
|
error: ""
|
||||||
|
}},
|
||||||
|
methods: {
|
||||||
|
clearFields () {
|
||||||
|
for (var key in this.credentials) {
|
||||||
|
this.credentials[key] = ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkEmail () {
|
||||||
|
// check? ... todo
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
submit () {
|
||||||
|
//console.log(this.credentials.password)
|
||||||
|
//console.log(this.credentials.snd_password)
|
||||||
|
const credentials = {
|
||||||
|
username: this.credentials.username,
|
||||||
|
password: this.credentials.password
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if fields are full
|
||||||
|
for (var key in this.credentials) {
|
||||||
|
if (credentials[key] === "") {
|
||||||
|
this.error = "Izpolnite vsa polja."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check e-mail
|
||||||
|
if (!this.checkEmail(this.credentials.email)) {
|
||||||
|
this.error = "Preverite e-poštni naslov."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check passwords
|
||||||
|
if (this.credentials.password !== this.credentials.snd_password) {
|
||||||
|
this.error = "Gesli se ne ujemata."
|
||||||
|
this.credentials.password = ""
|
||||||
|
this.credentials.snd_password = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = this
|
||||||
|
const post_data = {
|
||||||
|
username: this.credentials.username,
|
||||||
|
password: this.credentials.password,
|
||||||
|
email: this.credentials.email,
|
||||||
|
}
|
||||||
|
this.$http.post(this.$root.storeGet("api_addr") + "/api/register",
|
||||||
|
post_data, // the data to post
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/json',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
component.$router.push({
|
||||||
|
name: "Home"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
component.$root.store.api_error = err
|
||||||
|
component.error = "Registracija ni uspela."
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ev-login {
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
48
src/frontend_vue/src/components/Sense.vue
Normal file
48
src/frontend_vue/src/components/Sense.vue
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<template>
|
||||||
|
<div class="pb-3">
|
||||||
|
<div v-if="sense === undefined">
|
||||||
|
pomen ni definiran
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span>{{ sense.desc }}</span>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<small class="text-secondary">
|
||||||
|
- {{ sense.author }}
|
||||||
|
{{ gen_id() }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Sense",
|
||||||
|
props: ["sense"],
|
||||||
|
methods: {
|
||||||
|
gen_id: function() {
|
||||||
|
var id_arr = this.sense.sense_id.split("-")
|
||||||
|
var ret = ""
|
||||||
|
if (this.sense.author === "SSKJ") {
|
||||||
|
if (id_arr[1] !== "0") {
|
||||||
|
ret += ("[" + id_arr[1] + ["] "])
|
||||||
|
}
|
||||||
|
if (id_arr[2] !== "0") {
|
||||||
|
ret += ("pomen " + id_arr[2])
|
||||||
|
if (id_arr[3] !== "0") {
|
||||||
|
ret += ("." + id_arr[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id_arr[4] === "sopo") {
|
||||||
|
ret += " (sopomenka)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ret = this.sense.sense_id //debugging
|
||||||
|
if (ret.length > 0) {
|
||||||
|
ret = ": " + ret
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
140
src/frontend_vue/src/main.js
Normal file
140
src/frontend_vue/src/main.js
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
// The Vue build version to load with the `import` command
|
||||||
|
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App'
|
||||||
|
import router from './router'
|
||||||
|
import VueCookies from "vue-cookies"
|
||||||
|
|
||||||
|
// bootstrap
|
||||||
|
import BootstrapVue from "bootstrap-vue"
|
||||||
|
import 'bootstrap/dist/css/bootstrap.css'
|
||||||
|
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||||
|
|
||||||
|
// ajax
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
|
// config
|
||||||
|
import config_data from "../config/config.json"
|
||||||
|
// console.log(config_data)
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
// cokies
|
||||||
|
Vue.use(VueCookies)
|
||||||
|
|
||||||
|
// bootstrap
|
||||||
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
|
// CORS
|
||||||
|
// Vue.$http.headers.common['Access-Control-Allow-Origin'] = true
|
||||||
|
|
||||||
|
Vue.prototype.$http = axios
|
||||||
|
|
||||||
|
// hand-made global storage
|
||||||
|
const store = {
|
||||||
|
api_error: null,
|
||||||
|
api_addr: config_data.api_addr,
|
||||||
|
// api_addr: "http://localhost:5004", // development (webpack)
|
||||||
|
// api_addr: "http://193.2.76.103:5004", // production
|
||||||
|
token: null,
|
||||||
|
username: null,
|
||||||
|
navSS: "words",
|
||||||
|
radio: "one",
|
||||||
|
has_se: [], // used for appending (se) to certain verbs
|
||||||
|
}
|
||||||
|
|
||||||
|
const store_methods = {
|
||||||
|
storeSet: function(key, val) {
|
||||||
|
store[key] = val
|
||||||
|
},
|
||||||
|
storeGet: function(key) {
|
||||||
|
// returns undefined if not in dict.
|
||||||
|
// check if (variable)
|
||||||
|
return store[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const login_methods = {
|
||||||
|
checkToken: function () {
|
||||||
|
var tthis = this
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
if (tthis.store.token === null) {
|
||||||
|
tthis.store.username = null
|
||||||
|
reject(false)
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
token: tthis.store.token,
|
||||||
|
user: tthis.store.username
|
||||||
|
}
|
||||||
|
tthis.$http.post(tthis.store.api_addr + "/api/token", data,
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded',
|
||||||
|
}}
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
tthis.store.api_error = null
|
||||||
|
if (response.data.confirmation) {
|
||||||
|
resolve(true)
|
||||||
|
} else {
|
||||||
|
tthis.store.username = null
|
||||||
|
tthis.store.token = null
|
||||||
|
reject(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
tthis.store.api_error = err
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const other_methods = {
|
||||||
|
routeBack: function() {
|
||||||
|
this.$router.go(-1)
|
||||||
|
},
|
||||||
|
mkspace: function (idx, word) {
|
||||||
|
var stopwords = [".", ",", ":", ";"]
|
||||||
|
if (stopwords.includes(word)) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-new */
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
router,
|
||||||
|
components: { App },
|
||||||
|
template: '<App/>',
|
||||||
|
data() { return {
|
||||||
|
store: store,
|
||||||
|
}},
|
||||||
|
methods: Object.assign(store_methods, login_methods, other_methods),
|
||||||
|
beforeCreate: function() {
|
||||||
|
document.title = "Vezljivostni vzorci"
|
||||||
|
if (this.$cookies.isKey("valency_token")) {
|
||||||
|
var cookie_token = this.$cookies.get("valency_token")
|
||||||
|
var data = {
|
||||||
|
token: cookie_token,
|
||||||
|
}
|
||||||
|
var component = this
|
||||||
|
this.$http.post(store.api_addr + "/api/token",
|
||||||
|
data, // the data to post
|
||||||
|
{ headers: {
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
if (response.data.confirmation) {
|
||||||
|
store.username = response.data.username
|
||||||
|
store.token = cookie_token
|
||||||
|
} else {
|
||||||
|
this.$cookies.remove("valency_token")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
store.api_error = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
48
src/frontend_vue/src/router/index.js
Normal file
48
src/frontend_vue/src/router/index.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Router from 'vue-router'
|
||||||
|
import Home from "@/components/Home"
|
||||||
|
import Login from "@/components/Login"
|
||||||
|
import Register from "@/components/Register"
|
||||||
|
import NewPass from "@/components/NewPass"
|
||||||
|
import MainDispl from "@/components/MainDispl"
|
||||||
|
import EditSenses from "@/components/EditSenses"
|
||||||
|
|
||||||
|
Vue.use(Router)
|
||||||
|
|
||||||
|
export default new Router({
|
||||||
|
mode: "history",
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: "/home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/home",
|
||||||
|
name: "Home",
|
||||||
|
component: Home,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "words/:hw",
|
||||||
|
name: "MainDispl",
|
||||||
|
component: MainDispl,
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
name: 'Login',
|
||||||
|
component: Login
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/register',
|
||||||
|
name: 'Register',
|
||||||
|
component: Register
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/new_pass',
|
||||||
|
name: 'NewPass',
|
||||||
|
component: NewPass
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
0
src/frontend_vue/static/.gitkeep
Normal file
0
src/frontend_vue/static/.gitkeep
Normal file
3
src/frontend_vue/webpack.config.js
Normal file
3
src/frontend_vue/webpack.config.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
proxy: {
|
||||||
|
'*': 'http://localhost:8080'
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user