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/ | ||||
| *egg-info/ | ||||
| *.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