diff --git a/.travis.yml b/.travis.yml
index bb0051e51..74cd05e18 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ matrix:
- flake8 openslides tests
- isort --check-only --diff --recursive openslides tests
- python -m mypy openslides/
- - python -W ignore -m pytest --cov --cov-fail-under=75
+ - python -W ignore -m pytest --cov --cov-fail-under=70
- language: python
cache:
@@ -35,7 +35,7 @@ matrix:
- flake8 openslides tests
- isort --check-only --diff --recursive openslides tests
- python -m mypy openslides/
- - python -W ignore -m pytest --cov --cov-fail-under=75
+ - python -W ignore -m pytest --cov --cov-fail-under=70
- language: node_js
node_js:
diff --git a/DEVELOPMENT.rst b/DEVELOPMENT.rst
index 1f7f97a54..b41d15d11 100644
--- a/DEVELOPMENT.rst
+++ b/DEVELOPMENT.rst
@@ -43,31 +43,18 @@ See step 1. b. in the installation section in the `README.rst
`_.
-d. Install dependencies
-'''''''''''''''''''''''
+d. Finish the server
+''''''''''''''''''''
Install all required Python packages::
$ pip install --requirement requirements.txt
-Install all Node.js and Bower packages and run several JavaScript build tasks::
+Create a settings file, run migrations and start the server::
- $ yarn
-
-Optional: To enhance performance run Gulp in production mode::
-
- $ node_modules/.bin/gulp --production
-
-
-e. Start OpenSlides
-'''''''''''''''''''
-
-Use the command-line interface::
-
- $ python manage.py start
-
-See step 1. d. in the installation section in the `README.rst
-`_.
+ $ python manage.py createsettings
+ $ python manage.py migrate
+ $ python manage.py runserver
To get help on the command line options run::
@@ -84,13 +71,25 @@ When debugging something email related change the email backend to console::
$ python manage.py start --debug-email
-To start OpenSlides with Daphne run::
+e. Setup and start the client
+'''''''''''''''''''''''''''''
- $ python manage.py runserver
+Go in the client's directory in a second command-line interface::
-Use gulp watch in a second command-line interface::
+ $ cd client/
- $ node_modules/.bin/gulp watch
+Install all dependencies and start the development server::
+
+ $ npm install
+ $ yarn start
+
+Now the client is available under ``localhost:4200``.
+
+If you do not need to work with the client, you can build the client and let it be delivered by the server directly::
+
+ $ yarn build
+
+The client's address is now ``localhost:8000``.
2. Installation on Windows
@@ -127,16 +126,20 @@ To run some server tests see `.travis.yml
`_.
-b. Running AngularJS test cases
-'''''''''''''''''''''''''''''''
+b. Client tests and commands
+''''''''''''''''''''''''''''
-Run client tests by starting karma::
+Change to the client's directory to run every client related command. Run client tests::
- $ yarn run karma
+ $ yarn test
-Watch for file changes and run the tests automatically after each change::
+Fix the code format and lint it with::
- $ yarn run karma:watch
+ $ yarn pretty-quick && yarn lint
+
+To extract translations run::
+
+ $ yarn extract
OpenSlides in big mode
======================
@@ -207,23 +210,7 @@ This is an example configuration for a single Daphne listen on port 8000::
server_name _;
- location ~* ^/projector.*$ {
- rewrite ^.*$ /static/templates/projector-container.html;
- }
- location ~* ^/real-projector.*$ {
- rewrite ^.*$ /static/templates/projector.html;
- }
- location ~* ^/webclient.*$ {
- rewrite ^/webclient/(site|projector).*$ /static/js/webclient-$1.js;
- }
- location /static {
- alias /collected-static;
- }
- location ~* ^/(?!ws|wss|media|rest|views).*$ {
- rewrite ^.*$ /static/templates/index.html;
- }
-
- location / {
+ location ~* ^/(ws|wss|media|rest|apps).*$ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
@@ -232,4 +219,7 @@ This is an example configuration for a single Daphne listen on port 8000::
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
+ location / {
+ alias /collected-static;
+ }
}
diff --git a/README.rst b/README.rst
index e75215773..776409bcb 100644
--- a/README.rst
+++ b/README.rst
@@ -165,53 +165,7 @@ OpenSlides uses the following projects or parts of them:
* Several Python packages (see ``requirements/production.txt`` and ``requirements/big_mode.txt``).
-* Several JavaScript packages (see ``bower.json``)
-
- * `angular `_, License: MIT
- * `angular-animate `_, License: MIT
- * `angular-bootstrap-colorpicker `_, License: MIT
- * `angular-chosen-localytics `_, License: MIT
- * `angular-ckeditor `_, License: MIT
- * `angular-file-saver `_, License: MIT
- * `angular-formly `_, License: MIT
- * `angular-formly-templates-bootstrap `_, License: MIT
- * `angular-gettext `_, License: MIT
- * `angular-messages `_, License: MIT
- * `angular-pdf `_, License: MIT
- * `angular-sanitize `_, License: MIT
- * `angular-scroll-glue `_, License: MIT
- * `angular-ui-bootstrap `_, License: MIT
- * `angular-ui-router `_, License: MIT
- * `angular-ui-router-title `_, License: MIT
- * `angular-ui-tree `_, License: MIT
- * `angular-xeditable `_, License: MIT
- * `angularjs-scroll-glue `_, License: MIT
- * `angularjs-slider `_, License: MIT
- * `api-check `_, License: MIT
- * `blob-polyfill `_, License: MIT
- * `bootstrap `_, License: MIT
- * `bootstrap `_, License: MIT
- * `bootstrap-css-only `_, License: MIT
- * `bootstrap-ui-datetime-picker `_, License: MIT
- * `chosen `_, License: MIT
- * `ckeditor `_, License: (GPL-2.0 OR LGPL-2.1 OR MPL-1.1)
- * `docxtemplater `_, License: MIT
- * `file-saver.js `_, License: LICENSE.md
- * `font-awesome-bower `_, License: MIT
- * `jquery `_, License: MIT
- * `jquery.cookie `_, License: MIT
- * `js-data `_, License: MIT
- * `js-data-angular `_, License: MIT
- * `jszip `_, License: MIT or GPLv3
- * `lodash `_, License: MIT
- * `ng-dialog `_, License: MIT
- * `ng-file-upload `_, License: MIT
- * `ngbootbox `_, License: MIT
- * `ngStorage `_, License: MIT
- * `papaparse `_, License: MIT
- * `pdfjs-dist `_, License: Apache-2.0
- * `pdfmake `_, License: MIT
- * `roboto-fontface `_, License: Apache-2.0
+* Several JavaScript packages (see ``client/package.json``)
License and authors
diff --git a/bower.json b/bower.json
deleted file mode 100644
index ccb38d1a6..000000000
--- a/bower.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "name": "openslides",
- "private": true,
- "dependencies": {
- "bootstrap": "~3.3.7",
- "jquery": "~3.1.0",
- "angular": "~1.5.8",
- "angular-animate": "~1.5.8",
- "angular-bootstrap": "~2.1.3",
- "angular-bootstrap-colorpicker": "~3.0.25",
- "angular-chosen-localytics": "~1.5.0",
- "angular-ckeditor": "~1.0.3",
- "angular-file-saver": "~1.1.2",
- "angular-formly": "~8.4.0",
- "angular-formly-templates-bootstrap": "~6.2.0",
- "angular-gettext": "~2.3.7",
- "angular-messages": "~1.5.8",
- "angular-pdf": "1.3.0",
- "angular-sanitize": "~1.5.8",
- "angular-scroll-glue": "~2.0.7",
- "angular-ui-router": "~0.3.1",
- "angular-ui-tree": "https://github.com/FinnStutzenstein/angular-ui-tree.git#94dbaaff6b36f9d7a514843b73c28d2a3684c0c0",
- "angular-xeditable": "~0.5.0",
- "angularjs-slider": "~6.2.2",
- "bootstrap-css-only": "~3.3.6",
- "bootstrap-ui-datetime-picker": "~2.4.0",
- "ckeditor": "~4.7.2",
- "docxtemplater": "~2.1.5",
- "font-awesome-bower": "~4.7.0",
- "jquery.cookie": "~1.4.1",
- "js-data": "~2.9.0",
- "js-data-angular": "~3.2.1",
- "jszip": "~3.1.3",
- "lodash": "~4.16.0",
- "ng-dialog": "~0.6.4",
- "ng-file-upload": "~11.2.3",
- "ngstorage": "~0.3.11",
- "ngBootbox": "~0.1.3",
- "papaparse": "~4.1.2",
- "pdfmake": "0.1.37",
- "roboto-fontface": "~0.6.0"
- },
- "overrides": {
- "pdfmake": {
- "main": []
- },
- "pdfjs-dist": {
- "main": "build/pdf.combined.js"
- },
- "roboto-fontface": {
- "main": [
- "fonts/Roboto/Roboto-Regular.woff",
- "fonts/Roboto/Roboto-Medium.woff",
- "fonts/Roboto-Condensed/Roboto-Condensed-Regular.woff",
- "fonts/Roboto-Condensed/Roboto-Condensed-Light.woff"
- ]
- }
- },
- "resolutions": {
- "angular": ">=1.5 <1.6",
- "jquery": ">=3.1 <3.2",
- "angular-bootstrap": "~2.1.3"
- }
-}
diff --git a/client/angular.json b/client/angular.json
index fbe7a6140..ad17a72eb 100644
--- a/client/angular.json
+++ b/client/angular.json
@@ -17,7 +17,7 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
- "outputPath": "dist/client",
+ "outputPath": "../openslides/static",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
diff --git a/client/package-lock.json b/client/package-lock.json
index 511bbe3b2..2a79ae86c 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -5307,13 +5307,15 @@
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5330,19 +5332,22 @@
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5473,7 +5478,8 @@
"version": "2.0.3",
"resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -5487,6 +5493,7 @@
"resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5503,6 +5510,7 @@
"resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -5511,13 +5519,15 @@
"version": "0.0.8",
"resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"minipass": {
"version": "2.2.4",
"resolved": false,
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -5538,6 +5548,7 @@
"resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5626,7 +5637,8 @@
"version": "1.0.1",
"resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -5640,6 +5652,7 @@
"resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -5777,6 +5790,7 @@
"resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
diff --git a/client/package.json b/client/package.json
index 906b8859c..01c170fa7 100644
--- a/client/package.json
+++ b/client/package.json
@@ -10,8 +10,7 @@
"e2e": "ng e2e",
"compodoc": "./node_modules/.bin/compodoc --hideGenerator -p src/tsconfig.app.json -n 'OpenSlides Documentation' -d ../Compodoc -s -w -t -o --port",
"extract": "ngx-translate-extract -i ./src -o ./src/assets/i18n/{en,de,fr}.json --clean --sort --format-indentation ' ' --format namespaced-json",
- "format:fix": "pretty-quick --staged",
- "precommit": "run-s format:fix lint"
+ "format:fix": "pretty-quick --staged"
},
"private": true,
"dependencies": {
diff --git a/openslides/agenda/static/templates/docx/agenda.docx b/client/src/assets/docx/agenda.docx
similarity index 100%
rename from openslides/agenda/static/templates/docx/agenda.docx
rename to client/src/assets/docx/agenda.docx
diff --git a/openslides/motions/static/templates/docx/motions.docx b/client/src/assets/docx/motions.docx
similarity index 100%
rename from openslides/motions/static/templates/docx/motions.docx
rename to client/src/assets/docx/motions.docx
diff --git a/gulpfile.js b/gulpfile.js
deleted file mode 100644
index 0d1d43a25..000000000
--- a/gulpfile.js
+++ /dev/null
@@ -1,362 +0,0 @@
-/**
- * Gulp tasks for development and production.
- *
- * Run
- *
- * $ ./node_modules/.bin/gulp
- *
- * for development and
- *
- * $ ./node_modules/.bin/gulp --production
- *
- * for production mode.
- */
-
-var argv = require('yargs').argv,
- gulp = require('gulp'),
- concat = require('gulp-concat'),
- cssnano = require('gulp-cssnano'),
- gulpif = require('gulp-if'),
- gettext = require('gulp-angular-gettext'),
- inject = require('gulp-inject-string'),
- jshint = require('gulp-jshint'),
- mainBowerFiles = require('main-bower-files'),
- path = require('path'),
- rename = require('gulp-rename'),
- sass = require('gulp-sass'),
- sourcemaps = require('gulp-sourcemaps'),
- templateCache = require('gulp-angular-templatecache'),
- through = require('through2'),
- uglify = require('gulp-uglify'),
- vsprintf = require('sprintf-js').vsprintf;
-
-
-// Directory where the results go to
-var output_directory = path.join('openslides', 'static');
-
-
-// Container for all watchers
-var watchers = [];
-
-
-/**
- * Default tasks to be run before start.
- */
-
-// Catches all JavaScript files (excluded worker files) from all core apps and concats them to one
-// file js/openslides.js. In production mode the file is uglified.
-var js_src = [
- path.join('openslides', '*', 'static', 'js', '**', '*.js'),
- '!' + path.join('openslides', 'core', 'static', 'js', 'core', 'pdf-worker.js'),
-];
-
-gulp.task('js', function () {
- return gulp.src(js_src)
- .pipe(sourcemaps.init())
- .pipe(concat('openslides.js'))
- .pipe(sourcemaps.write())
- //TODO: Needs rework in all js files that uglified code works correctly.
- //.pipe(gulpif(argv.production, uglify()))
- .pipe(gulp.dest(path.join(output_directory, 'js')));
-});
-
-watchers.push(function () {
- gulp.watch(js_src, gulp.series('js'));
-});
-
-
-// Catches all JavaScript files from all bower components and concats them to
-// one file js/openslides-libs.js. In production mode the file is uglified.
-gulp.task('js_libs', function () {
- return gulp.src(mainBowerFiles({
- filter: /\.js$/
- }))
- .pipe(sourcemaps.init())
- .pipe(concat('openslides-libs.js'))
- .pipe(sourcemaps.write())
- .pipe(inject.prepend("/* set basepath of CKEditor */\n" +
- "window.CKEDITOR_BASEPATH = '/static/ckeditor/';\n\n"))
- .pipe(inject.prepend("/* Workaround for IE and pdfjs-dist#1.3.100 (see PR#3714) */\n" +
- "PDFJS = {workerSrc: 'not used but set'};\n\n"))
- .pipe(gulpif(argv.production, uglify()))
- .pipe(gulp.dest(path.join(output_directory, 'js')));
-});
-
-
-// Catches all pdfmake files for pdf worker and pdfmake library.
-var pdf_worker_src = path.join('openslides', 'core', 'static', 'js', 'core', 'pdf-worker.js');
-
-gulp.task('pdf_worker', function () {
- return gulp.src(pdf_worker_src)
- .pipe(gulpif(argv.production, uglify()))
- .pipe(gulp.dest(path.join(output_directory, 'js', 'workers')));
-});
-
-gulp.task('pdf_worker_libs', function () {
- return gulp.src(path.join('bower_components', 'pdfmake', 'build', 'pdfmake.min.js'))
- .pipe(gulpif(argv.production, uglify()))
- .pipe(rename('pdf-worker-libs.js'))
- .pipe(gulp.dest(path.join(output_directory, 'js', 'workers')));
-});
-
-watchers.push(function () {
- gulp.watch(pdf_worker_src, gulp.series('pdf_worker'));
-});
-
-
-// Catches all template files from all core apps and concats them to one
-// file js/openslides-templates.js. In production mode the file is uglified.
-var templates_src = path.join('openslides', '*', 'static', 'templates', '**', '*.html');
-
-gulp.task('templates', function () {
- return gulp.src(templates_src)
- .pipe(templateCache('openslides-templates.js', {
- module: 'OpenSlidesApp-templates',
- standalone: true,
- moduleSystem: 'IIFE',
- transformUrl: function (url) {
- var pathList = url.split(path.sep);
- pathList.shift();
- return pathList.join(path.sep);
- },
- }))
- .pipe(gulpif(argv.production, uglify()))
- .pipe(gulp.dest(path.join(output_directory, 'js')));
-});
-
-watchers.push(function () {
- gulp.watch(templates_src, gulp.series('templates'));
-});
-
-
-// Build the openslides-site.css file from the main file core/static/css/site.scss.
-// Minimizes the outputfile if the production flag is given.
-gulp.task('css_site', function () {
- return gulp.src(path.join('openslides', 'core', 'static', 'css', 'site.scss'))
- .pipe(sass().on('error', sass.logError))
- .pipe(gulpif(argv.production, cssnano({safe: true})))
- .pipe(rename('openslides-site.css'))
- .pipe(gulp.dest(path.join(output_directory, 'css')));
-});
-
-
-// Build the openslides-projector.css file from the main file core/static/css/projector.scss.
-// Minimizes the outputfile if the production flag is given.
-gulp.task('css_projector', function () {
- return gulp.src(path.join('openslides', 'core', 'static', 'css', 'projector.scss'))
- .pipe(sass().on('error', sass.logError))
- .pipe(gulpif(argv.production, cssnano({safe: true})))
- .pipe(rename('openslides-projector.css'))
- .pipe(gulp.dest(path.join(output_directory, 'css')));
-});
-
-
-// Watcher for scss files.
-// We cannot differentiate between all scss files which belong to each realm. So if
-// one scss file changes the site and projector css is rebuild.
-watchers.push(function () {
- gulp.watch(path.join('openslides', '*', 'static', 'css', '**', '*.scss'), gulp.parallel('css_site', 'css_projector'));
-});
-
-
-// Catches all CSS files from all bower components and concats them to one file
-// css/openslides-libs.css. In production mode the file is uglified.
-gulp.task('css_libs', function () {
- return gulp.src(mainBowerFiles({
- filter: /\.css$/
- }))
- .pipe(concat('openslides-libs.css'))
- .pipe(gulpif(argv.production, cssnano({safe: true})))
- .pipe(gulp.dest(path.join(output_directory, 'css')));
-});
-
-
-// Catches all font files from all bower components.
-gulp.task('fonts_libs', function () {
- return gulp.src(mainBowerFiles({
- filter: /\.(woff)|(woff2)$/
- }))
- .pipe(gulp.dest(path.join(output_directory, 'fonts')));
-});
-
-
-// Catches image files for angular-chosen.
-gulp.task('angular_chosen_img', function () {
- return gulp.src(path.join('bower_components', 'chosen', '*.png'))
- .pipe(gulp.dest(path.join(output_directory, 'css')));
-});
-
-
-// Tasks for CKEditor
-gulp.task('ckeditor_defaults', function () {
- return gulp.src([
- path.join('bower_components', 'ckeditor', 'styles.js'),
- path.join('bower_components', 'ckeditor', 'contents.css'),
- ])
- .pipe(gulp.dest(path.join(output_directory, 'ckeditor')));
-});
-
-gulp.task('ckeditor_skins', function () {
- return gulp.src(
- [
- path.join('bower_components', 'ckeditor', 'skins', 'moono-lisa', '**', '*'),
- ],
- {
- base: path.join('bower_components', 'ckeditor', 'skins')
- }
- )
- .pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'skins')));
-});
-
-gulp.task('ckeditor_plugins', function () {
- return gulp.src(
- [
- path.join('bower_components', 'ckeditor', 'plugins', 'clipboard', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'colorbutton', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'colordialog', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'dialog', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'find', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'image', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'justify', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'link', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'liststyle', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'magicline', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'pastefromword', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'panelbutton', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'showblocks', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'specialchar', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'sourcedialog', '**', '*'),
- path.join('bower_components', 'ckeditor', 'plugins', 'table', '**', '*'),
- ],
- {
- base: path.join('bower_components', 'ckeditor', 'plugins')
- }
- )
- .pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'plugins')));
-});
-
-gulp.task('ckeditor_lang', function () {
- return gulp.src([
- path.join('bower_components', 'ckeditor', 'lang', 'en.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'de.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'pt.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'es.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'fr.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'cs.js'),
- path.join('bower_components', 'ckeditor', 'lang', 'ru.js'),
- ])
- .pipe(gulp.dest(path.join(output_directory, 'ckeditor', 'lang')));
-});
-
-gulp.task('ckeditor', gulp.parallel('ckeditor_defaults', 'ckeditor_skins', 'ckeditor_plugins', 'ckeditor_lang'));
-
-
-// Compiles translation files (*.po) to *.json and saves them in the directory
-// openslides/static/i18n/.
-gulp.task('translations', function () {
- return gulp.src(path.join('openslides', 'locale', 'angular-gettext', '*.po'))
- .pipe(gettext.compile({
- format: 'json'
- }))
- .pipe(gulp.dest(path.join(output_directory, 'i18n')));
-});
-
-
-// Gulp default task. Runs all other tasks before.
-gulp.task('default', gulp.parallel(
- 'js',
- 'js_libs',
- 'pdf_worker',
- 'pdf_worker_libs',
- 'templates',
- 'css_site',
- 'css_projector',
- 'css_libs',
- 'fonts_libs',
- 'angular_chosen_img',
- 'ckeditor',
- 'translations'
-));
-
-
-/**
- * Extra tasks that have to be called manually. Useful for development.
- */
-
-// Watches changes in JavaScript and templates.
-gulp.task('watching', function () {
- // This tasks never completes because it starts all watchers and let them
- // watch forever ...
- for (var i = 0; i < watchers.length; i++) {
- watchers[i]();
- }
-});
-
-gulp.task('watch', gulp.series(gulp.parallel('js', 'pdf_worker', 'templates', 'css_site', 'css_projector'), 'watching'));
-
-
-// Extracts translatable strings using angular-gettext and saves them in file
-// openslides/locale/angular-gettext/template-en.pot.
-gulp.task('pot', function () {
- return gulp.src([
- templates_src,
- path.join('openslides', '*', 'static', 'js', '**', '*.js'),
- ])
- .pipe(gettext.extract('template-en.pot', {}))
- .pipe(gulp.dest('openslides/locale/angular-gettext/'));
-});
-
-
-// Checks JavaScript using JSHint
-gulp.task('jshint', function () {
- return gulp.src([
- 'gulpfile.js',
- path.join('openslides', '*', 'static', 'js', '**', '*.js'),
- ])
- .pipe(jshint())
- .pipe(jshint.reporter('default'))
- .pipe(jshint.reporter('fail'));
-});
-
-
-// Extracts names, URLs and licensed of all uses bower components and prints
-// it to the console. This is useful to update the README.rst during release
-// process.
-gulp.task('bower-components-for-readme', function () {
- var files = [];
- return gulp.src([
- path.join('bower_components', '*', 'bower.json'),
- path.join('bower_components', '*', 'package.json'),
- path.join('bower_components', '*', 'component.json'),
- ])
- .pipe(
- through.obj(
- function (chunk, encoding, callback) {
- files.push(chunk);
- callback();
- },
- function (callback) {
- // Extract JSON from bower.json or components.json file.
- var extracted = [];
- for (var index = 0; index < files.length; index++) {
- extracted.push(JSON.parse(files[index].contents.toString()));
- }
- // Sort files.
- extracted.sort(function (a, b) {
- return a.name < b.name ? -1 : 1;
- });
- // Print out line for README.rst.
- for (var index2 = 0; index2 < extracted.length; index2++) {
- var data = [
- extracted[index2].name,
- extracted[index2].homepage,
- extracted[index2].license,
- ];
- console.log(vsprintf(' * `%s <%s>`_, License: %s', data));
- }
- // End stream without further file processing.
- callback();
- }
- )
- );
-});
diff --git a/openslides/agenda/static/css/agenda/_list_of_speakers.scss b/openslides/agenda/static/css/agenda/_list_of_speakers.scss
deleted file mode 100644
index 2661ed101..000000000
--- a/openslides/agenda/static/css/agenda/_list_of_speakers.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-/* List of speakers */
-.lastSpeakers {
- color: #9a9898;
- margin-left: 27px;
-}
-
-.currentSpeaker {
- font-weight: bold;
-
- i.fa-microphone {
- padding-right: 5px;
- }
-}
-
-.nextSpeakers {
- margin-left: 13px;
-
- li {
- line-height: 150%;
- }
-}
diff --git a/openslides/agenda/static/css/agenda/_projector.scss b/openslides/agenda/static/css/agenda/_projector.scss
deleted file mode 100644
index 815771cf5..000000000
--- a/openslides/agenda/static/css/agenda/_projector.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-@import 'list_of_speakers';
-
-/* Agenda list */
-.agendalist-table {
- td {
- vertical-align: top;
- padding-left: 15px;
- }
-
- td.number {
- padding-left: 0;
- white-space: nowrap;
- }
-
- p.mainitem {
- font-size: 140%;
- }
-
- p.subitem {
- font-size: 100%;
- }
-}
diff --git a/openslides/agenda/static/css/agenda/_site.scss b/openslides/agenda/static/css/agenda/_site.scss
deleted file mode 100644
index f5fb60b1b..000000000
--- a/openslides/agenda/static/css/agenda/_site.scss
+++ /dev/null
@@ -1,37 +0,0 @@
-@import 'list_of_speakers';
-
-#agenda-table {
- .icon-column {
- padding: 3px;
- width: 5%;
- }
-
- .title-column {
- padding-left: 3px;
- padding-right: 10px;
- width: calc(95% - 15px );
- }
-
- .caret-spacer {
- width: 15px;
- padding: 3px;
- color: #337ab7;
- font-size: 115%;
- }
-}
-
-.agenda-sort {
- .internal {
- padding: 7px;
- opacity: 0.6;
- }
- .angular-ui-tree-node {
- min-height: 0;
- }
-}
-
-div.speakers-toolbar {
- margin: -20px -20px 30px -20px;
- padding: 12px 15px 10px 15px;
-
-}
diff --git a/openslides/agenda/static/js/agenda/base.js b/openslides/agenda/static/js/agenda/base.js
deleted file mode 100644
index d2ef7c990..000000000
--- a/openslides/agenda/static/js/agenda/base.js
+++ /dev/null
@@ -1,441 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda', ['OpenSlidesApp.users'])
-
-.factory('Speaker', [
- 'DS',
- function(DS) {
- return DS.defineResource({
- name: 'agenda/speaker',
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
- }
- }
- }
- });
- }
-])
-
-.factory('Agenda', [
- '$http',
- 'DS',
- 'Speaker',
- 'jsDataModel',
- 'Projector',
- 'ProjectHelper',
- 'gettextCatalog',
- 'gettext',
- 'CamelCase',
- 'EditForm',
- function($http, DS, Speaker, jsDataModel, Projector, ProjectHelper, gettextCatalog,
- gettext, CamelCase, EditForm) {
- var name = 'agenda/item';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Agenda'),
- computed: {
- is_public: function () {
- return !this.is_internal && !this.is_hidden;
- },
- },
- methods: {
- getResourceName: function () {
- return name;
- },
- getContentObject: function () {
- return DS.get(this.content_object.collection, this.content_object.id);
- },
- getContentObjectDetailState: function () {
- return CamelCase(this.content_object.collection).replace('/', '.') +
- '.detail({id: ' + this.content_object.id + '})';
- },
- getContentObjectForm: function () {
- return EditForm.fromCollectionString(this.content_object.collection);
- },
- getContentResource: function () {
- return DS.definitions[this.content_object.collection];
- },
- getTitle: function () {
- var title;
- try {
- title = this.getContentObject().getAgendaTitle();
- } catch (e) {
- // when the content object is not in the DS store.
- title = this.title;
- }
- if (this.item_number) {
- title = this.item_number + ' · ' + title;
- }
- return title;
- },
- getListOfSpeakersTitle: function () {
- var title;
- try {
- title = this.getContentObject().getListOfSpeakersTitle();
- if (this.item_number) {
- title = this.item_number + ' · ' + title;
- }
- } catch (e) {
- title = this.getTitle();
- }
- return title;
- },
- getAgendaTitle: function () {
- return this.title;
- },
- getCSVExportText: function () {
- var text;
- try {
- text = this.getContentObject().getCSVExportText();
- } catch (e) {
- // when the content object is not in the DS store
- // or 'getCSVExportText' is not defined return nothing.
- }
- return text;
- },
- // link name which is shown in search result
- getSearchResultName: function () {
- return this.getAgendaTitle();
- },
- // return true if a specific relation matches for given searchquery
- // (here: speakers)
- hasSearchResult: function (results) {
- var item = this;
- // search for speakers (check if any user.id from already found users matches)
- return _.some(results, function(result) {
- if (result.getResourceName() === "users/user") {
- if (_.some(item.speakers, {'user_id': result.id})) {
- return true;
- }
- }
- });
- },
- getProjectorTitle: function () {
- try {
- return this.getContentObject().getAgendaListViewTitle();
- } catch (e) {
- // when the content object is not in the DS store
- return this.list_view_title;
- }
- },
- getListViewTitle: function () {
- var title = this.getProjectorTitle();
- if (this.item_number) {
- title = this.item_number + ' · ' + title;
- }
- return title;
- },
- getItemNumberWithAncestors: function (agendaId) {
- if (!agendaId) {
- agendaId = this.id;
- }
- var agendaItem = DS.get(name, agendaId);
- if (!agendaItem) {
- return '';
- } else if (agendaItem.item_number) {
- return agendaItem.item_number;
- } else if (agendaItem.parent_id) {
- return this.getItemNumberWithAncestors(agendaItem.parent_id);
- } else {
- return '';
- }
- },
- // override project function of jsDataModel factory
- project: function (projectorId, tree) {
- if (tree) {
- var isProjectedIds = this.isProjected(tree);
- var requestData = {
- clear_ids: isProjectedIds,
- };
- // Activate, if the projector_id is a new projector.
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- requestData.prune = {
- id: projectorId,
- element: {
- name: 'agenda/item-list',
- tree: true,
- id: this.id,
- },
- };
- }
- return ProjectHelper.project(requestData);
- } else { // Project the content object
- var contentObject = DS.get(this.content_object.collection, this.content_object.id);
- return contentObject.project(projectorId);
- }
- },
- // override isProjected function of jsDataModel factory
- isProjected: function (tree) {
- // Returns all ids of all projectors with an agenda-item element. Otherwise an empty list.
- if (typeof tree === 'undefined') {
- tree = false;
- }
- var self = this;
- var predicate = function (element) {
- var value;
- if (tree) {
- // Item tree slide for sub tree
- value = element.name == 'agenda/item-list' &&
- typeof element.id !== 'undefined' &&
- element.id == self.id;
- } else {
- // Releated item detail slide
- value = element.name == self.content_object.collection &&
- typeof element.id !== 'undefined' &&
- element.id == self.content_object.id;
- }
- return value;
- };
- var isProjectedIds = [];
- Projector.getAll().forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- isProjectedIds.push(projector.id);
- }
- });
- return isProjectedIds;
- },
- isRelatedProjected: function () {
- // related objects for agenda items: list of speakers slide.
- return this.isListOfSpeakersProjected();
- },
- // project list of speakers
- projectListOfSpeakers: function(projectorId) {
- var isProjectedIds = this.isListOfSpeakersProjected();
- var requestData = {
- clear_ids: isProjectedIds,
- };
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- requestData.prune = {
- id: projectorId,
- element: {
- name: 'agenda/list-of-speakers',
- id: this.id,
- },
- };
- }
- return ProjectHelper.project(requestData);
- },
- // check if list of speakers is projected
- isListOfSpeakersProjected: function () {
- // Returns all ids of all projectors with an element with the
- // name 'agenda/list-of-speakers' and the same id. Else returns an empty list.
- var self = this;
- var predicate = function (element) {
- return element.name == 'agenda/list-of-speakers' &&
- typeof element.id !== 'undefined' &&
- element.id == self.id;
- };
- var isProjecteds = [];
- Projector.getAll().forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- isProjecteds.push(projector.id);
- }
- });
- return isProjecteds;
- },
- hasSubitems: function(items) {
- var self = this;
- var hasChild = false;
- // Returns true if the item has at least one child item.
- _.each(items, function (item) {
- if (item.parent_id == self.id) {
- hasChild = true;
- }
- });
- return hasChild;
- }
- },
- relations: {
- hasMany: {
- 'core/tag': {
- localField: 'tags',
- localKeys: 'tags_id',
- },
- 'agenda/speaker': {
- localField: 'speakers',
- foreignKey: 'item_id',
- }
- }
- },
- beforeInject: function (resource, instance) {
- Speaker.ejectAll({where: {item_id: {'==': instance.id}}});
- }
- });
- }
-])
-
-.factory('AgendaTree', [
- function () {
- return {
- getTree: function (items) {
- // Sort items after there weight
- items.sort(function(itemA, itemB) {
- return itemA.weight - itemB.weight;
- });
-
- // Build a dict with all children (dict-value) to a specific
- // item id (dict-key).
- var itemChildren = {};
-
- _.each(items, function (item) {
- if (item.parent_id) {
- // Add item to his parent. If it is the first child, then
- // create a new list.
- try {
- itemChildren[item.parent_id].push(item);
- } catch (error) {
- itemChildren[item.parent_id] = [item];
- }
- }
-
- });
-
- // Recursive function that generates a nested list with all
- // items with there children
- function getChildren(items) {
- var returnItems = [];
- _.each(items, function (item) {
- returnItems.push({
- item: item,
- children: getChildren(itemChildren[item.id]),
- id: item.id,
- });
- });
- return returnItems;
- }
-
- // Generates the list of root items (with no parents)
- var parentItems = items.filter(function (item) {
- return !item.parent_id;
- });
- return getChildren(parentItems);
- },
-
- // Returns a list of all items as a flat tree
- getFlatTree: function(items) {
- var tree = this.getTree(items);
- var flatItems = [];
-
- function generateFlatTree(tree, parentCount) {
- _.each(tree, function (item) {
- item.item.childrenCount = item.children.length;
- item.item.parentCount = parentCount;
- flatItems.push(item.item);
- generateFlatTree(item.children, parentCount + 1);
- });
- }
- generateFlatTree(tree, 0);
- return flatItems;
- }
- };
- }
-])
-
-.factory('CurrentListOfSpeakersItem', [
- 'Projector',
- 'Agenda',
- function (Projector, Agenda) {
- return {
- getItem: function (projectorId) {
- var projector = Projector.get(projectorId), item;
- if (projector) {
- _.forEach(projector.elements, function(element) {
- if (element.agenda_item_id) {
- item = Agenda.get(element.agenda_item_id);
- }
- });
- }
- return item;
- }
- };
- }
-])
-
-.factory('CurrentListOfSpeakersSlide', [
- '$http',
- 'Projector',
- function($http, Projector) {
- var name = 'agenda/current-list-of-speakers';
- return {
- project: function (projectorId, overlay) {
- var isProjected = this.isProjectedWithOverlayStatus();
- _.forEach(isProjected, function (mapping) {
- $http.post('/rest/core/projector/' + mapping.projectorId + '/deactivate_elements/',
- [mapping.uuid]
- );
- });
-
- // The slide was projected, if the id matches. If the overlay is given, also
- // the overlay is checked
- var wasProjectedBefore = _.some(isProjected, function (mapping) {
- var value = (mapping.projectorId === projectorId);
- if (overlay !== undefined) {
- value = value && (mapping.overlay === overlay);
- }
- return value;
- });
- overlay = overlay || false; // set overlay if it wasn't defined
-
- if (!wasProjectedBefore) {
- var activate = function () {
- return $http.post(
- '/rest/core/projector/' + projectorId + '/activate_elements/',
- [{name: name,
- stable: overlay, // if this is an overlay, it should not be
- // removed by changing the main content
- overlay: overlay}]
- );
- };
- if (!overlay) {
- // clear all elements on this projector, because we are _not_ using the overlay.
- $http.post('/rest/core/projector/' + projectorId + '/clear_elements/').then(activate);
- } else {
- activate();
- }
- }
- },
- isProjected: function () {
- // Returns the ids of all projectors with an agenda-item element. Else return an empty list.
- var predicate = function (element) {
- return element.name === name;
- };
- var isProjectedIds = [];
- Projector.getAll().forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- isProjectedIds.push(projector.id);
- }
- });
- return isProjectedIds;
- },
- // Returns a list of mappings between pojector id, overlay and uuid.
- isProjectedWithOverlayStatus: function () {
- var mapping = [];
- _.forEach(Projector.getAll(), function (projector) {
- _.forEach(projector.elements, function (element, uuid) {
- if (element.name === name) {
- mapping.push({
- projectorId: projector.id,
- uuid: uuid,
- overlay: element.overlay || false,
- });
- }
- });
- });
- return mapping;
- },
- };
- }
-])
-
-
-
-// Make sure that the Agenda resource is loaded.
-.run(['Agenda', function(Agenda) {}]);
-
-}());
diff --git a/openslides/agenda/static/js/agenda/csv.js b/openslides/agenda/static/js/agenda/csv.js
deleted file mode 100644
index 9de5fcb93..000000000
--- a/openslides/agenda/static/js/agenda/csv.js
+++ /dev/null
@@ -1,41 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda.csv', [])
-
-.factory('AgendaCsvExport', [
- 'HumanTimeConverter',
- 'gettextCatalog',
- 'CsvDownload',
- function (HumanTimeConverter, gettextCatalog, CsvDownload) {
- var makeHeaderline = function () {
- var headerline = ['Title', 'Text', 'Duration', 'Comment', 'Internal item'];
- return _.map(headerline, function (entry) {
- return gettextCatalog.getString(entry);
- });
- };
- return {
- export: function (agenda) {
- var csvRows = [
- makeHeaderline()
- ];
- _.forEach(agenda, function (item) {
- var row = [];
- var duration = item.duration ? HumanTimeConverter.secondsToHumanTime(item.duration*60,
- { seconds: 'disabled',
- hours: 'enabled' }) : '';
- row.push('"' + (item.title || '') + '"');
- row.push('"' + (item.getCSVExportText() || '') + '"');
- row.push('"' + duration + '"');
- row.push('"' + (item.comment || '') + '"');
- row.push('"' + (item.is_hidden ? '1' : '') + '"');
- csvRows.push(row);
- });
- CsvDownload(csvRows, gettextCatalog.getString('Agenda') + '.csv');
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/agenda/static/js/agenda/docx.js b/openslides/agenda/static/js/agenda/docx.js
deleted file mode 100644
index 1de1c92cb..000000000
--- a/openslides/agenda/static/js/agenda/docx.js
+++ /dev/null
@@ -1,84 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda.docx', ['OpenSlidesApp.core.docx'])
-
-.factory('AgendaDocxExport', [
- '$http',
- 'gettextCatalog',
- 'FileSaver',
- 'Agenda',
- 'AgendaTree',
- 'Config',
- function ($http, gettextCatalog, FileSaver, Agenda, AgendaTree, Config) {
-
- var getData = function (items) {
- // Item structure: The top layer has subitems, that are flat.
- // The first layer is bold and all sublayers not. The docx
- // templater cannot render items recursively, so the second
- // layer are all subitems flated out. Spacing is done with tabs.
- var tree = AgendaTree.getTree(items);
- var subitems = []; // This will be used as a temporary variable.
- var flatSubitems = function (children, parentCount) {
- _.forEach(children, function (child) {
- var taps = _.repeat('\t', parentCount - 1);
- subitems.push({
- item_number: taps + child.item.item_number,
- item_title: child.item.list_view_title,
- });
- flatSubitems(child.children, parentCount + 1);
- });
- };
- var twoLayerTree = _.map(tree, function (mainItem) {
- subitems = [];
- flatSubitems(mainItem.children, 1);
- return {
- item_number: mainItem.item.item_number,
- item_title: mainItem.item.list_view_title,
- subitems: subitems,
- };
- });
-
- // header
- var headerline1 = [
- Config.translate(Config.get('general_event_name').value),
- Config.translate(Config.get('general_event_description').value)
- ].filter(Boolean).join(' – ');
- var headerline2 = [
- Config.get('general_event_location').value,
- Config.get('general_event_date').value
- ].filter(Boolean).join(', ');
-
- // Data structure for the docx templater.
- return {
- header: [headerline1, headerline2].join('\n'),
- agenda_translation: gettextCatalog.getString('Agenda'),
- top_list: twoLayerTree,
- };
- };
-
- return {
- export: function (items) {
- // TODO: use filtered items.
- var filename = gettextCatalog.getString('Agenda') + '.docx';
- $http.get('/agenda/docxtemplate/').then(function (success) {
- var content = window.atob(success.data);
- var doc = new Docxgen(content);
-
- var data = getData(items);
- doc.setData(data);
- doc.render();
-
- var zip = doc.getZip();
- //zip = converter.updateZipFile(zip);
-
- var out = zip.generate({type: 'blob'});
- FileSaver.saveAs(out, filename);
- });
- },
- };
- }
-]);
-
-})();
diff --git a/openslides/agenda/static/js/agenda/pdf.js b/openslides/agenda/static/js/agenda/pdf.js
deleted file mode 100644
index 47532d835..000000000
--- a/openslides/agenda/static/js/agenda/pdf.js
+++ /dev/null
@@ -1,93 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda.pdf', ['OpenSlidesApp.core.pdf'])
-
-.factory('AgendaContentProvider', [
- 'gettextCatalog',
- 'PDFLayout',
- function(gettextCatalog, PDFLayout) {
-
- var createInstance = function(items) {
-
- // page title
- var title = PDFLayout.createTitle(gettextCatalog.getString("Agenda"));
-
- // generate the item list with all subitems
- var createItemList = function() {
- var agenda_items = [];
- _.forEach(items, function (item) {
- if (item.is_public) {
- var itemIndent = item.parentCount * 15;
-
- var itemStyle;
- if (item.parentCount === 0) {
- itemStyle = 'listParent';
- } else {
- itemStyle = 'listChild';
- }
-
- var agendaJsonString = {
- style: itemStyle,
- columns: [
- {
- width: itemIndent,
- text: ''
- },
- {
- width: 60,
- text: item.item_number
- },
- {
- text: item.title
- }
- ]
- };
-
- agenda_items.push(agendaJsonString);
- }
- });
- return agenda_items;
- };
-
- var getContent = function() {
- return [
- title,
- createItemList()
- ];
- };
-
- return {
- getContent: getContent
- };
- };
-
- return {
- createInstance: createInstance
- };
-
-}])
-
-.factory('AgendaPdfExport', [
- 'gettextCatalog',
- 'AgendaContentProvider',
- 'PdfMakeDocumentProvider',
- 'PdfCreate',
- 'Messaging',
- function (gettextCatalog, AgendaContentProvider, PdfMakeDocumentProvider, PdfCreate, Messaging) {
- return {
- export: function (items) {
- var filename = gettextCatalog.getString('Agenda') + '.pdf';
- var agendaContentProvider = AgendaContentProvider.createInstance(items);
- PdfMakeDocumentProvider.createInstance(agendaContentProvider).then(function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/agenda/static/js/agenda/projector.js b/openslides/agenda/static/js/agenda/projector.js
deleted file mode 100644
index 2c4176145..000000000
--- a/openslides/agenda/static/js/agenda/projector.js
+++ /dev/null
@@ -1,137 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda.projector', ['OpenSlidesApp.agenda'])
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('agenda/list-of-speakers', {
- template: 'static/templates/agenda/slide-list-of-speakers.html',
- });
- slidesProvider.registerSlide('agenda/item-list', {
- template: 'static/templates/agenda/slide-item-list.html',
- });
- slidesProvider.registerSlide('agenda/current-list-of-speakers', {
- template: 'static/templates/agenda/slide-current-list-of-speakers.html',
- });
- }
-])
-
-.controller('SlideCurrentListOfSpeakersCtrl', [
- '$scope',
- 'Agenda',
- 'CurrentListOfSpeakersItem',
- 'Config',
- 'Projector',
- function ($scope, Agenda, CurrentListOfSpeakersItem, Config, Projector) {
- $scope.overlay = $scope.element.overlay;
- // Watch for changes in the current list of speakers reference
- $scope.$watch(function () {
- return Config.lastModified('projector_currentListOfSpeakers_reference');
- }, function () {
- $scope.currentListOfSpeakersReference = $scope.config('projector_currentListOfSpeakers_reference');
- $scope.updateCurrentListOfSpeakers();
- });
- // Watch for changes in the referenced projector
- $scope.$watch(function () {
- return Projector.lastModified($scope.currentListOfSpeakersReference);
- }, function () {
- $scope.updateCurrentListOfSpeakers();
- });
- // Watch for changes in the current item.
- $scope.$watch(function () {
- return Agenda.lastModified();
- }, function () {
- $scope.updateCurrentListOfSpeakers();
- });
- $scope.updateCurrentListOfSpeakers = function () {
- $scope.agendaItem = CurrentListOfSpeakersItem.getItem($scope.currentListOfSpeakersReference);
- };
- }
-])
-
-.controller('SlideListOfSpeakersCtrl', [
- '$scope',
- 'Agenda',
- 'User',
- function ($scope, Agenda, User) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- Agenda.bindOne(id, $scope, 'item');
- }
-])
-
-.controller('SlideItemListCtrl', [
- '$scope',
- '$http',
- '$filter',
- 'Agenda',
- 'AgendaTree',
- 'Config',
- function ($scope, $http, $filter, Agenda, AgendaTree, Config) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
-
- // Bind agenda tree to the scope
- var items;
- $scope.$watch(function () {
- return Agenda.lastModified() +
- Config.lastModified('agenda_hide_internal_items_on_projector');
- }, function () {
- if ($scope.element.id) {
- // remove hidden items
- items = _.filter(Agenda.getAll(), function (item) {
- return !item.is_hidden;
- });
- if (Config.get('agenda_hide_internal_items_on_projector').value) {
- items = _.filter(items, function (item) {
- return item.is_public;
- });
- }
- var tree = AgendaTree.getTree(items);
-
- var getRootNode = function (node) {
- if (node.id == $scope.element.id) {
- return node;
- }
- for (var i = 0; i < node.children.length; i++) {
- var result = getRootNode(node.children[i]);
- if (result) {
- return result;
- }
- }
- return false;
- };
- _.forEach(tree, function (node) {
- var result = getRootNode(node);
- if (result) {
- $scope.rootItem = result.item;
- $scope.tree = result.children;
- return false;
- }
- });
- } else if ($scope.element.tree) {
- items = _.filter(Agenda.getAll(), function (item) {
- return item.is_public;
- });
- $scope.tree = AgendaTree.getTree(items);
- } else {
- items = Agenda.filter({
- where: { parent_id: null },
- orderBy: 'weight'
- });
- items = _.filter(items, function (item) {
- return item.is_public;
- });
- $scope.tree = AgendaTree.getTree(items);
- }
- });
- }
-]);
-
-}());
diff --git a/openslides/agenda/static/js/agenda/site.js b/openslides/agenda/static/js/agenda/site.js
deleted file mode 100644
index 2735aabdf..000000000
--- a/openslides/agenda/static/js/agenda/site.js
+++ /dev/null
@@ -1,890 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.agenda.site', [
- 'OpenSlidesApp.agenda',
- 'OpenSlidesApp.core.pdf',
- 'OpenSlidesApp.agenda.pdf',
- 'OpenSlidesApp.agenda.csv',
- 'OpenSlidesApp.agenda.docx',
-])
-
-.config([
- 'mainMenuProvider',
- 'gettext',
- function (mainMenuProvider, gettext) {
- mainMenuProvider.register({
- 'ui_sref': 'agenda.item.list',
- 'img_class': 'calendar-o',
- 'title': gettext('Agenda'),
- 'weight': 200,
- 'perm': 'agenda.can_see',
- });
- }
-])
-
-.config([
- 'SearchProvider',
- 'gettext',
- function (SearchProvider, gettext) {
- SearchProvider.register({
- 'verboseName': gettext('Agenda'),
- 'collectionName': 'agenda/item',
- 'urlDetailState': 'agenda.item.detail',
- 'weight': 200,
- });
- }
-])
-
-.config([
- '$stateProvider',
- 'gettext',
- function ($stateProvider, gettext) {
- $stateProvider
- .state('agenda', {
- url: '/agenda',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Agenda'),
- basePerm: 'agenda.can_see',
- },
- })
- .state('agenda.item', {
- abstract: true,
- template: " ",
- })
- .state('agenda.item.list', {})
- .state('agenda.item.detail', {
- resolve: {
- itemId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- .state('agenda.item.sort', {
- url: '/sort',
- controller: 'AgendaSortCtrl',
- })
- .state('agenda.current-list-of-speakers', {
- url: '/speakers',
- controller: 'CurrentListOfSpeakersViewCtrl',
- data: {
- title: gettext('Current list of speakers'),
- },
- });
- }
-])
-
-// Set the sensitivity of moving nodes horizontal for the ui-tree.
-.config([
- 'treeConfig',
- function (treeConfig) {
- treeConfig.dragMoveSensitivity = 20;
- }
-])
-
-.factory('ShowAsAgendaItemField', [
- 'operator',
- 'gettext',
- 'gettextCatalog',
- function (operator, gettext, gettextCatalog) {
- return function (managePermission) {
- return {
- key: 'agenda_type',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Agenda visibility'),
- options: [
- {type: 1, displayName: gettext('Public item')},
- {type: 2, displayName: gettext('Internal item')},
- {type: 3, displayName: gettext('Hidden item')}
- ],
- ngOptions: 'type.type as (type.displayName | translate) for type in to.options',
- },
- hide: !(operator.hasPerms(managePermission) && operator.hasPerms('agenda.can_manage'))
- };
- };
- }
-])
-
-.controller('ItemListCtrl', [
- '$scope',
- '$filter',
- '$http',
- '$state',
- 'DS',
- 'operator',
- 'ngDialog',
- 'Agenda',
- 'TopicForm', // TODO: Remove this dependency. Use template hook for "New" and "Import" buttons.
- 'AgendaTree',
- 'Projector',
- 'ProjectionDefault',
- 'gettextCatalog',
- 'gettext',
- 'osTableFilter',
- 'osTablePagination',
- 'AgendaCsvExport',
- 'AgendaPdfExport',
- 'AgendaDocxExport',
- 'ErrorMessage',
- function($scope, $filter, $http, $state, DS, operator, ngDialog, Agenda, TopicForm,
- AgendaTree, Projector, ProjectionDefault, gettextCatalog, gettext, osTableFilter,
- osTablePagination, AgendaCsvExport, AgendaPdfExport, AgendaDocxExport, ErrorMessage) {
-
- $scope.AGENDA_ITEM = 1;
- $scope.INTERNAL_ITEM = 2;
- $scope.HIDDEN_ITEM = 3;
-
- // Bind agenda tree to the scope
- $scope.$watch(function () {
- return Agenda.lastModified();
- }, function () {
- // Filter out items that doesn't have the list_item_title. This happens, if the
- // item is a hidden item but provides the list of speakers, but should not be
- // visible in the list view.
- var allowedItems = _.filter(Agenda.getAll(), function (item) {
- return item.list_view_title;
- });
- $scope.items = AgendaTree.getFlatTree(allowedItems);
- $scope.agendaHasSubitems = $filter('filter')($scope.items, {'parent_id': ''}).length;
- });
- Projector.bindAll({}, $scope, 'projectors');
- $scope.mainListTree = true;
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'agenda_all_items'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId_all_items = projectiondefault.projector_id;
- }
- $scope.projectionDefaults = ProjectionDefault.getAll();
- });
- $scope.alert = {};
-
-
- // Filtering
- $scope.filter = osTableFilter.createInstance('AgendaTableFilter');
-
- if (!$scope.filter.existsStorageEntry()) {
- $scope.filter.booleanFilters = {
- closed: {
- value: undefined,
- defaultValue: undefined,
- displayName: gettext('Closed items'),
- choiceYes: gettext('Closed items'),
- choiceNo: gettext('Open items'),
- },
- // The next filters are just on-off, so no undefined there
- is_public: {
- value: true,
- defaultValue: true,
- choiceYes: gettext('Public items'),
- choiceNo: gettext('No public items'),
- },
- is_internal: {
- value: true,
- defaultValue: true,
- choiceYes: gettext('Internal items'),
- choiceNo: gettext('No internal items'),
- permission: 'agenda.can_see_internal_items',
- },
- is_hidden: {
- value: false,
- defaultValue: false,
- choiceYes: gettext('Hidden items'),
- choiceNo: gettext('No hidden items'),
- permission: 'agenda.can_manage',
- },
- };
- }
- $scope.filter.propertyList = ['item_number', 'title', 'title_list_view', 'comment', 'duration'];
- $scope.filter.propertyFunctionList = [
- function (item) {return item.getListViewTitle();},
- ];
- $scope.areFiltersSet = function () {
- return ($scope.areVisibilityFiltersSet() ||
- $scope.filter.booleanFilters.closed.value !== $scope.filter.booleanFilters.closed.defaultValue);
- };
- $scope.areVisibilityFiltersSet = function () {
- return ($scope.filter.booleanFilters.is_public.value !== $scope.filter.booleanFilters.is_public.defaultValue ||
- $scope.filter.booleanFilters.is_internal.value !== $scope.filter.booleanFilters.is_internal.defaultValue ||
- $scope.filter.booleanFilters.is_hidden.value !== $scope.filter.booleanFilters.is_hidden.defaultValue);
-
- };
- $scope.resetFilters = function (isSelectMode) {
- if (!isSelectMode) {
- _.forEach($scope.filter.booleanFilters, function (filter) {
- filter.value = filter.defaultValue;
- });
- $scope.filter.save();
- }
- };
-
- // Expand all items during searching.
- $scope.filter.changed = function () {
- $scope.collapseState = true;
- $scope.toggleCollapseState();
- };
-
- // pagination
- $scope.pagination = osTablePagination.createInstance('AgendaTablePagination', 50);
-
- // parse duration for inline editing
- $scope.generateDurationText = function (item) {
- //convert data from model format (m) to view format (hh:mm)
- if (item.duration) {
- var time = "",
- totalminutes = item.duration;
- if (totalminutes < 0) {
- time = "-";
- totalminutes = -totalminutes;
- }
- var hh = Math.floor(totalminutes / 60);
- var mm = Math.floor(totalminutes % 60);
- // Add leading "0" for double digit values
- mm = ("0"+mm).slice(-2);
- time += hh + ":" + mm;
- item.durationText = time;
- } else {
- item.durationText = "";
- }
- };
- $scope.setDurationText = function (item) {
- //convert data from view format (hh:mm) to model format (m)
- var time = item.durationText.replace('h', '').split(':');
- var data;
- if (time.length > 1 && !isNaN(time[0]) && !isNaN(time[1])) {
- data = (+time[0]) * 60 + (+time[1]);
- if (data < 0) {
- data = "-"+data;
- }
- item.duration = parseInt(data);
- } else if (time.length == 1 && !isNaN(time[0])) {
- data = (+time[0]);
- item.duration = parseInt(data);
- } else {
- item.duration = 0;
- }
- $scope.save(item);
- };
-
- /** Duration calculations **/
- $scope.sumDurations = function () {
- var totalDuration = 0;
- $scope.items.forEach(function (item) {
- if (item.duration) {
- totalDuration += item.duration;
- }
- });
- return totalDuration;
- };
- $scope.calculateEndTime = function () {
- var totalDuration = $scope.sumDurations();
- var startTimestamp = $scope.config('agenda_start_event_date_time');
- if (startTimestamp) {
- var endTimestamp = startTimestamp + totalDuration * 60 * 1000;
- var endDate = new Date(endTimestamp);
- var mm = ("0" + endDate.getMinutes()).slice(-2);
- var dateStr = endDate.getHours() + ':' + mm;
- return dateStr;
- } else {
- return '';
- }
- };
-
- // Agenda collapse function
- $scope.toggleCollapseState = function () {
- $scope.collapseState = !$scope.collapseState;
- _.forEach($scope.items, function (item) {
- item.hideChildren = $scope.collapseState;
- });
- };
-
- // Check, if an item has childs in all filtered items
- $scope.hasChildren = function (item) {
- return _.some($scope.itemsFiltered, function (_item) {
- return _item.parent_id == item.id;
- });
- };
-
- // returns true, if the agenda has at least two layers
- $scope.agendaHasMultipleLayers = function () {
- return _.some($scope.items, function (item) {
- return item.parent_id;
- });
- };
-
- /** Agenda item functions **/
- // open dialog for new topics // TODO Remove this. Don't forget import button in template.
- $scope.newDialog = function () {
- ngDialog.open(TopicForm.getDialog());
- };
- // save changed item
- $scope.save = function (item) {
- Agenda.save(item).then(
- function (success) {
- $scope.alert.show = false;
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- // delete related item
- $scope.deleteRelatedItem = function (item) {
- DS.destroy(item.content_object.collection, item.content_object.id);
- };
- // auto numbering of agenda items
- $scope.autoNumbering = function() {
- $http.post('/rest/agenda/item/numbering/', {});
- };
- // check open permission
- // TODO: Use generic solution here.
- $scope.isAllowedToSeeOpenLink = function (item) {
- var collection = item.content_object.collection;
- switch (collection) {
- case 'topics/topic':
- return operator.hasPerms('agenda.can_see');
- case 'motions/motion':
- return operator.hasPerms('motions.can_see');
- case 'motions/motion-block':
- return operator.hasPerms('motions.can_see');
- case 'assignments/assignment':
- return operator.hasPerms('assignments.can_see');
- default:
- return false;
- }
- };
- $scope.edit = function (item) {
- ngDialog.open(item.getContentObjectForm().getDialog({id: item.content_object.id}));
- };
-
- // export
- $scope.pdfExport = function () {
- AgendaPdfExport.export($scope.itemsFiltered);
- };
- $scope.csvExport = function () {
- AgendaCsvExport.export($scope.itemsFiltered);
- };
- $scope.docxExport = function () {
- AgendaDocxExport.export($scope.itemsFiltered);
- };
-
- /** select mode functions **/
- $scope.isSelectMode = false;
- // check all checkboxes
- $scope.checkAll = function () {
- $scope.selectedAll = !$scope.selectedAll;
- angular.forEach($scope.items, function (item) {
- item.selected = $scope.selectedAll;
- });
- };
- // uncheck all checkboxes if isDeleteMode is closed
- $scope.uncheckAll = function () {
- if (!$scope.isSelectMode) {
- $scope.selectedAll = false;
- angular.forEach($scope.items, function (item) {
- item.selected = false;
- });
- }
- };
- // set type for selected items
- $scope.setTypeMultiple = function (type) {
- _.forEach($scope.items, function (item) {
- if (item.selected) {
- item.type = type;
- $scope.save(item);
- }
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // set closed for selected items
- $scope.setStateMultiple = function (closed) {
- _.forEach($scope.items, function (item) {
- if (item.selected) {
- item.closed = closed;
- $scope.save(item);
- }
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // delete selected items
- $scope.deleteMultiple = function () {
- _.forEach($scope.items, function (item) {
- if (item.selected) {
- DS.destroy(item.content_object.collection, item.content_object.id);
- }
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
-
- /** Project functions **/
- // get ProjectionDefault for item
- $scope.getProjectionDefault = function (item) {
- if (item.tree) {
- return $scope.defaultProjectorId_all_items;
- } else {
- var app_name = item.content_object.collection.split('/')[0];
- var id = 1;
- $scope.projectionDefaults.forEach(function (projectionDefault) {
- if (projectionDefault.name == app_name) {
- id = projectionDefault.projector_id;
- }
- });
- return id;
- }
- };
- // project agenda
- $scope.projectAgenda = function (projectorId, tree, id) {
- var isAgendaProjectedIds = $scope.isAgendaProjected($scope.mainListTree);
- _.forEach(isAgendaProjectedIds, function (id) {
- $http.post('/rest/core/projector/' + id + '/clear_elements/');
- });
- if (_.indexOf(isAgendaProjectedIds, projectorId) == -1) {
- $http.post('/rest/core/projector/' + projectorId + '/prune_elements/',
- [{name: 'agenda/item-list', tree: tree, id: id}]);
- }
- };
- // change whether all items or only main items should be projected
- $scope.changeMainListTree = function () {
- var isAgendaProjectedId = $scope.isAgendaProjected($scope.mainListTree);
- $scope.mainListTree = !$scope.mainListTree;
- if (isAgendaProjectedId > 0) {
- $scope.projectAgenda(isAgendaProjectedId, $scope.mainListTree);
- }
- };
- // change whether one item or all subitems should be projected
- $scope.changeItemTree = function (item) {
- var tree = item.tree;
- item.tree = !item.tree;
- var isProjected = item.isProjected(tree);
- _.forEach(isProjected, function (projectorId) {
- // Deactivate and reactivate
- item.project(projectorId, tree).then(function (s) {
- item.project(projectorId, !tree);
- });
- });
- };
- // check if agenda is projected
- $scope.isAgendaProjected = function (tree) {
- // Returns the ids of all projectors with an element with
- // the name 'agenda/item-list'. Else returns an empty list.
- var predicate = function (element) {
- var value;
- if (tree) {
- // tree with all agenda items
- value = element.name == 'agenda/item-list' &&
- typeof element.id === 'undefined' &&
- element.tree;
- } else {
- // only main agenda items
- value = element.name == 'agenda/item-list' &&
- typeof element.id === 'undefined' &&
- !element.tree;
- }
- return value;
- };
- var projectorIds = [];
- $scope.projectors.forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- projectorIds.push(projector.id);
- }
- });
- return projectorIds;
- };
- }
-])
-
-// Filter for the item type that filters the selected items by type. filters
-// are the boolean filters from the ui.
-.filter('itemTypeFilter', [
- function () {
- return function (items, filters) {
- return _.filter(items, function (item) {
- return (item.is_public && filters.is_public.value) ||
- (item.is_internal && filters.is_internal.value) ||
- (item.is_hidden && filters.is_hidden.value);
- });
- };
- }
-])
-
-// filter to hide collapsed items. Items has to be a flat tree.
-.filter('collapsedItemFilter', [
- function () {
- return function (items) {
- return _.filter(items, function (item) {
- var index = _.findIndex(items, item);
- var parentId = item.parent_id;
- // Search for parents, if one has the hideChildren attribute set. All parents
- // have a higher index as this item, because items is a flat tree.
- // If a parent has this attribute, we should remove this item. Else if we hit
- // the top or an item on the first layer, the item is not collapsed.
- for (--index; index >= 0 && parentId !== null; index--) {
- var p = items[index];
- if (p.id === parentId) {
- if (p.hideChildren) {
- return false;
- } else {
- parentId = p.parent_id;
- }
- }
- }
- return true;
- });
- };
- }
-])
-
-.controller('ItemDetailCtrl', [
- '$scope',
- '$filter',
- 'Agenda',
- 'itemId',
- 'Projector',
- 'ProjectionDefault',
- 'gettextCatalog',
- 'WebpageTitle',
- 'ErrorMessage',
- function ($scope, $filter, Agenda, itemId, Projector, ProjectionDefault, gettextCatalog, WebpageTitle,
- ErrorMessage) {
- $scope.alert = {};
-
- $scope.$watch(function () {
- return Agenda.lastModified(itemId);
- }, function () {
- $scope.item = Agenda.get(itemId);
- WebpageTitle.updateTitle(gettextCatalog.getString('List of speakers') + ' ' +
- gettextCatalog.getString('of') + ' ' + $scope.item.getTitle());
- // all speakers
- $scope.speakers = $filter('orderBy')($scope.item.speakers, 'weight');
- // next speakers
- $scope.nextSpeakers = $filter('filter')($scope.speakers, {'begin_time': null});
- // current speaker
- $scope.currentSpeaker = $filter('filter')($scope.speakers, {'begin_time': '!!', 'end_time': null});
- // last speakers
- $scope.lastSpeakers = $filter('filter')($scope.speakers, {'end_time': '!!'});
- $scope.lastSpeakers = $filter('orderBy')($scope.lastSpeakers, 'begin_time');
- });
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var item_app_name = $scope.item.content_object.collection.split('/')[0];
- var projectiondefaultItem = ProjectionDefault.filter({name: item_app_name})[0];
- if (projectiondefaultItem) {
- $scope.defaultProjectorItemId = projectiondefaultItem.projector_id;
- }
- var projectiondefaultListOfSpeakers = ProjectionDefault.filter({name: 'agenda_list_of_speakers'})[0];
- if (projectiondefaultListOfSpeakers) {
- $scope.defaultProjectorListOfSpeakersId = projectiondefaultListOfSpeakers.projector_id;
- }
- });
- }
-])
-
-/* This is the controller for the list of speakers partial management template.
- * The parent controller needs to provide a $scope.item, $scope.speakers, $scope.nextSpeakers,
- * $scope.currentSpeakers, $scope.lastSpeakers. See (as example) ItemDetailCtrl. */
-.controller('ListOfSpeakersManagementCtrl', [
- '$scope',
- '$http',
- '$filter',
- 'Agenda',
- 'User',
- 'operator',
- 'ErrorMessage',
- function ($scope, $http, $filter, Agenda, User, operator, ErrorMessage) {
- User.bindAll({}, $scope, 'users');
- $scope.speakerSelectBox = {};
-
- // close/open list of speakers of current item
- $scope.closeList = function (listClosed) {
- $scope.item.speaker_list_closed = listClosed;
- Agenda.save($scope.item);
- };
-
- // add user to list of speakers
- $scope.addSpeaker = function (userId) {
- $http.post('/rest/agenda/item/' + $scope.item.id + '/manage_speaker/', {'user': userId}).then(
- function (success) {
- $scope.alert.show = false;
- $scope.speakerSelectBox = {};
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- $scope.speakerSelectBox = {};
- }
- );
- };
-
- // delete speaker(!) from list of speakers
- $scope.removeSpeaker = function (speakerId) {
- $http.delete(
- '/rest/agenda/item/' + $scope.item.id + '/manage_speaker/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({speaker: speakerId})}
- )
- .then(function (success) {
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- //delete all speakers from list of speakers
- $scope.removeAllSpeakers = function () {
- var speakersOnList = [];
- angular.forEach($scope.item.speakers, function (speaker) {
- speakersOnList.push(speaker.id);
- });
- $http.delete(
- '/rest/agenda/item/' + $scope.item.id + '/manage_speaker/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({speaker: speakersOnList})}
- )
- .then(function (success) {
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- // Return true if the requested user is allowed to do a specific action
- // and see the corresponding button (e.g. 'add me' or 'remove me').
- $scope.isAllowed = function (action) {
- var nextUsers = [];
- angular.forEach($scope.nextSpeakers, function (speaker) {
- nextUsers.push(speaker.user_id);
- });
- switch (action) {
- case 'add':
- return (operator.hasPerms('agenda.can_be_speaker') &&
- !$scope.item.speaker_list_closed &&
- $.inArray(operator.user.id, nextUsers) == -1);
- case 'remove':
- if (operator.user) {
- return ($.inArray(operator.user.id, nextUsers) != -1);
- }
- return false;
- case 'removeAll':
- return (operator.hasPerms('agenda.can_manage_list_of_speakers') &&
- $scope.speakers.length > 0);
- case 'showLastSpeakers':
- return $scope.lastSpeakers.length > 0;
- }
- };
-
- // begin speech of selected/next speaker
- $scope.beginSpeech = function (speakerId) {
- $http.put('/rest/agenda/item/' + $scope.item.id + '/speak/', {'speaker': speakerId})
- .then(function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- // end speech of current speaker
- $scope.endSpeech = function () {
- $http.delete(
- '/rest/agenda/item/' + $scope.item.id + '/speak/',
- {headers: {'Content-Type': 'application/json'}, data: {}}
- ).then(
- function (success) {},
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- // gets speech duration of selected speaker in seconds
- $scope.getDuration = function (speaker) {
- var beginTimestamp = new Date(speaker.begin_time).getTime();
- var endTimestamp = new Date(speaker.end_time).getTime();
- // calculate duration in seconds
- return Math.floor((endTimestamp - beginTimestamp) / 1000);
-
- };
- // save reordered list of speakers
- $scope.treeOptions = {
- dropped: function (event) {
- var sortedSpeakers = _.map($scope.nextSpeakers, function (speaker) {
- return speaker.id;
- });
- $http.post('/rest/agenda/item/' + $scope.item.id + '/sort_speakers/',
- {speakers: sortedSpeakers}
- );
- }
- };
-
- // Marking a speaker
- $scope.toggleMarked = function (speaker) {
- $http.patch('/rest/agenda/item/' + $scope.item.id + '/manage_speaker/', {
- user: speaker.user.id,
- marked: !speaker.marked,
- }).then(function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('AgendaSortCtrl', [
- '$scope',
- '$http',
- 'Agenda',
- 'AgendaTree',
- 'ErrorMessage',
- function($scope, $http, Agenda, AgendaTree, ErrorMessage) {
- // Bind agenda tree to the scope
- $scope.$watch(function () {
- return Agenda.lastModified();
- }, function () {
- $scope.items = AgendaTree.getTree(Agenda.getAll());
- });
- $scope.showInternalItems = true;
- $scope.alert = {};
-
- // save parent and weight of moved agenda item (and all items on same level)
- $scope.treeOptions = {
- dropped: function(event) {
- var parentID = null;
- var droppedItemID = event.source.nodeScope.$modelValue.id;
- if (event.dest.nodesScope.item) {
- parentID = event.dest.nodesScope.item.id;
- }
- $http.post('/rest/agenda/item/sort/', {
- nodes: event.dest.nodesScope.$modelValue,
- parent_id: parentID}
- ).then(
- function(success) {},
- function(error){
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- }
- };
- }
-])
-
-.controller('CurrentListOfSpeakersViewCtrl', [
- '$scope',
- '$http',
- '$filter',
- 'Projector',
- 'ProjectionDefault',
- 'Agenda',
- 'Config',
- 'CurrentListOfSpeakersItem',
- 'CurrentListOfSpeakersSlide',
- 'gettextCatalog',
- 'WebpageTitle',
- function($scope, $http, $filter, Projector, ProjectionDefault, Agenda, Config,
- CurrentListOfSpeakersItem, CurrentListOfSpeakersSlide, gettextCatalog, WebpageTitle) {
- $scope.alert = {};
- $scope.currentListOfSpeakers = CurrentListOfSpeakersSlide;
-
- // Watch for changes in the current list of speakers reference
- $scope.$watch(function () {
- return Config.lastModified('projector_currentListOfSpeakers_reference');
- }, function () {
- $scope.currentListOfSpeakersReference = $scope.config('projector_currentListOfSpeakers_reference');
- $scope.updateCurrentListOfSpeakersItem();
- });
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function() {
- $scope.projectors = Projector.getAll();
- // If there is just one projector we provide just the overlay.
- if ($scope.projectors.length === 1) {
- $scope.currentListOfSpeakersAsOverlay = true;
- }
- $scope.updateCurrentListOfSpeakersItem();
-
- $scope.listOfSpeakersDefaultProjectorId = ProjectionDefault.filter({name: 'agenda_current_list_of_speakers'})[0].projector_id;
- });
-
- $scope.$watch(function () {
- return $scope.item ? Agenda.lastModified($scope.item.id) : void 0;
- }, function () {
- $scope.updateCurrentListOfSpeakersItem();
- });
-
- $scope.updateCurrentListOfSpeakersItem = function () {
- $scope.item = CurrentListOfSpeakersItem.getItem($scope.currentListOfSpeakersReference);
- if ($scope.item) {
- // all speakers
- $scope.speakers = $filter('orderBy')($scope.item.speakers, 'weight');
- // next speakers
- $scope.nextSpeakers = $filter('filter')($scope.speakers, {'begin_time': null});
- // current speaker
- $scope.currentSpeaker = $filter('filter')($scope.speakers, {'begin_time': '!!', 'end_time': null});
- // last speakers
- $scope.lastSpeakers = $filter('filter')($scope.speakers, {'end_time': '!!'});
- $scope.lastSpeakers = $filter('orderBy')($scope.lastSpeakers, 'begin_time');
- } else {
- $scope.speakers = void 0;
- $scope.nextSpeakers = void 0;
- $scope.currentSpeaker = void 0;
- $scope.lastSpeakers = void 0;
- }
- if ($scope.item) {
- WebpageTitle.updateTitle(gettextCatalog.getString('Current list of speakers') + ' ' +
- gettextCatalog.getString('of') + ' ' + $scope.item.getTitle());
- } else {
- WebpageTitle.updateTitle(gettextCatalog.getString('Current list of speakers'));
- }
- };
-
- // Set the current overlay status
- if ($scope.currentListOfSpeakers.isProjected().length) {
- var isProjected = $scope.currentListOfSpeakers.isProjectedWithOverlayStatus();
- $scope.currentListOfSpeakersAsOverlay = isProjected[0].overlay;
- } else {
- $scope.currentListOfSpeakersAsOverlay = false;
- }
- $scope.setOverlay = function (overlay) {
- $scope.currentListOfSpeakersAsOverlay = overlay;
- var isProjected = $scope.currentListOfSpeakers.isProjectedWithOverlayStatus();
- if (isProjected.length) {
- _.forEach(isProjected, function (mapping) {
- if (mapping.overlay != overlay) { // change the overlay if it is different
- $scope.currentListOfSpeakers.project(mapping.projectorId, overlay);
- }
- });
- }
- };
- }
-])
-
-//mark all agenda config strings for translation with Javascript
-.config([
- 'gettext',
- function (gettext) {
- gettext('Enable numbering for agenda items');
- gettext('Numbering prefix for agenda items');
- gettext('This prefix will be set if you run the automatic agenda numbering.');
- gettext('Agenda');
- gettext('Invalid input.');
- gettext('Numeral system for agenda items');
- gettext('Arabic');
- gettext('Roman');
- gettext('Begin of event');
- gettext('Input format: DD.MM.YYYY HH:MM');
- gettext('Hide internal items when projecting subitems');
- gettext('Number of last speakers to be shown on the projector');
- gettext('List of speakers');
- gettext('Show orange countdown in the last x seconds of speaking time');
- gettext('Enter duration in seconds. Choose 0 to disable warning color.');
- gettext('Couple countdown with the list of speakers');
- gettext('[Begin speech] starts the countdown, [End speech] stops the ' +
- 'countdown.');
- gettext('Agenda visibility');
- gettext('Default visibility for new agenda items (except topics)');
- }
- ]);
-
-}());
diff --git a/openslides/agenda/static/templates/agenda/current-list-of-speakers.html b/openslides/agenda/static/templates/agenda/current-list-of-speakers.html
deleted file mode 100644
index 3b665e018..000000000
--- a/openslides/agenda/static/templates/agenda/current-list-of-speakers.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/item-detail.html b/openslides/agenda/static/templates/agenda/item-detail.html
deleted file mode 100644
index de3f43d5e..000000000
--- a/openslides/agenda/static/templates/agenda/item-detail.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/item-list.html b/openslides/agenda/static/templates/agenda/item-list.html
deleted file mode 100644
index 77b5e3506..000000000
--- a/openslides/agenda/static/templates/agenda/item-list.html
+++ /dev/null
@@ -1,551 +0,0 @@
-
-
-
-
-
-
-
-
- Select ...
-
-
-
-
-
- Sort ...
-
-
-
-
-
-
- Numbering
-
-
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
-
-
-
-
{{ itemsFiltered.length }} /
- {{ (items|filter:{is_hidden:false}).length }} {{ "items" | translate }}
,
- {{(items|filter:{selected:true}).length}} {{ "selected" | translate }}
-
- ·
- Duration :
- {{ sumDurations() | osMinutesToTime }}h
-
- (Estimated end: {{ calculateEndTime() }})
-
-
-
-
- ·
-
- Expand all
- Collapse all
-
-
-
-
-
-
- Page {{ pagination.currentPage }} /
- {{ pagination.getPageCount(itemsFiltered) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Public
-
-
-
- Internal
-
-
-
- Hidden
-
-
-
-
-
-
-
-
-
-
-
- Public
-
-
-
- Internal
-
-
-
- Hidden
-
-
-
-
-
-
-
- Set duration ...
-
- {{ (item.duration | osMinutesToTime)}}
- h
-
-
-
-
-
-
- {{ item.duration | osMinutesToTime }}
- h
-
-
-
-
-
-
-
-
-
- Set comment ...
- {{ item.comment }}
-
-
-
-
-
-
-
-
- Set item number ...
- Change item number ...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/item-sort.html b/openslides/agenda/static/templates/agenda/item-sort.html
deleted file mode 100644
index e33c301a3..000000000
--- a/openslides/agenda/static/templates/agenda/item-sort.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
Drag and drop items to change the order of the agenda. Your modification will be saved immediately.
-
-
-
- Hide internal items
- Show internal items
-
-
-
- {{ alert.msg }}
-
-
-
-
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/list-of-speakers-partial-management.html b/openslides/agenda/static/templates/agenda/list-of-speakers-partial-management.html
deleted file mode 100644
index 5299fdea2..000000000
--- a/openslides/agenda/static/templates/agenda/list-of-speakers-partial-management.html
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
- The list of speakers is empty.
-
-
-
-
-
-
-
- Last speakers
- Hide
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
- {{ getDuration(speaker) | osSecondsToTime }} minutes
- (Start time :
- {{ speaker.begin_time | date:'yyyy-MM-dd HH:mm:ss' }})
-
-
-
-
-
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
- Stop
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ $index + 1 }}.
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
- Start
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers-overlay.html b/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers-overlay.html
deleted file mode 100644
index 36aeebf97..000000000
--- a/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers-overlay.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
List of speakers
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
- + {{ nextSpeakers.length - 3 }}
-
-
diff --git a/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers.html b/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers.html
deleted file mode 100644
index 2020d3727..000000000
--- a/openslides/agenda/static/templates/agenda/partial-slide-current-list-of-speakers.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
List of speakers
- {{ agendaItem.getListOfSpeakersTitle() }}
-
- – {{ (agendaItem.speakers | filter: {begin_time: null}).length }} speakers
-
- Closed
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers.html b/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers.html
deleted file mode 100644
index f4a0357f8..000000000
--- a/openslides/agenda/static/templates/agenda/slide-current-list-of-speakers.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/slide-item-list.html b/openslides/agenda/static/templates/agenda/slide-item-list.html
deleted file mode 100644
index c9fc98b0b..000000000
--- a/openslides/agenda/static/templates/agenda/slide-item-list.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
Agenda
-
{{ rootItem.getTitle() }}
-
-
-
-
-
-
diff --git a/openslides/agenda/static/templates/agenda/slide-list-of-speakers.html b/openslides/agenda/static/templates/agenda/slide-list-of-speakers.html
deleted file mode 100644
index c2b9371d0..000000000
--- a/openslides/agenda/static/templates/agenda/slide-list-of-speakers.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
List of speakers
-
- {{ item.getListOfSpeakersTitle() }}
-
- – {{ (item.speakers | filter: {begin_time: null}).length }} speakers
-
- Closed
-
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
-
- {{ speaker.user.get_full_name() }}
-
-
-
-
diff --git a/openslides/agenda/urls.py b/openslides/agenda/urls.py
deleted file mode 100644
index 2589aa2c9..000000000
--- a/openslides/agenda/urls.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.conf.urls import url
-
-from . import views
-
-
-urlpatterns = [
- url(r'^docxtemplate/$',
- views.AgendaDocxTemplateView.as_view(),
- name='agenda_docx_template'),
-]
diff --git a/openslides/agenda/views.py b/openslides/agenda/views.py
index f324c57d0..3d2d143f2 100644
--- a/openslides/agenda/views.py
+++ b/openslides/agenda/views.py
@@ -15,7 +15,6 @@ from openslides.utils.rest_api import (
detail_route,
list_route,
)
-from openslides.utils.views import BinaryTemplateView
from ..utils.auth import has_perm
from .access_permissions import ItemAccessPermissions
@@ -340,11 +339,3 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
inform_changed_data(items)
return Response({'detail': _('The agenda has been sorted.')})
-
-
-# Special views
-class AgendaDocxTemplateView(BinaryTemplateView):
- """
- Returns the template for motions docx export
- """
- template_name = 'templates/docx/agenda.docx'
diff --git a/openslides/assignments/static/css/assignments/_projector.scss b/openslides/assignments/static/css/assignments/_projector.scss
deleted file mode 100644
index bfd37c454..000000000
--- a/openslides/assignments/static/css/assignments/_projector.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-.electionresults table {
- width: calc(100% - 230px);
-}
-
-#speakerbox {
- width: 40%;
- float: right;
- margin: 20px;
- right: 0;
- bottom: 0;
- position: absolute;
- background: #d3d3d3;
- border-radius: 7px;
- border: 1px solid #999;
- padding: 0px 7px 10px 19px;
- z-index: 99;
- box-shadow: 3px 3px 10px 1px rgba(0,0,0,0.5);
- overflow: hidden;
-}
diff --git a/openslides/assignments/static/css/assignments/_site.scss b/openslides/assignments/static/css/assignments/_site.scss
deleted file mode 100644
index e7c8fa269..000000000
--- a/openslides/assignments/static/css/assignments/_site.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-#content .col1 .ballot-tabs {
- ul {
- margin-left: 0px;
- }
- li.active a {
- background-color: #f5f5f5 !important;
- }
- .tab-content {
- background-color: #f5f5f5;
- border: 1px solid #ddd;
- border-width: 0px 1px 1px 1px;
- padding: 15px;
- }
-}
diff --git a/openslides/assignments/static/js/assignments/base.js b/openslides/assignments/static/js/assignments/base.js
deleted file mode 100644
index 08f481809..000000000
--- a/openslides/assignments/static/js/assignments/base.js
+++ /dev/null
@@ -1,500 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.assignments', [])
-
-.factory('AssignmentPollOption', [
- 'DS',
- 'jsDataModel',
- 'gettextCatalog',
- 'Config',
- 'MajorityMethods',
- function (DS, jsDataModel, gettextCatalog, Config, MajorityMethods) {
- return DS.defineResource({
- name: 'assignments/polloption',
- useClass: jsDataModel,
- // Change the stringified numbers to floats.
- beforeInject: function (resource, instance) {
- _.forEach(instance.votes, function (vote) {
- vote.weight = parseFloat(vote.weight);
- });
- },
- methods: {
- getVotes: function () {
- if (!this.poll.has_votes) {
- // Return undefined if this poll has no votes.
- return;
- }
-
- // Initial values for the option
- var votes = [],
- config = Config.get('assignments_poll_100_percent_base').value;
-
- var base = this.poll.getPercentBase(config);
- if (typeof base === 'object' && base !== null) {
- // this.poll.pollmethod === 'yna'
- base = base[this.id];
- }
-
- _.forEach(this.votes, function (vote) {
- // Initial values for the vote
- var order = '',
- value = '',
- percentStr = '',
- percentNumber;
-
- // Check for special value
- switch (vote.weight) {
- case -1:
- value = gettextCatalog.getString('majority');
- break;
- case -2:
- value = gettextCatalog.getString('undocumented');
- break;
- default:
- if (vote.weight >= 0) {
- value = vote.weight;
- } else {
- value = 0; // Vote was not defined. Set value to 0.
- }
- }
- switch (vote.value) {
- case "Yes":
- order = 1;
- break;
- case "No":
- order = 2;
- break;
- case "Abstain":
- order = 3;
- break;
- default:
- order = 0;
- }
-
- // Special case where to skip percents
- var skipPercents = config === 'YES_NO' && vote.value === 'Abstain';
-
- if (base && !skipPercents) {
- percentNumber = Math.round(vote.weight * 100 / base * 100) / 100;
- if (percentNumber >= 0) {
- percentStr = '(' + percentNumber + ' %)';
- }
- }
- votes.push({
- 'order': order,
- 'label': gettextCatalog.getString(vote.value),
- 'value': value,
- 'percentStr': percentStr,
- 'percentNumber': percentNumber
- });
- });
- return _.sortBy(votes, 'order');
- },
-
- // Returns 0 or positive integer if quorum is reached or surpassed.
- // Returns negativ integer if quorum is not reached.
- // Returns undefined if we can not calculate the quorum.
- isReached: function (method) {
- if (!this.poll.has_votes) {
- // Return undefined if this poll has no votes.
- return;
- }
- var isReached;
- var config = Config.get('assignments_poll_100_percent_base').value;
- var base = this.poll.getPercentBase(config);
- if (typeof base === 'object' && base !== null) {
- // this.poll.pollmethod === 'yna'
- base = base[this.id];
- }
- if (base) {
- // Provide result only if base is not undefined and not 0.
- isReached = MajorityMethods[method](this.getVoteYes(), base);
- }
- return isReached;
- },
-
- // Returns the weight for the vote or the vote 'yes' in case of YNA poll method.
- getVoteYes: function () {
- var voteYes = 0;
- if (this.poll.pollmethod === 'yna') {
- var voteObj = _.find(this.votes, function (vote) {
- return vote.value === 'Yes';
- });
- if (voteObj) {
- voteYes = voteObj.weight;
- }
- } else {
- // pollmethod === 'votes'
- voteYes = this.votes[0].weight;
- }
- return voteYes;
- }
- },
- relations: {
- belongsTo: {
- 'assignments/poll': {
- localField: 'poll',
- localKey: 'poll_id',
- },
- 'users/user': {
- localField: 'candidate',
- localKey: 'candidate_id',
- }
- }
- },
- });
- }
-])
-
-.factory('AssignmentPoll', [
- '$http',
- 'DS',
- 'jsDataModel',
- 'gettextCatalog',
- 'AssignmentPollOption',
- 'Config',
- function ($http, DS, jsDataModel, gettextCatalog, AssignmentPollOption, Config) {
- var name = 'assignments/poll';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- // Change the stringified numbers to floats.
- beforeInject: function (resource, instance) {
- var attrs = ['votescast', 'votesinvalid', 'votesvalid', 'votesabstain', 'votesno'];
- _.forEach(attrs, function (attr) {
- if (instance[attr] !== null) {
- instance[attr] = parseFloat(instance[attr]);
- }
- });
- },
- methods: {
- getResourceName: function () {
- return name;
- },
-
- // Returns percent base. Returns undefined if calculation is not possible in general.
- getPercentBase: function (config, type) {
- var base;
- switch (config) {
- case 'CAST':
- if (this.votescast <= 0 || this.votesinvalid < 0) {
- // It would be OK to check only this.votescast < 0 because 0
- // is checked again later but this is a little bit faster.
- break;
- }
- base = this.votescast;
- /* falls through */
- case 'VALID':
- if (this.votesvalid < 0) {
- base = void 0;
- break;
- }
- if (typeof base === 'undefined' && type !== 'votescast' && type !== 'votesinvalid') {
- base = this.votesvalid;
- }
- /* falls through */
- case 'YES_NO_ABSTAIN':
- case 'YES_NO':
- if (this.pollmethod === 'yna') {
- if (typeof base === 'undefined' && type !== 'votescast' && type !== 'votesinvalid' && type !== 'votesvalid') {
- base = {};
- _.forEach(this.options, function (option) {
- var allVotes = option.votes;
- if (config === 'YES_NO') {
- allVotes = _.filter(allVotes, function (vote) {
- // Extract abstain votes in case of YES_NO percent base.
- // Do not extract abstain vote if it is set to majority so the predicate later
- // fails and therefor we get an undefined base. Reason: It should not be possible
- // to set abstain to majority and nevertheless calculate percents of yes and no.
- return vote.value !== 'Abstain' || vote.weight === -1;
- });
- }
- var predicate = function (vote) {
- return vote.weight < 0;
- };
- if (_.findIndex(allVotes, predicate) === -1) {
- base[option.id] = _.reduce(allVotes, function (sum, vote) {
- return sum + vote.weight;
- }, 0);
- }
- });
- }
- } else {
- // this.pollmethod === 'votes'
- var predicate = function (option) {
- return option.votes[0].weight < 0;
- };
- if (_.findIndex(this.options, predicate) !== -1) {
- base = void 0;
- } else {
- if (typeof base === 'undefined' && type !== 'votesabstain' &&
- type !== 'votesno' && type !== 'votescast' &&
- type !== 'votesinvalid' && type !== 'votesvalid') {
- base = _.reduce(this.options, function (sum, option) {
- return sum + option.votes[0].weight;
- }, 0);
- }
- }
- }
- }
- return base;
- },
-
- // Returns object with value and percent for this poll (for votes valid/invalid/cast only).
- getVote: function (type) {
- if (!this.has_votes) {
- // Return undefined if this poll has no votes.
- return;
- }
-
- // Initial values
- var value = '',
- percentStr = '',
- percentNumber,
- vote,
- config = Config.get('assignments_poll_100_percent_base').value;
-
- switch (type) {
- case 'votesabstain':
- vote = this.votesabstain;
- break;
- case 'votesno':
- vote = this.votesno;
- break;
- case 'votesinvalid':
- vote = this.votesinvalid;
- break;
- case 'votesvalid':
- vote = this.votesvalid;
- break;
- case 'votescast':
- vote = this.votescast;
- break;
- }
-
- // Check special values
- switch (vote) {
- case -1:
- value = gettextCatalog.getString('majority');
- break;
- case -2:
- value = gettextCatalog.getString('undocumented');
- break;
- default:
- if (vote >= 0) {
- value = vote;
- } else {
- value = 0; // value was not defined
- }
- }
-
- // Calculate percent value
- var base = this.getPercentBase(config, type);
- if (base) {
- percentNumber = Math.round(vote * 100 / (base) * 10) / 10;
- percentStr = '(' + percentNumber + ' %)';
- }
- return {
- 'value': value,
- 'percentStr': percentStr,
- 'percentNumber': percentNumber,
- 'display': value + ' ' + percentStr
- };
- }
- },
- relations: {
- belongsTo: {
- 'assignments/assignment': {
- localField: 'assignment',
- localKey: 'assignment_id',
- }
- },
- hasMany: {
- 'assignments/polloption': {
- localField: 'options',
- foreignKey: 'poll_id',
- }
- }
- },
- });
- }
-])
-
-.provider('AssignmentPollDecimalPlaces', [
- function () {
- this.$get = ['$q', function ($q) {
- return {
- getPlaces: function (poll, find) {
- if (find) {
- return $q(function (resolve) {
- resolve(0);
- });
- } else {
- return 0;
- }
- },
- };
- }];
- }
-])
-
-.factory('AssignmentRelatedUser', [
- 'DS',
- function (DS) {
- return DS.defineResource({
- name: 'assignments/relateduser',
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
- }
- }
- }
- });
- }
-])
-
-.factory('Assignment', [
- '$http',
- 'DS',
- 'Projector',
- 'ProjectHelper',
- 'AssignmentRelatedUser',
- 'AssignmentPoll',
- 'jsDataModel',
- 'gettext',
- function ($http, DS, Projector, ProjectHelper, AssignmentRelatedUser, AssignmentPoll,
- jsDataModel, gettext) {
- var name = 'assignments/assignment';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Election'),
- verboseNamePlural: gettext('Elections'),
- methods: {
- getResourceName: function () {
- return name;
- },
- getTitle: function () {
- return this.title;
- },
- getAgendaTitle: function () {
- return this.getTitle();
- },
- // link name which is shown in search result
- getSearchResultName: function () {
- return this.getAgendaTitle();
- },
- // return true if a specific relation matches for given searchquery
- // (here: related_users/candidates)
- hasSearchResult: function (results) {
- var assignment = this;
- // search for related users (check if any user.id from already found users matches)
- return _.some(results, function(result) {
- if (result.getResourceName() === "users/user") {
- if (_.some(assignment.assignment_related_users, {'user_id': result.id})) {
- return true;
- }
- }
- });
- },
- // override project function of jsDataModel factory
- project: function (projectorId, pollId) {
- var isProjectedIds = this.isProjected(pollId);
- var requestData = {
- clear_ids: isProjectedIds,
- };
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- requestData.prune = {
- id: projectorId,
- element: {
- name: 'assignments/assignment',
- id: this.id,
- poll: pollId
- },
- };
- }
- return ProjectHelper.project(requestData);
- },
- // override isProjected function of jsDataModel factory
- isProjected: function (poll_id, anyPoll) {
- // Returns the ids of all projectors with an element
- // with the name 'assignments/assignment'. Else returns an empty list.
- // Provide a poll_id to query a specific poll or set anyPoll to true, to
- // query whether any poll (but not the assignment itself) is projected.
- var self = this;
- var predicate = function (element) {
- var value;
- if (typeof poll_id === 'undefined') {
- // Assignment detail slide without poll
- value = element.name == 'assignments/assignment' &&
- typeof element.id !== 'undefined' &&
- element.id == self.id &&
- typeof element.poll === 'undefined';
- } else if (anyPoll) {
- // Assignment detail slide with any poll
- value = element.name == 'assignments/assignment' &&
- typeof element.id !== 'undefined' &&
- element.id == self.id &&
- typeof element.poll !== 'undefined';
- } else {
- // Assignment detail slide with specific poll
- value = element.name == 'assignments/assignment' &&
- typeof element.id !== 'undefined' &&
- element.id == self.id &&
- typeof element.poll !== 'undefined' &&
- element.poll == poll_id;
- }
- return value;
- };
- var isProjectedIds = [];
- Projector.getAll().forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- isProjectedIds.push(projector.id);
- }
- });
- return isProjectedIds;
- },
- isRelatedProjected: function () {
- var listOfSpeakers = [];
- if (this.agenda_item) {
- listOfSpeakers = this.agenda_item.isListOfSpeakersProjected();
- }
- return listOfSpeakers.concat(this.isProjected(null, true));
- },
- },
- relations: {
- belongsTo: {
- 'agenda/item': {
- localKey: 'agenda_item_id',
- localField: 'agenda_item',
- }
- },
- hasMany: {
- 'core/tag': {
- localField: 'tags',
- localKeys: 'tags_id',
- },
- 'assignments/relateduser': {
- localField: 'assignment_related_users',
- foreignKey: 'assignment_id',
- },
- 'assignments/poll': {
- localField: 'polls',
- foreignKey: 'assignment_id',
- }
- }
- },
- beforeInject: function (resource, instance) {
- AssignmentRelatedUser.ejectAll({where: {assignment_id: {'==': instance.id}}});
- }
- });
- }
-])
-
-.run(['Assignment', function(Assignment) {}]);
-
-}());
diff --git a/openslides/assignments/static/js/assignments/pdf.js b/openslides/assignments/static/js/assignments/pdf.js
deleted file mode 100644
index bbd4399dc..000000000
--- a/openslides/assignments/static/js/assignments/pdf.js
+++ /dev/null
@@ -1,666 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
-
-.factory('AssignmentContentProvider', [
- '$filter',
- 'HTMLValidizer',
- 'gettextCatalog',
- 'PDFLayout',
- 'AssignmentPollDecimalPlaces',
- function($filter, HTMLValidizer, gettextCatalog, PDFLayout, AssignmentPollDecimalPlaces) {
-
- var createInstance = function(assignment) {
-
- // page title
- var title = PDFLayout.createTitle(assignment.title);
- var isElectedSemaphore = false;
-
- // open posts
- var createPreamble = function() {
- var preambleText = gettextCatalog.getString("Number of persons to be elected") + ": ";
- var memberNumber = ""+assignment.open_posts;
- var preamble = {
- text: [
- {
- text: preambleText,
- bold: true,
- style: 'textItem'
- },
- {
- text: memberNumber,
- style: 'textItem'
- }
- ]
- };
- return preamble;
- };
-
- // description
- var createDescription = function() {
- if (assignment.description) {
- var html = HTMLValidizer.validize(assignment.description);
- var descriptionText = gettextCatalog.getString("Description") + ":";
- var description = [
- {
- text: descriptionText,
- bold: true,
- style: 'textItem'
- },
- {
- text: $(html).text(),
- style: 'textItem',
- margin: [10, 0, 0, 0]
- }
- ];
- return description;
- } else {
- return "";
- }
- };
-
- // show candidate list (if assignment phase is not 'finished')
- var createCandidateList = function() {
- if (assignment.phase != 2) {
- var candidates = $filter('orderBy')(assignment.assignment_related_users, 'weight');
- var candidatesText = gettextCatalog.getString("Candidates") + ": ";
- var userList = [];
-
- _.forEach(candidates, function(assignmentsRelatedUser) {
- userList.push({
- text: assignmentsRelatedUser.user.get_full_name(),
- margin: [0, 0, 0, 10],
- }
- );
- });
-
- var cadidateList = {
- columns: [
- {
- text: candidatesText,
- bold: true,
- width: "25%",
- style: 'textItem'
- },
- {
- ul: userList,
- style: 'textItem'
- }
- ]
- };
- return cadidateList;
- } else {
- return "";
- }
- };
-
- // handles the case if a candidate is elected or not
- var electedCandidateLine = function(candidateName, pollOption, pollTableBody) {
- if (pollOption.is_elected) {
- isElectedSemaphore = true;
- return {
- text: candidateName + "*",
- bold: true,
- style: PDFLayout.flipTableRowStyle(pollTableBody.length)
- };
- } else {
- return {
- text: candidateName,
- style: PDFLayout.flipTableRowStyle(pollTableBody.length)
- };
- }
- };
-
- //creates the voting string for the result table and differentiates between special values
- var parseVoteValue = function(voteObject, printLabel, precision) {
- var voteVal = '';
- if (voteObject) {
- if (printLabel) {
- voteVal += voteObject.label + ': ';
- }
- voteVal += $filter('number')(voteObject.value, precision);
-
- if (voteObject.percentStr) {
- voteVal += ' ' + voteObject.percentStr;
- }
- }
- voteVal += '\n';
- return voteVal;
- };
-
- // creates the election result table
- var createPollResultTable = function() {
- var resultBody = [];
- _.forEach(assignment.polls, function(poll, pollIndex) {
- if (poll.published) {
- var pollTableBody = [];
- var precision = AssignmentPollDecimalPlaces.getPlaces(poll);
-
- resultBody.push({
- text: gettextCatalog.getString('Ballot') + ' ' + (pollIndex+1),
- bold: true,
- style: 'textItem',
- margin: [0, 15, 0, 0]
- });
-
- pollTableBody.push([
- {
- text: gettextCatalog.getString('Candidates'),
- style: 'tableHeader',
- },
- {
- text: gettextCatalog.getString('Votes'),
- style: 'tableHeader',
- }
- ]);
-
- _.forEach(poll.options, function(pollOption, optionIndex) {
- var candidateName = pollOption.candidate.get_full_name();
- var votes = pollOption.getVotes(); // 0 = yes, 1 = no, 2 = abstain
- var tableLine = [];
-
- tableLine.push(electedCandidateLine(candidateName, pollOption, pollTableBody));
- if (poll.pollmethod == 'votes') {
- tableLine.push(
- {
- text: parseVoteValue(votes[0], false, precision),
- style: PDFLayout.flipTableRowStyle(pollTableBody.length)
- }
- );
- } else {
- var resultBlock = [];
- _.forEach(votes, function(vote) {
- resultBlock.push(parseVoteValue(vote, true, precision));
- });
- tableLine.push({
- text: resultBlock,
- style: PDFLayout.flipTableRowStyle(pollTableBody.length)
- }
- );
- }
- pollTableBody.push(tableLine);
- });
-
- var pushConcludeRow = function (title, fieldName) {
- if (poll[fieldName]) {
- pollTableBody.push([
- {
- text: gettextCatalog.getString(title),
- style: 'tableConclude'
- },
- {
- text: parseVoteValue(poll.getVote(fieldName), false, precision),
- style: 'tableConclude'
- },
- ]);
- }
- };
-
- pushConcludeRow('Abstain', 'votesabstain');
- pushConcludeRow('No', 'votesno');
- pushConcludeRow('Valid ballots', 'votesvalid');
- pushConcludeRow('Invalid ballots', 'votesinvalid');
- pushConcludeRow('Casted ballots', 'votescast');
-
- var resultTableJsonSting = {
- table: {
- widths: ['64%','33%'],
- headerRows: 1,
- body: pollTableBody,
- },
- layout: 'headerLineOnly',
- };
-
- resultBody.push(resultTableJsonSting);
- }
- });
-
- // add the legend to the result body
- if (assignment.polls.length > 0 && isElectedSemaphore) {
- resultBody.push({
- text: '* = ' + gettextCatalog.getString('is elected'),
- margin: [0, 5, 0, 0],
- });
- }
-
- return resultBody;
- };
-
- var getContent = function() {
- return [
- title,
- createPreamble(),
- createDescription(),
- createCandidateList(),
- createPollResultTable()
- ];
- };
-
- return {
- getContent: getContent,
- title: assignment.title
- };
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('BallotContentProvider', [
- '$q',
- '$filter',
- 'gettextCatalog',
- 'PDFLayout',
- 'Config',
- 'User',
- 'ImageConverter',
- function($q, $filter, gettextCatalog, PDFLayout, Config, User, ImageConverter) {
- var createInstance = function(assignment, poll, pollNumber) {
-
- var logoBallotPaperUrl = Config.get('logo_pdf_ballot_paper').value.path;
- var imageMap = {};
-
- // PDF header
- var header = function() {
- var columns = [];
-
- // logo
- if (logoBallotPaperUrl) {
- columns.push({
- image: logoBallotPaperUrl,
- fit: [90,20],
- width: '20%'
- });
- }
- var text = Config.get('general_event_name').value;
- columns.push({
- text: text,
- fontSize: 8,
- alignment: 'right',
- });
-
- return {
- color: '#555',
- margin: [30, 10, 10, -10], // [left, top, right, bottom]
- columns: columns,
- columnGap: 10
- };
- };
-
- // page title
- var createTitle = function() {
- return {
- text: assignment.title,
- style: 'title',
- };
- };
-
- // poll description
- var createPollHint = function() {
- var description = poll.description ? ': ' + poll.description : '';
- return {
- text: gettextCatalog.getString("Ballot") + " " + pollNumber + description,
- style: 'description',
- };
- };
-
- // election entries
- var createYNBallotEntry = function(decision) {
- var YNColumn = [
- {
- width: "auto",
- stack: [
- PDFLayout.createBallotEntry(gettextCatalog.getString("Yes"))
- ]
- },
- {
- width: "auto",
- stack: [
- PDFLayout.createBallotEntry(gettextCatalog.getString("No"))
- ]
- },
- ];
-
- if (poll.pollmethod == 'yna') {
- YNColumn.push({
- width: "auto",
- stack: [
- PDFLayout.createBallotEntry(gettextCatalog.getString("Abstain"))
- ]
- });
- }
-
- return [
- {
- text: decision,
- margin: [40, 10, 0, 0],
- },
- {
- columns: YNColumn
- }
- ];
- };
-
- var createSelectionField = function() {
- var candidates = $filter('orderBy')(poll.options, 'weight');
- var candidateBallotList = [];
-
- if (poll.pollmethod == 'votes') {
- _.forEach(candidates, function(option) {
- var candidate = option.candidate.get_full_name();
- candidateBallotList.push(PDFLayout.createBallotEntry(candidate));
- });
- // Add 'no' option
- var no = gettextCatalog.getString('No');
- var ballotEntry = PDFLayout.createBallotEntry(no);
- ballotEntry.margin[1] = 25; // top margin
- candidateBallotList.push(ballotEntry);
- } else {
- _.forEach(candidates, function(option) {
- var candidate;
- if (option.candidate) {
- candidate = option.candidate.get_full_name();
- }
- candidateBallotList.push(createYNBallotEntry(candidate));
- });
- }
- return candidateBallotList;
- };
-
- var createSection = function(marginTop) {
-
- // since it is not possible to give a column a fixed height, we draw an "empty" column
- // with a one px width and a fixed top-margin
- return {
- columns: [
- {
- width: 1,
- margin: [0, marginTop],
- text: '',
- },
- {
- width: '*',
- stack: [
- header(),
- createTitle(),
- createPollHint(),
- createSelectionField(),
- ],
- },
- ]
- };
- };
-
- var createTableBody = function(numberOfRows, sheetend, maxballots) {
- var ballotstoprint = numberOfRows * 2;
- if (Number.isInteger(maxballots) && maxballots > 0 && maxballots < ballotstoprint) {
- ballotstoprint = maxballots;
- }
- var tableBody = [];
- while (ballotstoprint > 1){
- tableBody.push([createSection(sheetend), createSection(sheetend)]);
- ballotstoprint -= 2;
- }
- if (ballotstoprint == 1) {
- tableBody.push([createSection(sheetend), '']);
- }
- return tableBody;
- };
-
- var createContentTable = function() {
- // first, determine how many ballots we need
- var amount;
- var amount_method = Config.get('assignments_pdf_ballot_papers_selection').value;
- switch (amount_method) {
- case 'NUMBER_OF_ALL_PARTICIPANTS':
- amount = User.getAll().length;
- break;
- case 'NUMBER_OF_DELEGATES':
- //TODO: assumption that DELEGATES is always group id 2. This may not be true
- var group_id = 2;
- amount = User.filter({where: {'groups_id': {contains:group_id} }}).length;
- break;
- case 'CUSTOM_NUMBER':
- amount = Config.get('assignments_pdf_ballot_papers_number').value;
- break;
- default:
- // should not happen.
- amount = 0;
- }
- var tabledContent = [];
- var rowsperpage;
- var sheetend;
- if (poll.pollmethod == 'votes') {
- if (poll.options.length <= 4) {
- sheetend = 105;
- rowsperpage = 4;
- } else if (poll.options.length <= 8) {
- sheetend = 140;
- rowsperpage = 3;
- } else if (poll.options.length <= 12) {
- sheetend = 210;
- rowsperpage = 2;
- }
- else { //works untill ~30 people
- sheetend = 418;
- rowsperpage = 1;
- }
- } else {
- if (poll.options.length <= 2) {
- sheetend = 105;
- rowsperpage = 4;
- } else if (poll.options.length <= 4) {
- sheetend = 140;
- rowsperpage = 3;
- } else if (poll.options.length <= 6) {
- sheetend = 210;
- rowsperpage = 2;
- } else {
- sheetend = 418;
- rowsperpage = 1;
- }
- }
- var page_entries = rowsperpage * 2;
- var fullpages = Math.floor(amount / page_entries);
- for (var i=0; i < fullpages; i++) {
- tabledContent.push({
- table: {
- headerRows: 1,
- widths: ['50%', '50%'],
- body: createTableBody(rowsperpage, sheetend),
- pageBreak: 'after'
- },
- layout: PDFLayout.getBallotLayoutLines(),
- rowsperpage: rowsperpage
- });
- }
- // fill the last page only partially
- var lastpage_ballots = amount - (fullpages * page_entries);
- if (lastpage_ballots < page_entries && lastpage_ballots > 0){
- var partialpage = createTableBody(rowsperpage, sheetend, lastpage_ballots);
- tabledContent.push({
- table: {
- headerRows: 1,
- widths: ['50%', '50%'],
- body: partialpage
- },
- layout: PDFLayout.getBallotLayoutLines(),
- rowsperpage: rowsperpage
- });
- }
- return tabledContent;
- };
-
- var getContent = function() {
- return createContentTable();
- };
-
- var getImageMap = function () {
- return imageMap;
- };
-
- return $q(function (resolve, reject) {
- var imageSources = [
- logoBallotPaperUrl,
- ];
- ImageConverter.toBase64(imageSources).then(function (_imageMap) {
- imageMap = _imageMap;
- resolve({
- getContent: getContent,
- getImageMap: getImageMap,
- });
- }, reject);
- });
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('AssignmentCatalogContentProvider', [
- 'gettextCatalog',
- 'PDFLayout',
- 'Config',
- function(gettextCatalog, PDFLayout, Config) {
-
- var createInstance = function(allAssignments) {
-
- var title = PDFLayout.createTitle(
- Config.translate(Config.get('assignments_pdf_title').value)
- );
-
- var createPreamble = function() {
- var preambleText = Config.get('assignments_pdf_preamble').value;
- if (preambleText) {
- return {
- text: preambleText,
- style: "preamble"
- };
- } else {
- return "";
- }
- };
-
- var createTOContent = function(assignmentTitles) {
- var heading = {
- text: gettextCatalog.getString("Table of contents"),
- style: "heading2",
- };
-
- var toc = [];
- _.forEach(assignmentTitles, function(title) {
- toc.push({
- text: title,
- style: "tableofcontent"
- });
- });
-
- return [
- heading,
- toc,
- PDFLayout.addPageBreak()
- ];
- };
-
- var getContent = function() {
- var content = [];
- var assignmentContent = [];
- var assignmentTitles = [];
-
- _.forEach(allAssignments, function(assignment, key) {
- assignmentTitles.push(assignment.title);
- assignmentContent.push(assignment.getContent());
- if (key < allAssignments.length - 1) {
- assignmentContent.push(PDFLayout.addPageBreak());
- }
- });
-
- content.push(title);
- content.push(createPreamble());
- content.push(createTOContent(assignmentTitles));
- content.push(assignmentContent);
- return content;
- };
-
- return {
- getContent: getContent
- };
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('AssignmentPdfExport', [
- 'gettextCatalog',
- 'AssignmentContentProvider',
- 'AssignmentCatalogContentProvider',
- 'PdfMakeDocumentProvider',
- 'BallotContentProvider',
- 'PdfMakeBallotPaperProvider',
- 'PdfCreate',
- 'Messaging',
- function (gettextCatalog, AssignmentContentProvider, AssignmentCatalogContentProvider,
- PdfMakeDocumentProvider, BallotContentProvider, PdfMakeBallotPaperProvider, PdfCreate,
- Messaging) {
- return {
- export: function (assignments, singleAssignment) {
- var filename = singleAssignment ?
- gettextCatalog.getString('Election') + '_' + assignments.title :
- gettextCatalog.getString('Elections');
- filename += '.pdf';
- if (singleAssignment) {
- assignments = [assignments];
- }
-
- // Convert the assignments to content providers
- var assignmentContentProviderArray = _.map(assignments, function (assignment) {
- return AssignmentContentProvider.createInstance(assignment);
- });
-
- var documentProviderPromise;
- if (singleAssignment) {
- documentProviderPromise =
- PdfMakeDocumentProvider.createInstance(assignmentContentProviderArray[0]);
- } else {
- var assignmentCatalogContentProvider =
- AssignmentCatalogContentProvider.createInstance(assignmentContentProviderArray);
- documentProviderPromise =
- PdfMakeDocumentProvider.createInstance(assignmentCatalogContentProvider);
- }
- documentProviderPromise.then(function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- },
- createBallotPdf: function (assignment, pollId) {
- var thePoll;
- var pollNumber;
- _.forEach(assignment.polls, function(poll, pollIndex) {
- if (poll.id == pollId) {
- thePoll = poll;
- pollNumber = pollIndex+1;
- }
- });
- var filename = gettextCatalog.getString('Ballot') + '_' + pollNumber + '_' + assignment.title + '.pdf';
- BallotContentProvider.createInstance(assignment, thePoll, pollNumber).then(function (ballotContentProvider) {
- var documentProvider = PdfMakeBallotPaperProvider.createInstance(ballotContentProvider);
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/assignments/static/js/assignments/projector.js b/openslides/assignments/static/js/assignments/projector.js
deleted file mode 100644
index ac27a8c21..000000000
--- a/openslides/assignments/static/js/assignments/projector.js
+++ /dev/null
@@ -1,46 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.assignments.projector', ['OpenSlidesApp.assignments'])
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('assignments/assignment', {
- template: 'static/templates/assignments/slide_assignment.html',
- });
- }
-])
-
-.controller('SlideAssignmentCtrl', [
- '$scope',
- 'Assignment',
- 'AssignmentPoll',
- 'AssignmentPhases',
- 'AssignmentPollDecimalPlaces',
- 'User',
- function($scope, Assignment, AssignmentPoll, AssignmentPhases, AssignmentPollDecimalPlaces, User) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- $scope.showResult = $scope.element.poll;
-
- if ($scope.showResult) {
- var poll = AssignmentPoll.get($scope.showResult);
- $scope.votesPrecision = 0;
- if (poll) {
- AssignmentPollDecimalPlaces.getPlaces(poll, true).then(function (decimalPlaces) {
- $scope.votesPrecision = decimalPlaces;
- });
- }
- }
-
- Assignment.bindOne(id, $scope, 'assignment');
- $scope.phases = AssignmentPhases;
- User.bindAll({}, $scope, 'users');
- }
-]);
-
-}());
diff --git a/openslides/assignments/static/js/assignments/site.js b/openslides/assignments/static/js/assignments/site.js
deleted file mode 100644
index 155a4725d..000000000
--- a/openslides/assignments/static/js/assignments/site.js
+++ /dev/null
@@ -1,941 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.assignments.site', [
- 'OpenSlidesApp.assignments',
- 'OpenSlidesApp.core.pdf',
- 'OpenSlidesApp.assignments.pdf',
- 'OpenSlidesApp.poll.majority'
-])
-
-.config([
- 'mainMenuProvider',
- 'gettext',
- function (mainMenuProvider, gettext) {
- mainMenuProvider.register({
- 'ui_sref': 'assignments.assignment.list',
- 'img_class': 'pie-chart',
- 'title': gettext('Elections'),
- 'weight': 400,
- 'perm': 'assignments.can_see'
- });
- }
-])
-
-.config([
- 'SearchProvider',
- 'gettext',
- function (SearchProvider, gettext) {
- SearchProvider.register({
- 'verboseName': gettext('Elections'),
- 'collectionName': 'assignments/assignment',
- 'urlDetailState': 'assignments.assignment.detail',
- 'weight': 400,
- });
- }
-])
-
-.config([
- '$stateProvider',
- 'gettext',
- function($stateProvider, gettext) {
- $stateProvider
- .state('assignments', {
- url: '/assignments',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Elections'),
- basePerm: 'assignments.can_see',
- },
- })
- .state('assignments.assignment', {
- abstract: true,
- template: " ",
- })
- .state('assignments.assignment.list', {})
- .state('assignments.assignment.detail', {
- controller: 'AssignmentDetailCtrl',
- resolve: {
- assignmentId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- // redirects to assignment detail and opens assignment edit form dialog, uses edit url,
- // used by ui-sref links from agenda only
- // (from assignment controller use AssignmentForm factory instead to open dialog in front
- // of current view without redirect)
- .state('assignments.assignment.detail.update', {
- onEnter: ['$stateParams', '$state', 'ngDialog',
- function($stateParams, $state, ngDialog) {
- ngDialog.open({
- template: 'static/templates/assignments/assignment-form.html',
- controller: 'AssignmentUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- assignmentId: function() {
- return $stateParams.id;
- },
- },
- preCloseCallback: function() {
- $state.go('assignments.assignment.detail', {assignment: $stateParams.id});
- return true;
- }
- });
- }
- ]
- });
- }
-])
-
-// Service for generic assignment form (create and update)
-.factory('AssignmentForm', [
- 'gettextCatalog',
- 'operator',
- 'Editor',
- 'Mediafile',
- 'Tag',
- 'Assignment',
- 'Agenda',
- 'AgendaTree',
- 'ShowAsAgendaItemField',
- function (gettextCatalog, operator, Editor, Mediafile, Tag, Assignment, Agenda, AgendaTree, ShowAsAgendaItemField) {
- return {
- // ngDialog for assignment form
- getDialog: function (assignment) {
- return {
- template: 'static/templates/assignments/assignment-form.html',
- controller: (assignment) ? 'AssignmentUpdateCtrl' : 'AssignmentCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- assignmentId: function () {return assignment ? assignment.id : void 0;}
- },
- };
- },
- // angular-formly fields for assignment form
- getFormFields: function (isCreateForm) {
- var images = Mediafile.getAllImages();
- var formFields = [
- {
- key: 'title',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Title'),
- required: true
- }
- },
- {
- key: 'description',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('Description')
- },
- data: {
- ckeditorOptions: Editor.getOptions(images)
- }
- },
- {
- key: 'open_posts',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Number of persons to be elected'),
- type: 'number',
- min: 1,
- required: true
- }
- },
- {
- key: 'poll_description_default',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Default comment on the ballot paper')
- }
- }];
-
- // show as agenda item + parent item
- if (isCreateForm) {
- formFields.push(ShowAsAgendaItemField('assignments.can_manage'));
- formFields.push({
- key: 'agenda_parent_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Parent item'),
- options: AgendaTree.getFlatTree(Agenda.getAll()),
- ngOptions: 'item.id as item.getListViewTitle() for item in to.options | notself : model.agenda_item_id',
- placeholder: gettextCatalog.getString('Select a parent item ...')
- },
- hide: !operator.hasPerms('agenda.can_manage')
- });
- }
- // more (with tags field)
- if (Tag.getAll().length > 0) {
- formFields.push(
- {
- key: 'more',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Show extended fields')
- },
- hide: !operator.hasPerms('assignments.can_manage')
- },
- {
- template: ' ',
- hideExpression: '!model.more'
- },
- {
- key: 'tags_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Tags'),
- options: Tag.getAll(),
- ngOptions: 'option.id as option.name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a tag ...')
- },
- hideExpression: '!model.more'
- }
- );
- }
-
- return formFields;
- }
- };
- }
-])
-
-// Cache for AssignmentPollDetailCtrl so that users choices are keeped during user actions (e. g. save poll form).
-.value('AssignmentPollDetailCtrlCache', {})
-
-// Child controller of AssignmentDetailCtrl for each single poll.
-.controller('AssignmentPollDetailCtrl', [
- '$scope',
- 'MajorityMethodChoices',
- 'Config',
- 'AssignmentPollDetailCtrlCache',
- 'AssignmentPoll',
- 'AssignmentPollDecimalPlaces',
- function ($scope, MajorityMethodChoices, Config, AssignmentPollDetailCtrlCache,
- AssignmentPoll, AssignmentPollDecimalPlaces) {
- // Define choices.
- $scope.methodChoices = MajorityMethodChoices;
- // TODO: Get $scope.baseChoices from config_variables.py without copying them.
-
- $scope.votesPrecision = AssignmentPollDecimalPlaces.getPlaces($scope.poll);
-
- // Setup empty cache with default values.
- if (typeof AssignmentPollDetailCtrlCache[$scope.poll.id] === 'undefined') {
- AssignmentPollDetailCtrlCache[$scope.poll.id] = {
- method: $scope.config('assignments_poll_default_majority_method'),
- };
- }
-
- // Fetch users choices from cache.
- $scope.method = AssignmentPollDetailCtrlCache[$scope.poll.id].method;
-
- $scope.recalculateMajorities = function (method) {
- $scope.method = method;
- _.forEach($scope.poll.options, function (option) {
- option.majorityReached = option.isReached(method);
- });
- };
- $scope.recalculateMajorities($scope.method);
-
- $scope.saveDescriptionChange = function (poll) {
- AssignmentPoll.save(poll);
- };
-
- // Save current values to cache on destroy of this controller.
- $scope.$on('$destroy', function() {
- AssignmentPollDetailCtrlCache[$scope.poll.id] = {
- method: $scope.method,
- };
- });
- }
-])
-
-.controller('AssignmentListCtrl', [
- '$scope',
- 'ngDialog',
- 'AssignmentForm',
- 'Assignment',
- 'Tag',
- 'Agenda',
- 'Projector',
- 'ProjectionDefault',
- 'gettextCatalog',
- 'User',
- 'osTableFilter',
- 'osTableSort',
- 'osTablePagination',
- 'gettext',
- 'AssignmentPhases',
- 'AssignmentPdfExport',
- function($scope, ngDialog, AssignmentForm, Assignment, Tag, Agenda, Projector,
- ProjectionDefault, gettextCatalog, User, osTableFilter, osTableSort, osTablePagination,
- gettext, AssignmentPhases, AssignmentPdfExport) {
- $scope.$watch(function () {
- return Assignment.lastModified();
- }, function () {
- $scope.assignments = _.orderBy(Assignment.getAll(), ['title']);
- });
- Tag.bindAll({}, $scope, 'tags');
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'assignments'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.phases = AssignmentPhases;
- $scope.alert = {};
-
- // Filtering
- $scope.filter = osTableFilter.createInstance('AssignmentTableFilter');
-
- if (!$scope.filter.existsStorageEntry()) {
- $scope.filter.multiselectFilters = {
- tag: [],
- phase: [],
- };
- }
- $scope.filter.propertyList = ['title', 'description'];
- $scope.filter.propertyFunctionList = [
- function (assignment) {
- return gettextCatalog.getString($scope.phases[assignment.phase].display_name);
- },
- ];
- $scope.filter.propertyDict = {
- 'assignment_related_users': function (candidate) {
- return candidate.user.get_short_name();
- },
- 'tags': function (tag) {
- return tag.name;
- },
- };
- $scope.getItemId = {
- tag: function (assignment) {return assignment.tags_id;},
- phase: function (assignment) {return assignment.phase;},
- };
-
- // Sorting
- $scope.sort = osTableSort.createInstance('AssignmentTableSort');
- if (!$scope.sort.column) {
- $scope.sort.column = 'title';
- }
- $scope.sortOptions = [
- {name: 'agenda_item.getItemNumberWithAncestors()',
- display_name: gettext('Item')},
- {name: 'title',
- display_name: gettext('Title')},
- {name: 'phase',
- display_name: gettext('Phase')},
- {name: 'assignment_related_users.length',
- display_name: gettext('Number of candidates')},
- ];
- $scope.hasTag = function (assignment, tag) {
- return _.indexOf(assignment.tags_id, tag.id) > -1;
- };
- $scope.toggleTag = function (assignment, tag) {
- if ($scope.hasTag(assignment, tag)) {
- assignment.tags_id = _.filter(assignment.tags_id, function (tag_id){
- return tag_id != tag.id;
- });
- } else {
- assignment.tags_id.push(tag.id);
- }
- Assignment.save(assignment);
- };
-
- // Pagination
- $scope.pagination = osTablePagination.createInstance('AssignmentTablePagination');
-
- // update phase
- $scope.updatePhase = function (assignment, phase_id) {
- assignment.phase = phase_id;
- Assignment.save(assignment);
- };
- // open new/edit dialog
- $scope.openDialog = function (assignment) {
- ngDialog.open(AssignmentForm.getDialog(assignment));
- };
- // *** select mode functions ***
- $scope.isSelectMode = false;
- // check all checkboxes
- $scope.checkAll = function () {
- $scope.selectedAll = !$scope.selectedAll;
- angular.forEach($scope.assignments, function (assignment) {
- assignment.selected = $scope.selectedAll;
- });
- };
- // uncheck all checkboxes if isSelectMode is closed
- $scope.uncheckAll = function () {
- if (!$scope.isSelectMode) {
- $scope.selectedAll = false;
- angular.forEach($scope.assignments, function (assignment) {
- assignment.selected = false;
- });
- }
- };
- // delete all selected assignments
- $scope.deleteMultiple = function () {
- angular.forEach($scope.assignments, function (assignment) {
- if (assignment.selected)
- Assignment.destroy(assignment.id);
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // delete single assignment
- $scope.delete = function (assignment) {
- Assignment.destroy(assignment.id);
- };
- // create the PDF List
- $scope.pdfExport = function () {
- AssignmentPdfExport.export($scope.assignmentsFiltered);
- };
- }
-])
-
-.controller('AssignmentDetailCtrl', [
- '$scope',
- '$http',
- '$filter',
- '$timeout',
- 'filterFilter',
- 'gettext',
- 'ngDialog',
- 'AssignmentForm',
- 'operator',
- 'Assignment',
- 'User',
- 'assignmentId',
- 'Projector',
- 'ProjectionDefault',
- 'gettextCatalog',
- 'AssignmentPhases',
- 'AssignmentPdfExport',
- 'WebpageTitle',
- 'ErrorMessage',
- function($scope, $http, $filter, $timeout, filterFilter, gettext, ngDialog, AssignmentForm, operator,
- Assignment, User, assignmentId, Projector, ProjectionDefault, gettextCatalog, AssignmentPhases,
- AssignmentPdfExport, WebpageTitle, ErrorMessage) {
- User.bindAll({}, $scope, 'users');
- var assignment = Assignment.get(assignmentId);
- Assignment.loadRelations(assignment, 'agenda_item');
- // This flag is for setting 'activeTab' to recently added (last) ballot tab.
- // Set this flag, if ballots are added/removed. When the next autoupdate comes
- // in, the tabset will be updated.
- var updateBallotTabsFlag = true;
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'assignments'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.$watch(function () {
- return Assignment.lastModified(assignmentId);
- }, function () {
- // setup sorting of candidates
- $scope.relatedUsersSorted = $filter('orderBy')(assignment.assignment_related_users, 'weight');
- $scope.assignment = Assignment.get(assignment.id);
- if (updateBallotTabsFlag) {
- $scope.activeTab = $scope.assignment.polls.length - 1;
- updateBallotTabsFlag = false;
- }
- WebpageTitle.updateTitle(gettextCatalog.getString('Election') + ' ' + $scope.assignment.title);
- });
- $scope.candidateSelectBox = {};
- $scope.phases = AssignmentPhases;
- $scope.alert = {};
-
- // open edit dialog
- $scope.openDialog = function () {
- ngDialog.open(AssignmentForm.getDialog($scope.assignment));
- };
- // add (nominate) candidate
- $scope.addCandidate = function (userId) {
- $http.post('/rest/assignments/assignment/' + assignmentId + '/candidature_other/', {'user': userId})
- .then(function (success){
- $scope.alert.show = false;
- $scope.candidateSelectBox = {};
- }, function (error){
- $scope.alert = ErrorMessage.forAlert(error);
- $scope.candidateSelectBox = {};
- });
- };
- // remove candidate
- $scope.removeCandidate = function (userId) {
- $http.delete('/rest/assignments/assignment/' + assignmentId + '/candidature_other/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({user: userId})})
- .then(function (success) {},
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- // add me (nominate self as candidate)
- $scope.addMe = function () {
- $http.post('/rest/assignments/assignment/' + assignmentId + '/candidature_self/', {}).then(
- function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- // remove me (withdraw own candidature)
- $scope.removeMe = function () {
- $http.delete('/rest/assignments/assignment/' + assignmentId + '/candidature_self/').then(
- function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- // check if current user is already a candidate (elected==false)
- $scope.isCandidate = function () {
- var check = $scope.assignment.assignment_related_users.map(function(candidate) {
- if (!candidate.elected) {
- return candidate.user_id;
- }
- }).indexOf(operator.user.id);
- if (check > -1) {
- return true;
- } else {
- return false;
- }
- };
- // Sort all candidates
- $scope.treeOptions = {
- dropped: function () {
- var sortedCandidates = [];
- _.forEach($scope.relatedUsersSorted, function (user) {
- sortedCandidates.push(user.id);
- });
- $http.post('/rest/assignments/assignment/' + assignmentId + '/sort_related_users/',
- {related_users: sortedCandidates}
- );
- }
- };
- // update phase
- $scope.updatePhase = function (phase_id) {
- $scope.assignment.phase = phase_id;
- Assignment.save($scope.assignment);
- };
- // create new ballot
- $scope.createBallot = function () {
- $http.post('/rest/assignments/assignment/' + assignmentId + '/create_poll/').then(
- function (success) {
- $scope.alert.show = false;
- if (assignment.phase === 0) {
- $scope.updatePhase(1);
- }
- updateBallotTabsFlag = true;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- // delete ballot
- $scope.deleteBallot = function (poll) {
- poll.DSDestroy().then(
- function (success) {
- $scope.activeTab = $scope.activeTab - 1;
- updateBallotTabsFlag = true;
- }
- );
- };
- // edit poll dialog
- $scope.editPollDialog = function (poll, ballot) {
- ngDialog.open({
- template: 'static/templates/assignments/assignmentpoll-form.html',
- controller: 'AssignmentPollUpdateCtrl',
- className: 'ngdialog-theme-default',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- assignmentpollId: function () {return poll.id;},
- ballot: function () {return ballot;},
- }
- });
- };
- // publish ballot
- $scope.togglePublishBallot = function (poll) {
- poll.DSUpdate({
- assignment_id: assignmentId,
- published: !poll.published,
- })
- .then(function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- // mark candidate as (not) elected
- $scope.markElected = function (user, reverse) {
- if (reverse) {
- $http.delete(
- '/rest/assignments/assignment/' + assignmentId + '/mark_elected/', {
- headers: {
- 'Content-Type': 'application/json'
- },
- data: JSON.stringify({user: user})
- });
- } else {
- $http.post('/rest/assignments/assignment/' + assignmentId + '/mark_elected/', {'user': user});
- }
-
- };
-
- // Creates the document as pdf
- $scope.pdfExport = function() {
- AssignmentPdfExport.export($scope.assignment, true);
- };
- // Creates the ballotpaper as pdf
- $scope.ballotpaperExport = function(pollId) {
- AssignmentPdfExport.createBallotPdf($scope.assignment, pollId);
- };
-
- // Just mark some vote value strings for translation.
- gettext('Yes');
- gettext('No');
- gettext('Abstain');
- }
-])
-
-.controller('AssignmentCreateCtrl', [
- '$scope',
- '$state',
- 'Assignment',
- 'AssignmentForm',
- 'Agenda',
- 'Config',
- 'ErrorMessage',
- function($scope, $state, Assignment, AssignmentForm, Agenda, Config, ErrorMessage) {
- $scope.model = {
- agenda_type: parseInt(Config.get('agenda_new_items_default_visibility').value),
- };
- // set default value for open posts form field
- $scope.model.open_posts = 1;
- // get all form fields
- $scope.formFields = AssignmentForm.getFormFields(true);
- // save assignment
- $scope.save = function(assignment, gotoDetailView) {
- Assignment.create(assignment).then(
- function (success) {
- if (gotoDetailView) {
- $state.go('assignments.assignment.detail', {id: success.id});
- }
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('AssignmentUpdateCtrl', [
- '$scope',
- '$state',
- 'Assignment',
- 'AssignmentForm',
- 'Agenda',
- 'assignmentId',
- 'ErrorMessage',
- function($scope, $state, Assignment, AssignmentForm, Agenda, assignmentId, ErrorMessage) {
- var assignment = Assignment.get(assignmentId);
- $scope.alert = {};
- // set initial values for form model by create deep copy of assignment object
- // so list/detail view is not updated while editing
- $scope.model = angular.copy(assignment);
- // get all form fields
- $scope.formFields = AssignmentForm.getFormFields();
-
- // save assignment
- $scope.save = function (assignment, gotoDetailView) {
- // inject the changed assignment (copy) object back into DS store
- Assignment.inject(assignment);
- // save changed assignment object on server
- Assignment.save(assignment).then(
- function(success) {
- if (gotoDetailView) {
- $state.go('assignments.assignment.detail', {id: success.id});
- }
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original assignment object from server
- Assignment.refresh(assignment);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('AssignmentPollUpdateCtrl', [
- '$scope',
- '$filter',
- 'gettextCatalog',
- 'AssignmentPoll',
- 'assignmentpollId',
- 'AssignmentPollDecimalPlaces',
- 'ballot',
- 'ErrorMessage',
- function($scope, $filter, gettextCatalog, AssignmentPoll, assignmentpollId,
- AssignmentPollDecimalPlaces, ballot, ErrorMessage) {
- // set initial values for form model by create deep copy of assignmentpoll object
- // so detail view is not updated while editing poll
- var assignmentpoll = angular.copy(AssignmentPoll.get(assignmentpollId));
- $scope.model = assignmentpoll;
- $scope.ballot = ballot;
- $scope.formFields = [];
- $scope.alert = {};
-
- // For number inputs
- var step = Math.pow(10, -AssignmentPollDecimalPlaces.getPlaces(assignmentpoll));
-
- // add dynamic form fields
- var options = $filter('orderBy')(assignmentpoll.options, 'weight');
- _.forEach(options, function(option) {
- var defaultValue;
- if (assignmentpoll.pollmethod == 'yna' || assignmentpoll.pollmethod == 'yn') {
- defaultValue = {};
- _.forEach(option.votes, function (vote) {
- defaultValue[vote.value.toLowerCase()] = vote.weight;
- });
-
- var columnClass = (assignmentpoll.pollmethod === 'yna') ? 'col-xs-4' : 'col-xs-6';
- var columns = [
- {
- key: 'yes_' + option.candidate_id,
- type: 'input',
- className: columnClass + ' no-padding-left',
- templateOptions: {
- label: gettextCatalog.getString('Yes'),
- type: 'number',
- min: -2,
- step: step,
- required: true
- },
- defaultValue: defaultValue.yes
- },
- {
- key: 'no_' + option.candidate_id,
- type: 'input',
- className: columnClass + ' no-padding-left' +
- (assignmentpoll.pollmethod === 'yn' ? ' no-padding-right' : ''),
- templateOptions: {
- label: gettextCatalog.getString('No'),
- type: 'number',
- min: -2,
- step: step,
- required: true
- },
- defaultValue: defaultValue.no
- }
- ];
- if (assignmentpoll.pollmethod == 'yna'){
- columns.push({
- key:'abstain_' + option.candidate_id,
- type: 'input',
- className: columnClass + ' no-padding-left no-padding-right',
- templateOptions: {
- label: gettextCatalog.getString('Abstain'),
- type: 'number',
- min: -2,
- step: step,
- required: true
- },
- defaultValue: defaultValue.abstain
- });
- }
- $scope.formFields.push({
- noFormControl: true,
- template: '' + option.candidate.get_full_name() + ' '
- },
- {
- className: 'row',
- fieldGroup: columns,
- });
- } else { // votes method
- if (option.votes.length) {
- defaultValue = option.votes[0].weight;
- }
- $scope.formFields.push({
- key: 'vote_' + option.candidate_id,
- type: 'input',
- templateOptions: {
- label: option.candidate.get_full_name(),
- type: 'number',
- min: -2,
- step: step,
- required: true,
- },
- defaultValue: defaultValue
- });
- }
- });
- if (assignmentpoll.pollmethod == 'votes'){
- $scope.formFields.push(
- {
- key: 'votesabstain',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Abstain'),
- type: 'number',
- step: step,
- min: -2,
- }
- },
- {
- key: 'votesno',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('No'),
- type: 'number',
- step: step,
- min: -2,
- }
- }
- );
- }
- // add general form fields
- $scope.formFields.push(
- {
- template: ' ',
- },
- {
- key: 'votesvalid',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Valid ballots'),
- type: 'number',
- step: step,
- min: -2,
- }
- },
- {
- key: 'votesinvalid',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Invalid ballots'),
- type: 'number',
- step: step,
- min: -2,
- }
- },
- {
- key: 'votescast',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Casted ballots'),
- type: 'number',
- step: step,
- min: -2,
- }
- }
- );
-
- // save assignmentpoll
- $scope.save = function (poll) {
- var votes = [];
- if (assignmentpoll.pollmethod == 'yna') {
- assignmentpoll.options.forEach(function(option) {
- votes.push({
- 'Yes': poll['yes_' + option.candidate_id],
- 'No': poll['no_' + option.candidate_id],
- 'Abstain': poll['abstain_' + option.candidate_id]
- });
- });
- } else if (assignmentpoll.pollmethod == 'yn') {
- assignmentpoll.options.forEach(function(option) {
- votes.push({
- 'Yes': poll['yes_' + option.candidate_id],
- 'No': poll['no_' + option.candidate_id]
- });
- });
- } else {
- assignmentpoll.options.forEach(function(option) {
- votes.push({
- 'Votes': poll['vote_' + option.candidate_id],
- });
- });
- }
- // save change poll object on server
- poll.DSUpdate({
- assignment_id: poll.assignment_id,
- votes: votes,
- votesabstain: poll.votesabstain,
- votesno: poll.votesno,
- votesvalid: poll.votesvalid,
- votesinvalid: poll.votesinvalid,
- votescast: poll.votescast,
- })
- .then(function(success) {
- $scope.alert.show = false;
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-//mark all assignment config strings for translation with Javascript
-.config([
- 'gettext',
- function (gettext) {
- gettext('Election method');
- gettext('Automatic assign of method');
- gettext('Always one option per candidate');
- gettext('Always Yes-No-Abstain per candidate');
- gettext('Always Yes/No per candidate');
- gettext('Elections');
- gettext('Ballot and ballot papers');
- gettext('The 100-%-base of an election result consists of');
- gettext('For Yes/No/Abstain per candidate and Yes/No per candidate the 100-%-base ' +
- 'depends on the election method: If there is only one option per candidate, ' +
- 'the sum of all votes of all candidates is 100 %. Otherwise for each ' +
- 'candidate the sum of all votes is 100 %.');
- gettext('Yes/No/Abstain per candidate');
- gettext('Yes/No per candidate');
- gettext('All valid ballots');
- gettext('All casted ballots');
- gettext('Disabled (no percents)');
- gettext('Number of ballot papers (selection)');
- gettext('Number of all delegates');
- gettext('Number of all participants');
- gettext('Use the following custom number');
- gettext('Custom number of ballot papers');
- gettext('Required majority');
- gettext('Default method to check whether a candidate has reached the required majority.');
- gettext('Simple majority');
- gettext('Two-thirds majority');
- gettext('Three-quarters majority');
- gettext('Disabled');
- gettext('Put all candidates on the list of speakers');
- gettext('Title for PDF document (all elections)');
- gettext('Preamble text for PDF document (all elections)');
- //other translations
- gettext('Searching for candidates');
- gettext('Voting');
- gettext('Finished');
- }
-]);
-
-}());
diff --git a/openslides/assignments/static/templates/assignments/assignment-detail.html b/openslides/assignments/static/templates/assignments/assignment-detail.html
deleted file mode 100644
index d585d345e..000000000
--- a/openslides/assignments/static/templates/assignments/assignment-detail.html
+++ /dev/null
@@ -1,299 +0,0 @@
-
-
-
-
-
-
-
-
-
-
Election result
-
-
-
-
- New ballot
-
-
-
-
-
-
-
-
-
- Set hint for ballot paper ...
- {{ poll.description }}
-
-
-
-
-
- Delete
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Required majority :
-
-
-
-
-
-
- Candidates
- Votes
- Quorum
-
-
-
-
-
-
-
-
-
-
- {{ option.candidate.get_full_name() }}
-
-
-
-
-
-
{{ vote.label }}:
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
-
-
-
-
-
-
-
- Quorum ({{ (option.getVoteYes() - option.majorityReached) | number:votesPrecision }}) reached.
-
-
- Quorum ({{ (option.getVoteYes() - option.majorityReached) | number:votesPrecision }}) not reached.
-
-
-
-
-
- Abstain
-
- {{ poll.getVote('votesabstain').value | number:votesPrecision }}
- {{ poll.getVote('votesabstain').percentStr }}
-
-
- No
-
- {{ poll.getVote('votesno').value | number:votesPrecision }}
- {{ poll.getVote('votesno').percentStr }}
-
-
- Valid ballots
-
- {{ poll.getVote('votesvalid').value | number:votesPrecision }}
- {{ poll.getVote('votesvalid').percentStr }}
-
-
- Invalid ballots
-
- {{ poll.getVote('votesinvalid').value | number:votesPrecision }}
- {{ poll.getVote('votesinvalid').percentStr }}
-
-
- Casted ballots
-
- {{ poll.getVote('votescast').value | number:votesPrecision }}
- {{ poll.getVote('votescast').percentStr }}
-
-
-
Election method
-
One vote per candidate
-
Yes/No/Abstain per candidate
-
Yes/No per candidate
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/assignments/static/templates/assignments/assignment-form.html b/openslides/assignments/static/templates/assignments/assignment-form.html
deleted file mode 100644
index 1e3ab0928..000000000
--- a/openslides/assignments/static/templates/assignments/assignment-form.html
+++ /dev/null
@@ -1,22 +0,0 @@
-Edit election
-New election
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/assignments/static/templates/assignments/assignment-list.html b/openslides/assignments/static/templates/assignments/assignment-list.html
deleted file mode 100644
index b23668a8e..000000000
--- a/openslides/assignments/static/templates/assignments/assignment-list.html
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
- --- Select phase ---
- {{ phase.display_name | translate }}
-
-
-
-
-
-
-
- {{ assignmentsFiltered.length }} /
- {{ assignments.length }} {{ "elections" | translate }},
- {{(assignments|filter:{selected:true}).length}} {{ "selected" | translate }}
-
-
-
-
- Page {{ pagination.currentPage }} /
- {{ pagination.getPageCount(assignmentsFiltered) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ tag.name }},
-
-
-
-
-
-
-
-
-
-
-
- {{ tag.name }},
-
-
-
-
-
-
-
-
- {{ assignment.assignment_related_users.length }}
-
-
-
-
{{ assignment.agenda_item.getItemNumberWithAncestors() }}
-
-
-
-
-
-
-
-
diff --git a/openslides/assignments/static/templates/assignments/assignmentpoll-form.html b/openslides/assignments/static/templates/assignments/assignmentpoll-form.html
deleted file mode 100644
index dcf905596..000000000
--- a/openslides/assignments/static/templates/assignments/assignmentpoll-form.html
+++ /dev/null
@@ -1,22 +0,0 @@
-Ballot {{ ballot }}
-
-
- {{ alert.msg }}
-
-
-
- Special values :
- -1 = majority
- -2 = undocumented
-
-
diff --git a/openslides/assignments/static/templates/assignments/slide_assignment.html b/openslides/assignments/static/templates/assignments/slide_assignment.html
deleted file mode 100644
index fb62f65cb..000000000
--- a/openslides/assignments/static/templates/assignments/slide_assignment.html
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
-
-
{{ assignment.agenda_item.getTitle() || assignment.title }}
-
- Election
-
-
-
-
-
-
-
-
-
-
Candidates
-
-
- {{ related_user.user.get_full_name() }}
-
-
-
-
-
-
-
- Waiting for results ...
-
-
-
-
-
- Candidates
- Votes
-
-
-
-
-
-
-
- {{ option.candidate.get_full_name() }}
-
-
-
-
-
-
- {{ votes[0].label | translate }}: {{ votes[0].value | number:votesPrecision }} {{ votes[0].percentStr }}
- {{ votes[1].label | translate }}: {{ votes[1].value | number:votesPrecision }} {{ votes[1].percentStr }}
- {{ votes[2].label | translate }}: {{ votes[2].value | number:votesPrecision }} {{ votes[2].percentStr }}
-
- {{ votes[0].label | translate }}: {{ votes[0].value | number:votesPrecision }} {{ votes[0].percentStr }}
- {{ votes[1].label | translate }}: {{ votes[1].value | number:votesPrecision }} {{ votes[1].percentStr }}
-
-
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
-
-
-
-
-
-
-
-
- Abstain
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
- No
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
- Valid ballots
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
-
- Invalid ballots
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
-
- Casted ballots
-
- {{ vote.value | number:votesPrecision }} {{ vote.percentStr }}
-
-
-
-
-
diff --git a/openslides/core/management/commands/collectstatic.py b/openslides/core/management/commands/collectstatic.py
deleted file mode 100644
index 0cc2785a2..000000000
--- a/openslides/core/management/commands/collectstatic.py
+++ /dev/null
@@ -1,66 +0,0 @@
-import os
-from typing import Any, Dict
-
-from django.conf import settings
-from django.contrib.staticfiles.management.commands.collectstatic import (
- Command as CollectStatic,
-)
-from django.contrib.staticfiles.utils import matches_patterns
-from django.core.management.base import CommandError
-from django.db.utils import OperationalError
-
-from ...views import WebclientJavaScriptView
-
-
-class Command(CollectStatic):
- """
- Custom collectstatic command.
- """
- realms = ['site', 'projector']
- js_filename = 'webclient-{}.js'
-
- def handle(self, **options: Any) -> str:
- if options['link']:
- raise CommandError("Option 'link' is not supported.")
- try:
- self.view = WebclientJavaScriptView()
- except OperationalError:
- raise CommandError('You have to run OpenSlides first to create a ' +
- 'database before collecting staticfiles.')
- return super().handle(**options)
-
- def collect(self) -> Dict[str, Any]:
- result = super().collect()
-
- try:
- destination_dir = os.path.join(settings.STATIC_ROOT, 'js')
- except IndexError:
- # If the user does not want do have staticfiles, he should not get
- # the webclient files either.
- pass
- else:
- if self.dry_run:
- self.log('Pretending to write WebclientJavaScriptView for all realms.', level=1)
- else:
- if not os.path.exists(destination_dir):
- os.makedirs(destination_dir)
-
- for realm in self.realms:
- filename = self.js_filename.format(realm)
- # Matches only the basename.
- if matches_patterns(filename, self.ignore_patterns):
- continue
- path = os.path.join(destination_dir, filename)
- if matches_patterns(path, self.ignore_patterns):
- continue
-
- content = self.view.get(realm=realm).content
- with open(path, 'wb+') as f:
- f.write(content)
- message = "Written WebclientJavaScriptView for realm {} to '{}'".format(
- realm,
- path)
- self.log(message, level=1)
- result['modified'].append(path)
-
- return result
diff --git a/openslides/core/static/css/_fonts.scss b/openslides/core/static/css/_fonts.scss
deleted file mode 100644
index 12ab0c028..000000000
--- a/openslides/core/static/css/_fonts.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Font definitions for OpenSlides site
- */
-
-@font-face {
- font-family: $font;
- src: $font-src;
- font-weight: 400;
- font-style: normal;
-}
-@font-face {
- font-family: $font-medium;
- src: $font-medium-src;
- font-weight: 400;
- font-style: normal;
-}
-@font-face {
- font-family: $font-condensed;
- src: $font-condensed-src;
- font-weight: 100;
- font-style: normal;
-}
-@font-face {
- font-family: $font-condensed-light;
- src: $font-condensed-light-src;
- font-weight: 100;
- font-style: normal;
-}
diff --git a/openslides/core/static/css/_helper.scss b/openslides/core/static/css/_helper.scss
deleted file mode 100644
index bfdb7328c..000000000
--- a/openslides/core/static/css/_helper.scss
+++ /dev/null
@@ -1,255 +0,0 @@
-/** General helper classes **/
-.disabled {
- color: #555;
- cursor: not-allowed !important;
-}
-
-.bold {
- font-weight: bold;
-}
-
-.dropdown-menu {
- margin-left: 0px !important;
- max-height: 300px;
- overflow-y: auto;
-}
-
-.slimDropDown {
- padding-left: 4px !important;
- padding-right: 4px !important;
-}
-
-.btn-primary {
- background-color: #317796;
-}
-
-.btn-slim {
- padding-left: 6px;
- padding-right: 6px;
-}
-
-.spacer, .spacer-top {
- margin-top: 7px;
-}
-
-.spacer-top-lg {
- margin-top: 25px;
-}
-
-.spacer-bottom {
- margin-bottom: 7px;
-}
-
-.spacer-right {
- margin-right: 5px;
-}
-
-.spacer-left {
- margin-left: 5px;
-}
-
-.spacer-left-lg {
- margin-left: 10px;
-}
-
-.no-padding {
- padding: 0px;
-}
-
-.lead-div {
- margin-bottom: 20px;
-
- .lead {
- margin-bottom: 0;
- }
-}
-
-.italic {
- font-style: italic;
-}
-
-.hoverActions {
- font-size: 85%;
-}
-
-.hiddenDiv {
- visibility: hidden;
-}
-
-.vcenter {
- vertical-align: middle;
-}
-
-.white-space-pre-line {
- white-space: pre-line;
-}
-
-.slimlabel.label {
- padding: 0px 10px;
-}
-
-.indentation, .indentation20 {
- margin-left: 20px !important;
-}
-
-.indentation-lg {
- margin-left: 35px !important;
-}
-
-.halfWidth {
- width: 50%;
-}
-
-.badge-info {
- background-color: #f0ad4e;
-}
-
-.badge-success {
- background-color: #5bb85b;
-}
-
-.smallhr {
- margin-top: 5px;
- margin-bottom: 5px;
- border-color: #cccccc;
-}
-
-.nobr {
- white-space: nowrap;
-}
-
-.rotate-45-deg-right {
- filter: "progid: DXImageTransform.Microsoft.BasicImage(rotation=0.5)";
- -webkit-transform: rotate(45deg);
- -moz-transform: rotate(45deg);
- -ms-transform: rotate(45deg);
- -o-transform: rotate(45deg);
- transform: rotate(45deg);
-}
-
-.optional { /* show optional column */
- display: auto;
-}
-
-.inline {
- display: inline;
-}
-
-.login-logo {
- width: 250px;
-}
-
-.loginForm .input-group-addon i {
- width: 15px;
-}
-
-.modal-header {
- padding: 5px;
-}
-
-.no-padding {
- padding: 0 !important;
-}
-
-.no-padding-left {
- padding-left: 0 !important;
-}
-
-.no-padding-right {
- padding-right: 0 !important;
-}
-
-.scroll-x-container {
- overflow-x: auto;
-}
-
-.btn-group > label > input[type=radio] {
- display: none;
-}
-
-/* tables */
-.topictext table {
- border-spacing: 10px 0;
- border-collapse: separate;
-}
-
-.minimum {
- width: 1px;
-}
-
-.minimumTable {
- width: auto;
-}
-
-.deleteColumn {
- text-align: center;
- background-color: #ff9999 !important;
-}
-
-th.sortable:hover, tr.pointer:hover, .pointer {
- cursor: pointer;
-}
-
-/** background colors for table rows **/
-tr.hiddenrow td {
- background-color: #F5DCDC;
-}
-
-tr.activeline td, li.activeline, .projected {
- background-color: #bed4de !important;
-}
-
-.related-projected {
- background-color: #e1ecfe !important;
-}
-
-tr.selected td {
- background-color: #ff9999;
-}
-
-.help-block {
- font-size: 85%;
- margin-top: 2px;
- margin-left: 2px;
-}
-
-.pagination-arrow {
- font-size: 150%;
- padding: 3px;
- text-decoration: none;
-
- &:hover, &:focus {
- text-decoration: none;
- }
-}
-
-.grey {
- color: gray;
-}
-
-.info {
- color: #222;
- background-color: #bed4de;
- border-color: #46b8da;
-}
-.error {
- color: #a94442;
- background-color: #f2dede;
- border-color: #ebccd1;
-}
-.success {
- color: #3c763d;
- background-color: #dff0d8;
- border-color: #d6e9c6;
-}
-.warning {
- color: #725523;
- background-color: #fcf8e3;
- border-color: #faebcc;
-}
-.close {
- opacity: 0.3 !important;
-}
-.close:hover {
- opacity: 0.6 !important;
-}
diff --git a/openslides/core/static/css/_mediaqueries.scss b/openslides/core/static/css/_mediaqueries.scss
deleted file mode 100644
index 62e1f5906..000000000
--- a/openslides/core/static/css/_mediaqueries.scss
+++ /dev/null
@@ -1,115 +0,0 @@
-/*////////////////////////////////////////
- =MEDIA QUERIES (RESPONSIVE DESIGN)
-////////////////////////////////////////*/
-
-/* display for 900 to 1200px resolutions */
-@media only screen and (max-width: 1200px) {
-
- body { font-size: 12px; }
-
- h1 { font-size: 30px; padding-bottom: 6px; }
-
- h2 { font-size: 22px; padding-bottom: 10px; }
-
- h3 { font-size: 18px; padding-bottom: 10px; }
-
- .col-md-4 {
- float: left;
- width: 50%;
- }
-
- .motion-text.line-numbers-outside .os-line-number:after {
- font-size: 10px;
- top: 9px;
- }
-}
-
-
-/* display for resolutions smaller that 900px */
-@media only screen and (max-width: 900px) {
-
- #nav .navbar li a { padding: 24px 5px; }
-
- #multi-table .info-head {
- width: 200px;
- &.small {
- width: 250px;
- }
- }
-
- /* hide text in multi-table earlier */
- #multi-table .optional { display: none; }
-
- /* show replacement elements, if any */
- #multi-table .optional-show { display: block !important; }
-
- /* hide searchbar input */
- #nav .searchbar input { display: none !important; }
- #nav .searchbar .btn {
- border-top-left-radius: 4px !important;
- border-bottom-left-radius: 4px !important;
- }
-}
-
-
-/* display for resolutions smaller that 760px */
-@media only screen and (max-width: 760px) {
-
- h1 { font-size: 22px; padding-bottom: 4px; }
-
- h2 { font-size: 16px; padding-bottom: 4px; }
-
- h3 { font-size: 14px; padding-bottom: 4px; }
-
- .user i { font-size: 16px; padding: 3px; }
-
- #nav .navbar { box-shadow: none; padding-right: 60px !important; }
- #nav .navbar ul li a { padding: 10px 15px; }
- #nav .searchbar { margin: 15px -53px 0 0 !important; }
-
- #chatbox { width: 100%; top: 40px; }
-
- .badge { font-size: 10px; }
-
- /* show replacement elements, if any */
- .optional-show { display: block !important; }
-
- /* hide marked element / column */
- .optional, .hide-sm { display: none !important; }
-}
-
-/* display for resolutions smaller that 560px */
-@media only screen and (max-width: 560px) {
- #content .containerOS { padding: 0; }
-
- #content .col2 { width: 100%; }
-
- #content .col2.sidebar-max, #content .col2.sidebar-min,
- #content .col1.sidebar-min, #content .col1.sidebar-max {
- width: 100%;
- }
-
- #sidebar {
- display: none !important;
- }
-
- #sidebar-xs {
- display: block !important;
- }
-
- #sidebar-xs .projector_full {
- margin-left: 0 !important;
- width: 100%;
- }
-
- #multi-table .info-head {
- width: 150px;
- &.small {
- width: 100px;
- }
- }
-
- .personalNoteFixed {
- width: 100%;
- }
-}
diff --git a/openslides/core/static/css/_startup-spinner.scss b/openslides/core/static/css/_startup-spinner.scss
deleted file mode 100644
index fe496aecf..000000000
--- a/openslides/core/static/css/_startup-spinner.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-#wrapper {
- float: left;
- width: 100%;
- margin: 0 auto 0 auto;
-}
-
-#startup-overlay {
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- background-color: #fff;
- z-index: 900;
-}
-
-#spinner-container {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- max-height: 340px;
- z-index: 1000;
-
- div {
- width: 100%;
- position: absolute;
- bottom: 0;
- font-size: 56px;
- text-align: center;
- color: #317796;
- }
-}
diff --git a/openslides/core/static/css/_ui-override.scss b/openslides/core/static/css/_ui-override.scss
deleted file mode 100644
index ee90d3f2d..000000000
--- a/openslides/core/static/css/_ui-override.scss
+++ /dev/null
@@ -1,169 +0,0 @@
-/* override booststrap's label class to fix linebreak and add spacing */
-.label {
- display: inline-block;
- padding: .4em .6em;
- margin-right: .2em;
- white-space: normal;
-}
-
-/* Custom OpenSlides slider classes */
-.os-slider {
- margin-top: 40px;
- margin-bottom: 20px;
-
- &.rzslider {
- .rz-bar {
- background: #317796;
- opacity: 0.3;
- height: 2px;
- }
-
- .rz-selection {
- background: #317796;
- }
-
- .rz-pointer {
- width: 14px;
- height: 14px;
- top: -7px;
- bottom: 0;
- background-color: #317796;
- border-radius: 7px;
-
- &:after {
- display: none;
- }
- }
- }
-}
-
-/* ngDialog: override ngdialog-theme-default */
-.ngdialog.ngdialog-theme-default {
- padding-top: 40px;
-
- .ngdialog-content {
- font-family: $font, sans-serif !important;
- }
-
- h2 {
- margin-top: 5px;
- }
-
- label {
- font-family: $font-medium;
- font-family: $font-medium, sans-serif;
- font-weight: normal;
- }
-
- .row:after, .row:before {
- display: table-cell !important;
- }
-}
-
-.ngdialog.ngdialog-theme-default.wide-form .ngdialog-content {
- width: 750px;
- line-height: 1em;
-}
-
-/* Bootbox: override z-index, that bootboxes are higher than ngDialogs */
-.bootbox {
- z-index: 100000;
-}
-
-/* angular-chosen: override default width of select fields in quickmode */
-.chosen-container {
- width: 100% !important;
- font-size: 14px;
-
- ul.chosen-results {
- margin: 0 !important;
-
- li.active-result {
- margin: 6px 5px 0 0 !important;
- }
- }
-
- input {
- margin: 4px 0 !important;
- }
-}
-
-.chosen-container-active .chosen-choices {
- border-color: rgba(82,168,236,.8);
- box-shadow: 0 0 8px rgba(82,168,236,.6);
-}
-
-/* angular-ui-tree style */
-.angular-ui-tree-handle {
- background: none repeat scroll 0 0 #f8faff;
- border: 1px solid #dae2ea;
- color: #7c9eb2;
- padding: 10px;
-
- &:hover {
- background: none repeat scroll 0 0 #f4f6f7;
- border-color: #dce2e8;
- color: #438eb9;
- }
-}
-
-.angular-ui-tree-placeholder {
- background: none repeat scroll 0 0 #f0f9ff;
- border: 2px dashed #bed2db;
- box-sizing: border-box;
-}
-
-/* ngAnimate classes */
-.animate-item.ng-enter {
- -webkit-animation: fade-in 0.5s linear;
- animation: fade-in 0.5s linear;
-}
-
-.animate-item.ng-leave {
- -webkit-animation: fade-out 0.25s linear;
- animation: fade-out 0.25s linear;
-}
-
-/* xeditable */
-.editable-click {
- border: none;
- cursor: pointer;
- color: #555;
-
- &:hover {
- color: #555;
- }
-}
-
-.popover-wrapper {
- .editable-hide {
- display: inline !important;
- }
-
- .small-form {
- input{
- width: 100px;
- height: 30px;
- }
-
- button{
- padding: 5px 10px;
- font-size: 12px;
- line-height: 1.5;
- }
- }
-}
-
-@keyframes fade-out {
- 0% { opacity: 1; background: none; }
- 100% { opacity: 0; background: none; }
-}
-@keyframes fade-in {
- 0% { opacity: 0; background: none; }
- 100% { opacity: 1; background: none; }
-}
-
-/* Angular formly */
-.checkbox label {
- padding-left: 0;
-}
diff --git a/openslides/core/static/css/_variables.scss b/openslides/core/static/css/_variables.scss
deleted file mode 100644
index 8894c57e4..000000000
--- a/openslides/core/static/css/_variables.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-/** Fonts **/
-/* Note: The font naming has to be consistent to the projector.html */
-$font: 'OSFont';
-$font-src: url('../fonts/Roboto-Regular.woff') format('woff');
-$font-medium: 'OSFont Medium';
-$font-medium-src: url('../fonts/Roboto-Medium.woff') format('woff');
-$font-condensed: 'OSFont Condensed';
-$font-condensed-src: url('../fonts/Roboto-Condensed-Regular.woff') format('woff');
-$font-condensed-light: 'OSFont Condensed Light';
-$font-condensed-light-src: url('../fonts/Roboto-Condensed-Light.woff') format('woff');
diff --git a/openslides/core/static/css/core/_chatbox.scss b/openslides/core/static/css/core/_chatbox.scss
deleted file mode 100644
index f53fb00f1..000000000
--- a/openslides/core/static/css/core/_chatbox.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Chatbox */
-#chatbox {
- position: fixed;
- top: 40px;
- right: 0;
- width: 40%;
- border-color: #dddddd;
- border-width: 1px;
- box-shadow: -5px 5px 5px rgba(0, 0, 0, 0.2);
- height: 234px;
- padding: 0 10px 10px 10px;
- z-index: 5;
-}
-
-#chatbox-text {
- overflow-y: scroll;
- height: 190px;
- color: #222;
-}
diff --git a/openslides/core/static/css/core/_config.scss b/openslides/core/static/css/core/_config.scss
deleted file mode 100644
index 98e4c52a2..000000000
--- a/openslides/core/static/css/core/_config.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-/** Config **/
-#content .col1 #config {
- .comments > div {
- margin-bottom: 5px;
- }
- .config-checkbox {
- padding: 6px 12px;
- }
- .custom-translations {
- > div {
- margin-bottom: 5px;
- padding-right: 15px;
- width: 100%;
- }
-
- .inputs {
- input {
- width: 47%;
- }
-
- .arrow {
- width: 6%;
- float: left;
- text-align: center;
- }
- }
- }
-}
diff --git a/openslides/core/static/css/core/_countdown.scss b/openslides/core/static/css/core/_countdown.scss
deleted file mode 100644
index 4528805ee..000000000
--- a/openslides/core/static/css/core/_countdown.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-/** Countdown fullscreen mode **/
-#countdownWrapper {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 1000;
- background-color: white;
-}
-#countdownWrapper > div {
- text-align: center;
- margin-top: 50px;
-}
-#countdown {
- display: inline-block;
- padding: 20px 50px;
- border-radius: 8px;
- font-size: 30vw;
- line-height: 1;
- font-weight: bold;
-}
-#countdown .description {
- font-weight: normal;
- font-size: 5vw;
-}
-.warning_time {
- color: #ed940d;
-}
-.negative {
- color: #CC0000;
-}
diff --git a/openslides/core/static/css/core/_csv-import.scss b/openslides/core/static/css/core/_csv-import.scss
deleted file mode 100644
index ddd57a81d..000000000
--- a/openslides/core/static/css/core/_csv-import.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-/* for csv import form */
-#content .col1 #csv-import {
- margin-left: 15px;
- width: 35%;
-
- .file-select {
- input {
- display: none;
- }
-
- label {
- font-weight: normal;
- cursor: pointer;
- }
- }
-
- .clear-file {
- color: #555;
- }
-
- .help-block {
- padding-bottom: 0;
- }
-
- .help-block-big {
- font-size: 100%;
- }
-}
diff --git a/openslides/core/static/css/core/_goto-top.scss b/openslides/core/static/css/core/_goto-top.scss
deleted file mode 100644
index b50fe0c9d..000000000
--- a/openslides/core/static/css/core/_goto-top.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-/** Goto top link **/
-#goto-top {
- position: fixed;
- bottom: 15px;
- right: 30px;
- padding: 10px 30px;
- background: white;
- opacity: 0.8;
- transition: opacity 250ms ease-out;
- z-index: 100;
-
- &:hover {
- opacity: 1;
- transition: opacity 250ms ease-in;
- }
-
- a:hover {
- text-decoration: none;
- }
-}
diff --git a/openslides/core/static/css/core/_manage-projectors.scss b/openslides/core/static/css/core/_manage-projectors.scss
deleted file mode 100644
index 7fd497698..000000000
--- a/openslides/core/static/css/core/_manage-projectors.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-/** manage-projectors **/
-#manage-projectors {
- > div {
- display: inline-table;
- width: 256px;
- margin: 10px 20px 35px 10px;
-
- > div {
- margin-bottom: 10px;
- }
- }
-
- .middle {
- width: 100%;
-
- > div {
- margin-left: auto;
- margin-right: auto;
- display: table;
- }
- }
-
- .dropdown button {
- width: 100%;
- }
-
- .resolution {
- display: inline-block;
- width: 120px;
- }
-}
diff --git a/openslides/core/static/css/core/_messaging.scss b/openslides/core/static/css/core/_messaging.scss
deleted file mode 100644
index 6cede6d82..000000000
--- a/openslides/core/static/css/core/_messaging.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-/** Messaging status bar **/
-#messaging {
- position: fixed;
- bottom: 0;
- width: 100%;
- z-index: 100000;
-}
-
-#messaging-container {
- margin: 0 auto 0 auto;
- padding: 0px 20px;
- max-width: 1400px;
-
- > div {
- margin-bottom: 10px;
- padding: 10px 20px;
- border-radius: 6px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
- }
-}
diff --git a/openslides/core/static/css/core/_multi-table.scss b/openslides/core/static/css/core/_multi-table.scss
deleted file mode 100644
index ce2141e2f..000000000
--- a/openslides/core/static/css/core/_multi-table.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-/* multi list */
-#multi-table {
- table-layout: fixed;
- text-align: center;
-
- thead tr th {
- vertical-align: top;
- text-align: center;
- min-width: 40px;
- overflow: hidden;
- }
-
- .info-head {
- width: 300px;
- &.small {
- width: 200px;
- }
- }
-
- tbody tr:hover {
- background-color: #f5f5f5 !important;
- }
-
- tbody tr.bg-grey {
- background-color: #f9f9f9;
- }
-
- tbody tr td .no-overflow{
- overflow: hidden;
- }
-
- tbody tr td:first-child {
- text-align: left;
- }
-
- tbody tr td div {
- text-align: center;
- }
-
- .optional-show { /* hide optional-show column */
- display: none;
- }
-
- .editable-click {
- color: #000;
- }
-}
diff --git a/openslides/core/static/css/core/_os-table.scss b/openslides/core/static/css/core/_os-table.scss
deleted file mode 100644
index 54197360e..000000000
--- a/openslides/core/static/css/core/_os-table.scss
+++ /dev/null
@@ -1,107 +0,0 @@
-/** OS-Table **/
-#content .col1 .os-table {
- font-weight: normal;
-
- small {
- color: #555;
- }
-
- .row {
- border: 1px solid #ddd;
- border-top: 0px;
-
- .col-xs-1 {
- width: 50px;
- }
-
- .col-xs-4 {
- padding-right: 10px;
- }
-
- .col-space {
- padding: 5px 7px 5px 7px;
- }
-
- // TODO: Isn't this defined in the _helper.scss?
- .centered {
- text-align: center;
- }
- }
-
- .data-row:hover {
- background-color: #f5f5f5;
- }
-
- .data-row > div {
- padding: 10px 0px 10px 0px;
- }
-
- .id-col {
- width: 50px;
- min-height: 1px;
- word-wrap: break-word;
- }
-
- .id-col-space {
- width: calc(100% - 50px);
- }
-
- .no-projector-spacer {
- margin-right: 20px;
- float: left;
- }
-
- .header-row {
- border-top: 1px solid #ddd;
- background-color: #f5f5f5;
- }
-
- .header-row > div {
- padding: 10px;
- }
-
- .main-header {
- width: calc(100% - 50px);
- float: right;
-
- .form-inline {
- margin-left: 15px;
- }
- }
-
- .content > div { /* horizontal blocks */
- display: inline-block;
- float: left;
- }
-
- .content > div > div { /* vertival blocks */
- margin-bottom: 3px;
- }
-
- .content > div > div:last-child {
- margin-bottom: 0px;
- }
-
- .projector {
- width: 70px !important;
- }
-
-
- .header-row .dropdown > span, .sort-spacer {
- padding: 5px 10px 5px 10px;
- }
-
- .title {
- font-family: $font-medium;
- font-family: $font-medium, sans-serif;
- font-weight: normal;
- font-size: 120%;
- margin-right: 3px;
- padding: 0;
- background-color: transparent;
- }
-
- .dropdown-hover-space {
- padding: 5px 5px 5px 0;
- }
-}
diff --git a/openslides/core/static/css/core/_projector-container.scss b/openslides/core/static/css/core/_projector-container.scss
deleted file mode 100644
index f686c7922..000000000
--- a/openslides/core/static/css/core/_projector-container.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-/* ProjectorContainer */
-.pContainer {
- background-color: #222;
- width: 100%;
- height: 100%;
- position: absolute;
- top: 0;
- left: 0;
- display: table;
-
- & > div {
- display: table-cell;
- vertical-align: middle;
- }
-
- #iframe {
- -moz-transform-origin: 0 0;
- -webkit-transform-origin: 0 0;
- -o-transform-origin: 0 0;
- transform-origin: 0 0 0;
- }
-
- #iframewrapper, .error {
- position: relative;
- overflow: hidden;
- margin-left: auto;
- margin-right: auto;
- }
-
- .error > p {
- color: #f00;
- font-size: 150%;
- text-align: center;
- }
-
- #iframeoverlay {
- position: absolute;
- top: 0px;
- left: 0px;
- display: block;
- z-index: 1;
- }
-}
diff --git a/openslides/core/static/css/core/_projector-sidebar.scss b/openslides/core/static/css/core/_projector-sidebar.scss
deleted file mode 100644
index 7ed81d270..000000000
--- a/openslides/core/static/css/core/_projector-sidebar.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Pojector sidebar */
-.col2 .projectorSelector {
- margin-top: 10px;
- margin-bottom: 10px;
-
- & > div {
- margin-bottom: 10px;
-
- & > div {
- width: 65%;
- padding-right: 5px;
- float: left;
- margin-bottom: 10px;
-
- & > button {
- width: 100%;
- overflow: hidden;
- }
- }
- }
-
- .manageBtn {
- width: 35%;
- }
-
- .btn-group {
- margin-left: auto;
- margin-right: auto;
- display: table;
- }
-}
diff --git a/openslides/core/static/css/core/_projector.scss b/openslides/core/static/css/core/_projector.scss
deleted file mode 100644
index d3834ae54..000000000
--- a/openslides/core/static/css/core/_projector.scss
+++ /dev/null
@@ -1,269 +0,0 @@
-@import "projector-container";
-
-/* Template styles for OpenSlides projector */
-html, body {
- height: 100%;
-}
-
-body {
- font-family: $font, sans-serif;
- font-size: 20px !important;
- line-height: 24px !important;
- overflow: hidden;
- color: #222;
-}
-
-h1, h2, h3, h4, h5, h6 {
- font-size: inherit;
- font-family: $font-condensed, sans-serif;
- font-weight: normal;
-}
-
-h1 {
- font-size: 2.25em;
- line-height: 1.1em;
- margin-bottom: 30px;
-}
-
-h2 {
- font-size: 28px;
- margin-top: 15px;
- display: block;
- color: #9a9898;
-}
-
-h3 {
- color: #222;
- margin-bottom: 10px
-}
-
-ul, ol {
- margin: 0 0 10px 0;
-}
-
-hr {
- margin: 10px 0;
-}
-
-#header {
- font-family: $font-condensed-light;
- background-repeat: no-repeat;
- background-size: 100% 100%;
- box-shadow: 0 0 7px rgba(0,0,0,0.6);
- height: 70px;
- margin-bottom: 20px;
-}
-
-#logo {
- position: relative;
- left: 50px;
- top: 10px;
- height: 50px;
- margin-right: 25px;
- float: left;
-}
-
-#eventdata {
- position: relative;
- left: 50px;
- top: 12px;
- height: 50px;
- overflow: hidden;
-
- .title {
- font-size: 26px;
- font-weight: bold;
-
- &.titleonly {
- position: relative;
- top: 12px;
- }
- }
-
- .description {
- font-size: 18px;
- opacity: 0.8;
- }
-}
-
-#currentTime {
- font-family: $font-condensed-light;
- border: 0 solid #000000;
- font-size: 24px;
- position: absolute;
- text-align: right;
- top: 23px;
- right: 50px;
- padding-left: 30px;
-}
-
-#footer {
- font-family: $font-condensed-light;
- position: fixed;
- bottom: 0;
- height: 35px;
- width: 100%;
- font-size: 16px;
- padding-left: 50px;
- padding-right: 50px;
- padding-top: 5px;
- overflow: hidden;
- text-align: right;
-
- span {
- opacity: 0.8;
- }
-}
-
-/* Content */
-.content {
- position: absolute;
- left: 50px;
- right: 50px;
- z-index: -1;
- line-height: 1.5em;
-
- img {
- max-width: 65%;
- height: auto;
- }
-}
-
-.scrollcontent {
- transition-property: margin;
- transition-duration: 1s;
-}
-
-.zoomcontent {
- transition-property: font-size;
- transition-duration: 1s;
-}
-
-.fullscreen {
- position: fixed;
- top: 0 !important;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 100;
- background-color: black;
-
- canvas {
- margin: auto;
- display: block !important;
- }
-}
-
-#title {
- border-bottom: 5px solid #d3d3d3;
- margin-bottom: 40px;
-
- h1 {
- margin-bottom: 0;
- padding-bottom: 0;
- }
-
- h2 {
- margin-top: 10px;
- margin-bottom: 5px;
- }
-}
-
-/* Overlays: countdown and message */
-.countdown {
- min-width: 260px;
- position: relative;
- margin: 0 0 10px 10px;
- top: 0px;
- right: 0px;
- padding: 26px 45px 7px 19px;
- min-height: 72px;
- font-family: $font-condensed, sans-serif;
- font-size: 3.7em;
- font-weight: bold;
- text-align: right;
- border-radius: 7px 7px 7px 7px;
- z-index: 320;
-
- .description {
- font-weight: normal;
- font-size: 18px;
- margin-top: 20px;
- padding-right: 6px;
- }
-}
-
-.message_background {
- background-color: #777777;
- opacity: 0.8;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 300;
-}
-.message {
- font-family: $font-condensed, sans-serif;
- font-weight: normal;
- position: fixed;
- top: 35%;
- left: 10%;
- width: 80%;
- text-align: center;
- border-radius: 0.2em;
- background: #FFFFFF;
- font-size: 2.75em;
- padding: 0.2em 0;
- line-height: normal !important;
- z-index: 350;
-}
-.identify {
- background-color: #D9F8C4;
- z-index: 400;
-}
-
-/* Table style */
-.table {
- border-collapse:collapse;
- border-color:#CCCCCC -moz-use-text-color #CCCCCC #CCCCCC;
- border-style:solid none solid solid;
- border-width:1px medium 1px 1px;
- margin:0;
- border-spacing:0px;
-
- th {
- border-right:1px solid #CCCCCC;
- color:#333333;
- font-weight:normal;
- padding:10px 10px 10px 10px;
- text-align:left;
- text-transform:uppercase;
- }
-
- tr.odd td {
- background:none repeat scroll 0 0 #F1F1F1;
- }
-
- td {
- background:none repeat scroll 0 0 #F7F7F7;
- border-right:1px solid #CCCCCC;
- line-height:120%;
- padding: 10px 10px;
- vertical-align:middle;
- }
-
- tr.total td {
- border-top: 1px solid #333333;
- background-color: #e3e3e3;
- }
-
- tr.elected td {
- background-color: #BED4DE !important;
- }
-}
-
-.transparentTable td {
- background-color: transparent;
- padding-right: 10px;
-}
diff --git a/openslides/core/static/css/core/_search.scss b/openslides/core/static/css/core/_search.scss
deleted file mode 100644
index 7e869cb55..000000000
--- a/openslides/core/static/css/core/_search.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-/* search results */
-.searchresults li {
- margin-bottom: 12px;
-}
-.searchresults h3 {
- margin-bottom: 3px;
- padding-bottom: 0;
-}
-.searchresults .hits {
- margin-bottom: 10px;
- color: #999999;
- font-size: 85%;
-}
diff --git a/openslides/core/static/css/core/_site.scss b/openslides/core/static/css/core/_site.scss
deleted file mode 100644
index df85cc729..000000000
--- a/openslides/core/static/css/core/_site.scss
+++ /dev/null
@@ -1,612 +0,0 @@
-/** Template styles for OpenSlides site **/
-
-@import "config";
-@import "search";
-@import "os-table";
-@import "multi-table";
-@import "csv-import";
-@import "chatbox";
-@import "countdown";
-@import "goto-top";
-@import "messaging";
-
-@import "projector-sidebar";
-@import "manage-projectors";
-
-* { /* set margin/padding for all (block) elements to null */
- margin: 0;
- padding: 0;
-}
-
-body {
- font-size: 14px;
- line-height: 1.5;
- color: #222;
- text-align: center;
- background: #e8eaed;
- font-family: $font, sans-serif !important;
-}
-
-div {
- text-align: left;
-}
-
-img {
- border: none;
-}
-
-a {
- text-decoration: none;
- color: #2b6883;
-
- &:hover {
- text-decoration: underline;
- }
-}
-
-blockquote {
- font-size: inherit;
-}
-
-h1, h2, h3, h4, h5, h6 {
- line-height: 1.1;
- font-family: $font-condensed, sans-serif;
- font-weight: 400;
-}
-
-h1 {
- font-size: 36px;
- color: #317796;
- padding-bottom: 8px;
-}
-
-h2 {
- font-size: 22px;
- color: #9a9898;
- padding-bottom: 14px;
-}
-
-h3 {
- font-size: 22px;
- color: #222;
- padding-bottom: 14px;
-}
-
-h4 {
- font-size: 18px;
- color: #222;
-}
-
-strong, b, th {
- font-family: $font-medium;
- font-family: $font-medium, sans-serif;
- font-weight: normal;
-}
-
-.heading {
- a {
- color: #444;
-
- &:hover {
- color: #2b6883;
- text-decoration: none;
- }
- }
-
-}
-
-/** Header **/
-#header {
- float: left;
- width: 100%;
- height: 40px;
- background: #002c42;
- color: #999;
-
- a.headerlink {
- text-decoration: none;
- color: #999;
- }
-
- a.headerlink:hover, a.headerlink:active, a.headerlink.active {
- color: #e8eaed;
- }
-
- .title {
- float: left;
- margin: 2px 0 0 -5px;
- color: #fff;
- font-family: $font-condensed, sans-serif;
- font-weight: 400;
- }
-
- .user {
- float: right;
- margin: 5px 0 0 0;
- height: 100%;
-
- .inline {
- display: inline;
- }
- }
-}
-
-#nav {
- float: left;
- width: 100%;
- height: auto;
- background: #317796;
- color: #fff;
- overflow-y: hidden;
-
- .navbar {
- width: 100%;
- border: none;
- margin: 0;
- }
-
- .navbar-toggle {
- padding: 5px 0;
- z-index: 2;
-
- i {
- font-size: 28px;
- color: #fff;
- opacity: 0.5;
- }
-
- &:hover i {
- opacity: 1;
- }
- }
-
- .navbar-collapse {
- padding: 0;
- }
-
- .navbar ul {
- list-style: none;
- margin: 0;
-
- li {
- float: left;
- text-align: center;
-
- a {
- display: block;
- color: #fff;
- padding: 22px 15px;
- text-decoration: none;
-
- &:hover {
- background: url('/static/img/nav_dark-bg.png');
- text-decoration: none;
- }
- }
-
- i {
- font-size: 28px;
- display: block;
- margin-bottom: 6px;
- margin-right: 0;
- opacity: 0.5;
- }
- }
-
- li.active {
- background: url('/static/img/nav_dark-bg.png');
-
- a {
- background: url('/static/img/nav_active.png') no-repeat bottom;
- }
-
- i {
- opacity: 1;
- }
- }
- }
-
- .searchbar {
- float: right;
- margin-top: 33px;
- margin-bottom: 32px;
- display: inline-table;
-
- input {
- width: 150px;
- }
-
- .btn {
- background: #e8eaed;
- color: #555;
- }
- }
-}
-
-#header .containerOS, #nav .containerOS, #content .containerOS {
- max-width: 1300px;
- height: 100%;
- margin: 0 auto 0 auto;
- padding: 0 30px;
-}
-
-#content .containerOSExpanded {
- height: 100%;
- margin: 0 auto 0 auto;
- padding: 0 20px;
-}
-
-/** Content **/
-#content {
- float: left;
- width: 100%;
- margin-top: 20px;
-
- .containerOS {
- height: 30px;
- }
-}
-
-
-/** Main column **/
-#content .col1 {
- float: left;
-
- &.sidebar-max { /*with maximized sidebar*/
- width: calc(100% - 325px);
- }
-
- &.sidebar-min { /*with minimized sidebar*/
- width: calc(100% - 70px);
- }
-
- &.sidebar-none { /*without sidebar*/
- width: 100%;
- }
-
- .header {
- background: #fff;
- border: 1px solid #d3d3d3;
-
- .submenu {
- float: right;
- }
- }
-
- .title {
- padding: 0 20px;
- width: auto;
- }
-
-
- .meta {
- .heading, h3 {
- font-family: $font-condensed-light;
- font-size: 22px;
- line-height: 24px;
- font-weight: 300;
- color: #444;
- padding-bottom: 0;
- margin-top: 20px;
- margin-bottom: 5px;
- }
-
- .title {
- width: 100%;
- cursor: pointer;
- height: 30px;
- color: #fff;
- background: #317796;
- padding: 5px 20px 0 20px;
-
- &:hover {
- color: #d3d3d3;
- }
-
- .name {
- float: left;
- font-size: 14px;
- }
-
- .icon {
- float: right;
- }
- }
-
- .detail {
- padding: 0 20px 10px 20px;
- width: 100%;
- min-height: 30px;
- background: #d3d3d3;
- color: #444;
- }
-
- .heading .drop-down-name {
- font-family: $font-condensed-light;
- }
- }
-
- .details {
- padding: 20px;
- width: auto;
- margin-top: 20px;
- background: #fff;
- border: 1px solid #d3d3d3;
-
- img {
- max-width: 100%;
- height: auto;
- }
- }
-
- ol, ul {
- margin-left: 15px;
- }
-}
-
-/** Projector sidebar column **/
-#sidebar-xs {
- display: none !important;
-}
-
-#content .col2 {
- float: right;
- position: relative;
- display: inline-flex;
- z-index: 3;
- margin-bottom: 20px;
-
- &.sidebar-max {
- width: 325px;
- }
-
- &.sidebar-min {
- width: 70px;
- }
-
- &.sidebar-none {
- width: 0px;
- }
-
- h4 {
- font-size: 20px;
- line-height: 24px;
- color: #444;
- font-family: $font-condensed-light;
- font-weight: 300;
- }
-
- a:hover h4 {
- text-decoration: none;
- }
-
- .projector_min {
- background: url('/static/img/nav_projector_sidebar_min.png') no-repeat left 17px;
- width: 50px;
- margin-left: 20px;
- padding-left: 8px;
- float: right;
-
- .icon {
- float: left;
- color: #fff;
- font-size: 24px;
- width: 50px;
- text-align: center;
- padding: 7px 0;
- background: #317796;
-
- a {
- color: #fff;
- display: block;
-
- i {
- opacity: 0.5;
- }
-
- &:hover i {
- opacity: 1;
- }
- }
- }
- }
-
- .projector_full {
- margin-left: 30px;
- width: auto;
-
- .title {
- width: 100%;
- color: #fff;
- height: 50px;
- background: #317796;
- cursor: pointer;
-
- &:hover {
- color: #d3d3d3;
- }
-
- a, a:hover {
- color: #fff;
- text-decoration: none;
- display: block;
- }
-
- i {
- margin-right: 10px;
- }
-
- .name {
- float: left;
- padding: 8px 0 0 20px;
- font-size: 22px;
- font-weight: 400;
- }
-
- .icon {
- float: right;
- width: 50px;
- text-align: center;
- padding-top: 7px;
- font-size: 24px;
- }
-
- }
-
- .details {
- clear: both;
- width: 100%;
- background: #d3d3d3;
-
- .section {
- padding: 1px 20px;
- width: auto;
- border-bottom: 1px solid #c2c2c2;
-
- a:hover {
- text-decoration: none;
- }
-
- div.in.collapse {
- padding-bottom: 15px;
- }
- }
- }
-
- .toggle-icon {
- font-size: 20px;
- float: right;
- margin-top: 10px;
- }
- }
-
- /* countdown and message controls */
- .countdown {
- &.panel {
- margin-bottom: 7px;
- }
-
- .panel-heading {
- padding: 3px 15px;
- }
-
- .panel-body {
- padding: 5px 15px;
- }
-
- .icons {
- padding-right: 10px;
- }
- }
-
- .message {
- &.panel {
- margin-bottom: 7px;
- }
-
- .panel-heading {
- padding: 3px 15px;
- }
-
- .panel-body {
- padding: 10px 15px;
- }
-
- projector-button {
- float: left;
- width: auto;
- margin: 5px 10px 5px 0px;
- }
-
- .innermessage {
- float: left;
- width: 180px;
- max-width: 170px;
- overflow: hidden;
- }
-
- .panel-input {
- width: 228px;
- float: left;
- margin-top: 10px;
- }
-
- .editicon {
- padding-right: 10px;
- }
- }
-
- .countdown_timer {
- font-size: 2.2em;
- font-weight: bold;
-
- &.warning {
- color: #ed940d;
- }
-
- &.negative {
- color: #CC0000;
- }
- }
-
- .notNull {
- color: red;
- font-weight: bold;
- }
-}
-
-/* iframe for live view */
-.iframe {
- -moz-transform-origin: 0 0;
- -webkit-transform-origin: 0 0;
- -o-transform-origin: 0 0;
- transform-origin: 0 0 0;
-}
-
-.iframewrapper {
- width: 258px;
- position: relative;
- overflow: hidden;
- border: 1px solid #D5D5D5;
- margin-bottom: 10px;
-}
-
-.iframeoverlay {
- width: 256px;
- position: absolute;
- top: 0px;
- left: 0px;
- display: block;
- z-index: 1;
-}
-
-/** Footer **/
-#footer {
- float: left;
- height: 50px;
- padding-top: 15px;
- font-size: 90%;
-}
-
-.details h1 {
- font-size: 20px;
- color: #000;
-}
-.details h2 {
- font-size: 18px;
- color: #000;
-}
-.details h3 {
- font-size: 16px;
- color: #000;
-}
-
-/** Config **/
-#config .panel-body {
- padding-top: 0;
-}
-#config.details h3 {
- font-size: 22px;
- padding-top: 30px;
- margin-top: 0;
-}
diff --git a/openslides/core/static/css/projector.scss b/openslides/core/static/css/projector.scss
deleted file mode 100644
index 3090e8bc6..000000000
--- a/openslides/core/static/css/projector.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Main projector CSS file. Just import all files needed for the site here. */
-
-/* General */
-@import "variables";
-@import "helper";
-@import "ui-override";
-@import "core/countdown";
-
-/* Apps */
-@import "core/projector";
-@import "../../../agenda/static/css/agenda/projector";
-@import "../../../assignments/static/css/assignments/projector";
-@import "../../../motions/static/css/motions/projector";
-@import "../../../mediafiles/static/css/mediafiles/projector";
diff --git a/openslides/core/static/css/site.scss b/openslides/core/static/css/site.scss
deleted file mode 100644
index 824a03fc9..000000000
--- a/openslides/core/static/css/site.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Main site CSS file. Just import all files needed for the site here. */
-
-/* General */
-@import "variables"; // TODO: Add colors, ...
-@import "fonts";
-@import "helper";
-@import "mediaqueries";
-@import "ui-override";
-@import "startup-spinner";
-
-/* Apps */
-@import "core/site";
-@import "../../../agenda/static/css/agenda/site";
-@import "../../../assignments/static/css/assignments/site";
-@import "../../../motions/static/css/motions/site";
-@import "../../../users/static/css/users/site";
-@import "../../../mediafiles/static/css/mediafiles/site";
diff --git a/openslides/core/static/img/favicon.png b/openslides/core/static/img/favicon.png
deleted file mode 100644
index 026653c14..000000000
Binary files a/openslides/core/static/img/favicon.png and /dev/null differ
diff --git a/openslides/core/static/img/logo-projector.png b/openslides/core/static/img/logo-projector.png
deleted file mode 100644
index 6b94d9098..000000000
Binary files a/openslides/core/static/img/logo-projector.png and /dev/null differ
diff --git a/openslides/core/static/img/nav_active.png b/openslides/core/static/img/nav_active.png
deleted file mode 100644
index 48be90846..000000000
Binary files a/openslides/core/static/img/nav_active.png and /dev/null differ
diff --git a/openslides/core/static/img/nav_dark-bg.png b/openslides/core/static/img/nav_dark-bg.png
deleted file mode 100644
index f53619aff..000000000
Binary files a/openslides/core/static/img/nav_dark-bg.png and /dev/null differ
diff --git a/openslides/core/static/img/nav_projector_sidebar_min.png b/openslides/core/static/img/nav_projector_sidebar_min.png
deleted file mode 100644
index d8d3e371f..000000000
Binary files a/openslides/core/static/img/nav_projector_sidebar_min.png and /dev/null differ
diff --git a/openslides/core/static/img/openslides-logo-dark.png b/openslides/core/static/img/openslides-logo-dark.png
deleted file mode 100644
index 52e165828..000000000
Binary files a/openslides/core/static/img/openslides-logo-dark.png and /dev/null differ
diff --git a/openslides/core/static/img/openslides-logo.png b/openslides/core/static/img/openslides-logo.png
deleted file mode 100644
index b39a3f5ed..000000000
Binary files a/openslides/core/static/img/openslides-logo.png and /dev/null differ
diff --git a/openslides/core/static/index.html b/openslides/core/static/index.html
new file mode 100644
index 000000000..e212cbf1e
--- /dev/null
+++ b/openslides/core/static/index.html
@@ -0,0 +1,3 @@
+Hello user!
+
+Use This url to get to the client. For further information see the DEVELOPMENT.rst
diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js
deleted file mode 100644
index 4f1992ed5..000000000
--- a/openslides/core/static/js/core/base.js
+++ /dev/null
@@ -1,1723 +0,0 @@
-(function () {
-
-'use strict';
-
-// The core module used for the OpenSlides site and the projector
-angular.module('OpenSlidesApp.core', [
- 'js-data',
- 'gettext',
- 'ngAnimate',
- 'ngBootbox',
- 'ngSanitize', // TODO: only use this in functions that need it.
- 'ngStorage',
- 'ui.bootstrap',
- 'ui.bootstrap.datetimepicker',
- 'ui.tree',
- 'pdf',
- 'OpenSlidesApp-templates',
-])
-
-.config([
- 'DSProvider',
- 'DSHttpAdapterProvider',
- function(DSProvider, DSHttpAdapterProvider) {
- DSProvider.defaults.reapAction = 'none';
- DSProvider.defaults.basePath = '/rest';
- DSProvider.defaults.afterReap = function(model, items) {
- if (items.length > 5) {
- model.findAll({}, {bypassCache: true});
- } else {
- _.forEach(items, function (item) {
- model.refresh(item[model.idAttribute]);
- });
- }
- };
- DSHttpAdapterProvider.defaults.forceTrailingSlash = true;
- }
-])
-
-.factory('ProjectorID', [
- function () {
- return function () {
- return /projector\/(\d+)\//.exec(location.pathname)[1];
- };
- }
-])
-
-.config([
- '$sessionStorageProvider',
- function ($sessionStorageProvider) {
- $sessionStorageProvider.setKeyPrefix('OpenSlides');
- }
-])
-
-.factory('autoupdate', [
- 'DS',
- 'REALM',
- 'ProjectorID',
- '$q',
- '$timeout',
- 'ErrorMessage',
- function (DS, REALM, ProjectorID, $q, $timeout, ErrorMessage) {
- var socket = null;
- var retryConnectCallbacks = [];
-
- var websocketProtocol;
- if (location.protocol == 'https:') {
- websocketProtocol = 'wss:';
- } else {
- websocketProtocol = 'ws:';
- }
-
- var websocketPath;
- if (REALM === 'site') {
- websocketPath = '/ws/site/';
- } else if (REALM === 'projector') {
- websocketPath = '/ws/projector/' + ProjectorID() + '/';
- } else {
- console.error('The constant REALM is not set properly.');
- }
-
- // Get a random retry timeout between 2000 and 5000 ms.
- var getTimeoutTime = function () {
- return Math.floor(Math.random() * 3000 + 2000);
- };
-
- /* The callbacks are invoked if the ws connection closed and this factory tries to
- * reconnect after 1 second. The callbacks should return a promise. If the promise
- * resolves, the retry-process is stopped, so the callback can indicate whether it
- * has managed the reconnecting different.*/
- var runRetryConnectCallbacks = function () {
- var callbackPromises = _.map(retryConnectCallbacks, function (callback) {
- return callback();
- });
- $q.all(callbackPromises).then(function (success) {
- ErrorMessage.clearConnectionError();
- }, function (error) {
- $timeout(runRetryConnectCallbacks, getTimeoutTime());
- });
- };
-
- var Autoupdate = {};
- Autoupdate.messageReceivers = [];
- // We use later a promise to defer the first message of the established ws connection.
- Autoupdate.firstMessageDeferred = $q.defer();
- Autoupdate.onMessage = function (receiver) {
- Autoupdate.messageReceivers.push(receiver);
- };
- Autoupdate.newConnect = function () {
- socket = new WebSocket(websocketProtocol + '//' + location.host + websocketPath);
- // Make shure the servers state hasn't changed: Send a whoami request. If no users is logged and
- // anonymous are deactivated, reboot the client in fact that the server has lost all login information.
- socket.onclose = function (event) {
- socket = null;
- if (event.code !== 1000) { // 1000 is a normal close, like the close on logout
- ErrorMessage.setConnectionError();
- }
- $timeout(runRetryConnectCallbacks, getTimeoutTime());
- };
- socket.onmessage = function (event) {
- var data;
- try {
- data = JSON.parse(event.data);
- _.forEach(Autoupdate.messageReceivers, function (receiver) {
- receiver(data);
- });
- } catch(err) {
- console.error(err);
- }
- // Check if the promise is not resolved yet.
- if (Autoupdate.firstMessageDeferred.promise.$$state.status === 0) {
- Autoupdate.firstMessageDeferred.resolve();
- }
- ErrorMessage.clearConnectionError();
- };
- };
- Autoupdate.send = function (type, content) {
- if (!socket) {
- return;
- }
-
- var message = {
- type: type,
- content: content,
- id: '',
- };
-
- // Generate random id
- var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
- for (var i = 0; i < 8; i++) {
- message.id += possible.charAt(Math.floor(Math.random() * possible.length));
- }
- socket.send(JSON.stringify(message));
- };
- Autoupdate.closeConnection = function () {
- if (socket) {
- socket.close();
- }
- Autoupdate.firstMessageDeferred = $q.defer();
- };
- Autoupdate.registerRetryConnectCallback = function (callback) {
- retryConnectCallbacks.push(callback);
- };
- return Autoupdate;
- }
-])
-
-.factory('operator', [
- 'User',
- 'Group',
- function (User, Group) {
- var setUserCallbacks = [];
- var operator = {
- user: null,
- perms: [],
- isAuthenticated: function () {
- return !!this.user;
- },
- setUser: function(user_id, user_data) {
- if (user_id && user_data) {
- operator.user = User.inject(user_data);
- } else {
- operator.user = null;
- }
- operator.reloadPerms();
- _.forEach(setUserCallbacks, function (cb) {
- cb(operator.user);
- });
- },
- // Returns true if the operator has at least one perm of the perms-list.
- hasPerms: function(perms) {
- if (typeof perms === 'string') {
- perms = perms.split(' ');
- }
- return _.intersection(perms, operator.perms).length > 0;
- },
- reloadPerms: function () {
- if (operator.user) {
- operator.perms = operator.user.getPerms();
- } else {
- var defaultGroup = Group.get(1);
- operator.perms = defaultGroup ? defaultGroup.permissions : [];
- }
- },
- // Returns true if the operator is a member of group.
- isInGroup: function(group) {
- var groups = operator.user.groups_id;
- if (groups.length === 0) {
- groups = [1]; // Set the default group, if no other groups are set.
- }
- return _.indexOf(groups, group.id) > -1;
- },
- registerSetUserCallback: function (cb) {
- setUserCallbacks.push(cb);
- },
- };
- return operator;
- }
-])
-
-// gets all in OpenSlides available languages
-.factory('Languages', [
- '$sessionStorage',
- '$ngBootbox',
- 'gettext',
- 'gettextCatalog',
- 'OpenSlidesPlugins',
- function ($sessionStorage, $ngBootbox, gettext, gettextCatalog, OpenSlidesPlugins) {
- return {
- // get all available languages
- getLanguages: function () {
- var current = $sessionStorage.language;
- // Define here new languages...
- var languages = [
- { code: 'en', name: 'English' },
- { code: 'de', name: 'Deutsch' },
- { code: 'fr', name: 'Français' },
- { code: 'es', name: 'Español' },
- { code: 'pt', name: 'Português' },
- { code: 'cs', name: 'Čeština'},
- { code: 'ru', name: 'русский'},
- ];
- angular.forEach(languages, function (language) {
- if (language.code == current)
- language.selected = true;
- });
- return languages;
- },
- // get detected browser language code
- getBrowserLanguage: function () {
- var lang = navigator.language || navigator.userLanguage;
- if (!navigator.language && !navigator.userLanguage) {
- lang = 'en';
- } else {
- if (lang.indexOf('-') !== -1)
- lang = lang.split('-')[0];
- if (lang.indexOf('_') !== -1)
- lang = lang.split('_')[0];
- }
- return lang;
- },
- // set current language and return updated languages object array
- setCurrentLanguage: function (lang) {
- var languages = this.getLanguages();
- var plugins = OpenSlidesPlugins.getAll();
- angular.forEach(languages, function (language) {
- language.selected = false;
- if (language.code == lang) {
- language.selected = true;
- $sessionStorage.language = lang;
- gettextCatalog.setCurrentLanguage(lang);
- // Plugins
- if (lang != 'en') {
- gettextCatalog.loadRemote("static/i18n/" + lang + ".json").then(function (success) {
- // translate ng-bootbox directives when the translations are available.
- $ngBootbox.addLocale(lang, {
- OK: gettextCatalog.getString('OK'),
- CANCEL: gettextCatalog.getString('Cancel'),
- CONFIRM: gettextCatalog.getString('OK'), // Yes, 'OK' is the original string.
- });
- $ngBootbox.setLocale(lang);
- });
- // load language files from plugins
- angular.forEach(plugins, function (plugin) {
- if (plugin.languages.indexOf(lang) != -1) {
- gettextCatalog.loadRemote("static/i18n/" + plugin.name + '/' + lang + ".json");
- }
- });
- }
- }
- });
- return languages;
- }
- };
- }
-])
-
-// Hook into gettextCatalog to include custom translations by wrapping
-// the getString method. The translations are stored in the config.
-.decorator('gettextCatalog', [
- '$delegate',
- '$rootScope',
- function ($delegate, $rootScope) {
- var oldGetString = $delegate.getString;
- var customTranslations = {};
-
- $delegate.getString = function () {
- var translated = oldGetString.apply($delegate, arguments);
- if (customTranslations[translated]) {
- translated = customTranslations[translated];
- }
- return translated;
- };
- $delegate.setCustomTranslations = function (translations) {
- customTranslations = translations;
- $rootScope.$broadcast('gettextLanguageChanged');
- };
-
- return $delegate;
- }
-])
-
-.run([
- '$rootScope',
- 'Config',
- 'gettextCatalog',
- function ($rootScope, Config, gettextCatalog) {
- $rootScope.$watch(function () {
- return Config.lastModified('translations');
- }, function () {
- var translations = Config.get('translations');
- if (translations) {
- var customTranslations = {};
- _.forEach(translations.value, function (entry) {
- customTranslations[entry.original] = entry.translation;
- });
- // Update all translate directives
- gettextCatalog.setCustomTranslations(customTranslations);
- }
- });
- }
-])
-
-// set browser language as default language for OpenSlides
-.run([
- '$sessionStorage',
- 'gettextCatalog',
- 'Languages',
- function($sessionStorage, gettextCatalog, Languages) {
- // set detected browser language as default language (fallback: 'en')
- if ($sessionStorage.language) {
- Languages.setCurrentLanguage($sessionStorage.language);
- } else {
- Languages.setCurrentLanguage(Languages.getBrowserLanguage());
- }
- // Set this to true for debug. Helps to find untranslated strings by
- // adding "[MISSING]:".
- gettextCatalog.debug = false;
- }
-])
-
-.factory('dsEject', [
- 'DS',
- function (DS) {
- return function (collection, instance) {
- var Resource = DS.definitions[collection];
- if (Resource.relationList) {
- Resource.relationList.forEach(function (relationDef) {
- if (relationDef.foreignKey && !relationDef.osProtectedRelation) {
- var query = {};
- query[relationDef.foreignKey] = instance[Resource.idAttribute];
- Resource.getResource(relationDef.relation).ejectAll(query);
- }
- });
- }
- };
- }
-])
-
-.run([
- 'DS',
- 'autoupdate',
- 'dsEject',
- function (DS, autoupdate, dsEject) {
- // Handler for normal autoupdate messages.
- autoupdate.onMessage(function(data) {
- if (data.type !== 'autoupdate') {
- return;
- }
-
- var dataList = data.content;
- var dataListByCollection = _.groupBy(dataList, 'collection');
- _.forEach(dataListByCollection, function (list, key) {
- var changedElements = [];
- var deletedElements = [];
- var collectionString = key;
- _.forEach(list, function (data) {
- // Uncomment this line for debugging to log all autoupdates:
- // console.log("Received object: " + data.collection + ", " + data.id);
-
- // remove (=eject) object from local DS store
- var instance = DS.get(data.collection, data.id);
- if (instance) {
- dsEject(data.collection, instance);
- }
- // check if object changed or deleted
- if (data.action === 'changed') {
- changedElements.push(data.data);
- } else if (data.action === 'deleted') {
- deletedElements.push(data.id);
- } else {
- console.error('Error: Undefined action for received object' +
- '(' + data.collection + ', ' + data.id + ')');
- }
- });
- // add (=inject) all given objects into local DS store
- if (changedElements.length > 0) {
- DS.inject(collectionString, changedElements);
- }
- // delete (=eject) all given objects from local DS store
- // (note: js-data does not provide 'bulk eject' as for DS.inject)
- _.forEach(deletedElements, function(id) {
- DS.eject(collectionString, id);
- });
- });
- });
- }
-])
-
-.factory('Notify', [
- 'autoupdate',
- 'operator',
- function (autoupdate, operator) {
- var anonymousTrackId;
-
- // Handler for notify messages.
- autoupdate.onMessage(function(data) {
- if (data.type !== 'notify') {
- return;
- }
-
- var dataList = data.content;
- var dataListByCollection = _.groupBy(dataList, 'collection');
- _.forEach(dataListByCollection.notify, function (notifyItem) {
- // Check, if this current user (or anonymous instance) has send this notify.
- if (notifyItem.senderUserId) {
- if (operator.user) { // User send to user
- notifyItem.sendBySelf = (notifyItem.senderUserId === operator.user.id);
- } else { // User send to anonymous
- notifyItem.sendBySelf = false;
- }
- } else {
- if (operator.user) { // Anonymous send to user
- notifyItem.sendBySelf = false;
- } else { // Anonymous send to anonymous
- notifyItem.sendBySelf = (notifyItem.anonymousTrackId === anonymousTrackId);
- }
- }
- // notify registered receivers.
- _.forEach(callbackReceivers[notifyItem.name], function (item) {
- item.fn(notifyItem);
- });
- });
- });
-
- var callbackReceivers = {};
- /* Structure of callbackReceivers:
- * event_name_one: [ {id:0, fn:fn}, {id:3, fn:fn} ],
- * event_name_two: [ {id:2, fn:fn} ],
- * */
- var idCounter = 0;
- var eventNameRegex = new RegExp('^[a-zA-Z0-9_-]+$');
- var externIdRegex = new RegExp('^[a-zA-Z0-9_-]+\/[0-9]+$');
- return {
- registerCallback: function (eventName, fn) {
- if (!eventNameRegex.test(eventName)) {
- throw 'eventName should only consist of [a-zA-Z0-9_-]';
- } else if (typeof fn === 'function') {
- var id = idCounter++;
-
- if (!callbackReceivers[eventName]) {
- callbackReceivers[eventName] = [];
- }
- callbackReceivers[eventName].push({
- id: id,
- fn: fn,
- });
- return eventName + '/' + id;
- } else {
- throw 'fn should be a function.';
- }
- },
- deregisterCallback: function (externId) {
- if (externIdRegex.test(externId)){
- var split = externId.split('/');
- var eventName = split[0];
- var id = parseInt(split[1]);
- callbackReceivers[eventName] = _.filter(callbackReceivers[eventName], function (item) {
- return item.id !== id;
- });
- } else {
- throw externId + ' is not a valid id';
- }
- },
- // variable length of parameters, just pass ids.
- deregisterCallbacks: function () {
- _.forEach(arguments, this.deregisterCallback);
- },
- notify: function(eventName, params, users, channels, projectors) {
- if (eventNameRegex.test(eventName)) {
- if (!params || typeof params !== 'object') {
- params = {};
- }
-
- var notifyItem = {
- collection: 'notify',
- name: eventName,
- params: params,
- users: users,
- replyChannels: channels,
- projectors: projectors,
- };
- if (!operator.user) {
- if (!anonymousTrackId) {
- anonymousTrackId = Math.floor(Math.random()*1000000);
- }
- notifyItem.anonymousTrackId = anonymousTrackId;
- }
- autoupdate.send('notify', [notifyItem]);
- } else {
- throw 'eventName should only consist of [a-zA-Z0-9_-]';
- }
- },
- };
- }
-])
-
-.run([
- 'autoupdate',
- function (autoupdate) {
- // Handler for normal autoupdate messages.
- autoupdate.onMessage(function (data) {
- if (data.type === 'error') {
- console.error("Websocket error", data.content);
- }
- });
- }
-])
-
-// Save the server time to the rootscope.
-.run([
- '$http',
- '$rootScope',
- function ($http, $rootScope) {
- // Loads server time and calculates server offset
- $rootScope.serverOffset = 0;
- $http.get('/core/servertime/')
- .then(function(data) {
- $rootScope.serverOffset = Math.floor(Date.now() / 1000 - data.data);
- });
- }
-])
-
-.run([
- 'Config',
- '$rootScope',
- function (Config, $rootScope) {
- $rootScope.config = function (key) {
- try {
- return Config.get(key).value;
- }
- catch(err) {
- return '';
- }
- };
- }
-])
-
-// Make the indexOf available in every scope; needed for the projectorbuttons
-.run([
- '$rootScope',
- function ($rootScope) {
- $rootScope.inArray = function (array, value) {
- return _.indexOf(array, value) > -1;
- };
- }
-])
-
-// Put the Math object into every scope.
-.run([
- '$rootScope',
- function ($rootScope) {
- $rootScope.Math = window.Math;
- }
-])
-
-// Template hooks
-// Possible uses:
-// 1. { id: 'myHookId', template: 'click me ' }
-// 2. { id: 'myHookId', templateUrl: '/static/templates/plugin_name/my-hook.html' }
-// 3. { id: 'myHookId' }
-//
-// Deprecated: Give the id with 'Id'. Please use 'id'.
-//
-// Option 3 is for just changing the scope (see below), but not the original content. This
-// is usefull to alter a JS behavior, e.g. on a ng-click. In this case, override is false
-// for this template hook.
-//
-// It is possible to provide a scope, that is merged into the surrounding scope.
-// You can override functions or values of the surrounding scope by providing them:
-// { id: 'hookId', template: 'click me ',
-// scope: {
-// customOrOverwritten: function () { /*Do something */ },
-// },
-// }
-// Or you provide a function that returns an object of functions/values to overwrite to
-// get access to the scope merged in:
-// { id: 'hookId', template: 'click me ',
-// scope: function (scope) {
-// return {
-// customOrOverwritten: function () {
-// scope.value = /* change it */;
-// },
-// };
-// },
-// }
-//
-// As a default, template hooks in flavour of option 1 and 2 override the content that was
-// originally there. Provide 'override: false', to prevent overriding the original content.
-.factory('templateHooks', [
- function () {
- var hooks = {};
- return {
- hooks: hooks,
- registerHook: function (hook) {
- // Deprecated: Set the new style 'id', if 'Id' is given.
- if (hook.id === void 0) {
- hook.id = hook.Id;
- }
-
- if (hooks[hook.id] === void 0) {
- hooks[hook.id] = [];
- }
- // set override default
- if (hook.override === void 0) {
- hook.override = !!(hook.template || hook.templateUrl);
- }
- hooks[hook.id].push(hook);
- }
- };
- }
-])
-
-.directive('templateHook', [
- '$compile',
- '$http',
- '$q',
- '$templateCache',
- '$timeout',
- 'templateHooks',
- function ($compile, $http, $q, $templateCache, $timeout, templateHooks) {
- return {
- restrict: 'E',
- template: '',
- link: function (scope, iElement, iAttr) {
- var hooks = templateHooks.hooks[iAttr.hookName];
- if (hooks) {
- // Populate scopes
- _.forEach(hooks, function (hook) {
- var _scope = hook.scope;
- // If it is a function, get the scope from the function and provide
- // the original scope.
- if (typeof hook.scope === 'function') {
- _scope = hook.scope(scope);
- }
-
- _.forEach(_scope, function (value, key) {
- scope[key] = value;
- });
- });
-
- // Check, if at least one hook overrides the original content.
- var override = _.some(hooks, function (hook) {
- return hook.override;
- });
-
- // filter hooks, that does actually have a template
- hooks = _.filter(hooks, function (hook) {
- return hook.template || hook.templateUrl;
- });
-
- // Get all templates
- var templates = _.map(hooks, function (hook) {
- // Either a template (html given as string) or a templateUrl has
- // to be given. If a scope is provided, the schope of this templateHook
- // is populated with the given functions/values.
- if (hook.template) {
- return hook.template;
- } else {
- return $templateCache.get(hook.templateUrl);
- }
- });
-
- // Wait for the dom to build up, so we can retrieve the inner html of iElement.
- $timeout(function () {
- var html = override ? '' : iElement.html();
- if (templates.length) {
- html += templates.join('');
- }
-
- iElement.empty();
- iElement.append($compile(html)(scope));
- });
- }
- }
- };
- }
-])
-
-/*
- * This places a projector button in the document.
- *
- * Example:
- * This button references to model (in this example 'motion'). Also a defaultProjectionId
- * has to be given. In the example it's a scope variable. The next two parameters are additional:
- * - arg: Then the model.project and model.isProjected will be called with
- * this argument (e. g.: model.project(2))
- * - content: A text placed behind the projector symbol.
- */
-.directive('projectorButton', [
- 'Projector',
- function (Projector) {
- return {
- restrict: 'E',
- templateUrl: 'static/templates/projector-button.html',
- link: function (scope, element, attributes) {
- if (!attributes.model) {
- throw 'A model has to be given!';
- } else if (!attributes.defaultProjectorId) {
- throw 'A default-projector-id has to be given!';
- }
-
- Projector.bindAll({}, scope, 'projectors');
-
- scope.$watch(attributes.model, function (model) {
- scope.model = model;
- });
-
- scope.$watch(attributes.defaultProjectorId, function (defaultProjectorId) {
- scope.defaultProjectorId = defaultProjectorId;
- });
-
- if (attributes.arg) {
- scope.$watch(attributes.arg, function (arg) {
- scope.arg = arg;
- });
- }
-
- scope.content = '';
- if (attributes.content) {
- attributes.$observe('content', function (content) {
- scope.content = content;
- });
- }
- }
- };
- }
-])
-
-.factory('jsDataModel', [
- '$http',
- 'Projector',
- 'ProjectHelper',
- function($http, Projector, ProjectHelper) {
- var BaseModel = function() {};
- BaseModel.prototype.project = function(projectorId) {
- // if this object is already projected on projectorId, delete this element from this projector
- var isProjectedIds = this.isProjected();
- var requestData = {
- clear_ids: isProjectedIds,
- };
- // Show the element, if it was not projected before on the given projector
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- requestData.prune = {
- id: projectorId,
- element: {name: this.getResourceName(), id: this.id},
- };
- }
- return ProjectHelper.project(requestData);
- };
- BaseModel.prototype.isProjected = function() {
- // Returns the ids of all projectors if there is a projector element
- // with the same name and the same id. Else returns an empty list.
- var self = this;
- var predicate = function (element) {
- return element.name == self.getResourceName() &&
- typeof element.id !== 'undefined' &&
- element.id == self.id;
- };
- var isProjectedIds = [];
- Projector.getAll().forEach(function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- isProjectedIds.push(projector.id);
- }
- });
- return isProjectedIds;
- };
- // Override this method to get object specific behavior
- BaseModel.prototype.isRelatedProjected = function() {
- throw "needs to be implemented!";
- };
- return BaseModel;
- }
-])
-
-.factory('ErrorMessage', [
- '$timeout',
- 'gettextCatalog',
- 'Messaging',
- function ($timeout, gettextCatalog, Messaging) {
- return {
- forAlert: function (error) {
- var message = gettextCatalog.getString('Error') + ': ';
-
- if (!error.data) {
- message += gettextCatalog.getString("The server didn't respond.");
- } else if (error.data.detail) {
- message += error.data.detail;
- } else if (error.status > 500) { // Some kind of server error.
- message += gettextCatalog.getString("A server error occurred (%%code%%). Please check the system logs.");
- message = message.replace('%%code%%', error.status);
- } else {
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- }
- return { type: 'danger', msg: message, show: true };
- },
- setConnectionError: function () {
- $timeout(function () {
- Messaging.createOrEditMessage(
- 'connectionLostMessage',
- gettextCatalog.getString('Offline mode: You can use OpenSlides but changes are not saved.'),
- 'warning',
- {noClose: true});
- }, 1);
- },
- clearConnectionError: function () {
- $timeout(function () {
- Messaging.deleteMessage('connectionLostMessage');
- }, 1);
- },
- };
- }
-])
-
-/* Messaging factory. The text is html-binded into the document, so you can
- * provide also html markup for the messages. There are 4 types: 'info',
- * 'success', 'warning', 'error'. The timeout is for autodeleting the message.
- * Args that could be provided:
- * - timeout: Milliseconds until autoclose the message (default: not set, no auto close)
- * - noClose: Whether to show the close button (default: false)
- */
-.factory('Messaging', [
- '$timeout',
- function($timeout) {
- var callbackList = [],
- messages = {},
- idCounter = 0;
-
- var onChange = function () {
- _.forEach(callbackList, function (callback) {
- callback();
- });
- };
-
- return {
- addMessage: function (text, type, args) {
- var id = idCounter++;
- return this.createOrEditMessage(id, text, type, args);
- },
- createOrEditMessage: function (id, text, type, args) {
- if (!args) {
- args = {};
- }
- if (messages[id] && messages[id].timeout) {
- $timeout.cancel(messages[id].timeout);
- }
- messages[id] = {
- text: text,
- type: type,
- id: id,
- args: args,
- };
- if (typeof args.timeout === 'number' && args.timeout > 0) {
- var self = this;
- messages[id].timeout = $timeout(function () {
- self.deleteMessage(id);
- }, args.timeout);
- }
- onChange();
- return id;
- },
- deleteMessage: function (id) {
- delete messages[id];
- onChange();
- },
- getMessages: function () {
- return messages;
- },
- registerMessageChangeCallback: function (fn) {
- if (typeof fn === 'function') {
- callbackList.push(fn);
- } else {
- throw 'fn has to be a function';
- }
- },
- };
- }
-])
-
-.factory('Logos', [
- 'Config',
- 'gettext',
- function (Config, gettext) {
- return {
- getKeys: function () {
- return Config.get('logos_available').value;
- },
- getAll: function () {
- var self = this;
- return _.map(this.getKeys(), function (key) {
- return self.get(key);
- });
- },
- get: function (key) {
- var config = Config.get(key);
- if (config) {
- config.value.key = key;
- return config.value;
- }
- },
- set: function (key, path) {
- var config = Config.get(key);
- if (config) {
- config.value.path = path || '';
- Config.save(key);
- }
- },
- };
- }
-])
-
-.factory('Fonts', [
- 'Config',
- 'gettext',
- function (Config, gettext) {
- var extensionFormatMap = {
- 'ttf': 'truetype',
- 'woff': 'woff',
- };
-
- return {
- getKeys: function () {
- return Config.get('fonts_available').value;
- },
- getAll: function () {
- var self = this;
- return _.map(this.getKeys(), function (key) {
- return self.get(key);
- });
- },
- get: function (key) {
- var config = Config.get(key);
- if (config) {
- config.value.key = key;
- return config.value;
- }
- },
- getUrl: function (key) {
- var font = this.get(key);
- if (font) {
- var path = font.path;
- if (!path) {
- return font.default;
- }
- return path;
- }
- },
- getForCss: function (key) {
- var url = this.getUrl(key);
- if (url) {
- var ext = _.last(url.split('.'));
- return "url('" + url + "') format('" +
- extensionFormatMap[ext] + "')";
- }
- },
- set: function (key, path) {
- var config = Config.get(key);
- if (config) {
- config.value.path = path || '';
- Config.save(key);
- }
- },
- };
- }
-])
-
-.factory('Tag', [
- 'DS',
- function(DS) {
- return DS.defineResource({
- name: 'core/tag',
- });
- }
-])
-
-.factory('Config', [
- '$http',
- 'gettextCatalog',
- 'DS',
- function($http, gettextCatalog, DS) {
- var configOptions;
- return DS.defineResource({
- name: 'core/config',
- idAttribute: 'key',
- translate: function (value) {
- return gettextCatalog.getString(value);
- }
- });
- }
-])
-
-.factory('ChatMessage', [
- 'DS',
- function(DS) {
- return DS.defineResource({
- name: 'core/chat-message',
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
- }
- }
- }
- });
- }
-])
-
-/*
- * Provides a function for plugins to register as new plugin.
- *
- * Get all registerd plugins via 'OpenSlidesPlugins.getAll()'.
- *
- * Example code for plugins:
- *
- * .config([
- * 'OpenSlidesPluginsProvider',
- * function(OpenSlidesPluginsProvider) {
- * OpenSlidesPluginsProvider.registerPlugin({
- * name: 'openslides_votecollector',
- * display_name: 'VoteCollector',
- * languages: ['de']
- * });
- * }
- * ])
- */
-.provider('OpenSlidesPlugins', [
- function () {
- var provider = this;
- provider.plugins = [];
- provider.registerPlugin = function (plugin) {
- provider.plugins.push(plugin);
- };
- provider.$get = [
- function () {
- return {
- getAll: function () {
- return provider.plugins;
- }
- };
- }
- ];
- }
-])
-
-
-// Configs for CKEditor which has to set while startup of OpenSlides
-.config(
- function() {
- CKEDITOR.disableAutoInline = true;
- }
-)
-
-// Options for CKEditor used in various create and edit views.
-// Required in core/base.js because MotionComment factory which used this
-// factory has to placed in motions/base.js.
-.factory('Editor', [
- 'gettextCatalog',
- function (gettextCatalog) {
- var extraPlugins = [];
- return {
- registerDialog: function (name, dialog) {
- CKEDITOR.dialog.add(name, dialog);
- },
- registerPlugin: function (name, plugin) {
- CKEDITOR.plugins.add(name, plugin);
- extraPlugins.push(name);
- },
- /* Provide special keyword in the arguments for a special behaviour:
- * Example: getOptions('inline', 'YOffset')
- * Available keywords:
- * - inline: smaller toolbar
- * - YOffset: move the editor toolbar 40px up
- */
- getOptions: function () {
- var extraPluginsString = 'colorbutton,colordialog,find,sourcedialog,justify,showblocks';
- var registeredPluginsString = extraPlugins.join(',');
- if (registeredPluginsString) {
- extraPluginsString += ',' + registeredPluginsString;
- }
- var options = {
- on: {
- instanceReady: function() {
- // This adds a listener to ckeditor to remove unwanted blank lines on import.
- // Clipboard content varies heavily in structure and html code, depending on the "sender".
- // Here it is first parsed into a pseudo-DOM (two lines taken from a ckeditor
- // paste example on the ckeditor site).
- this.on('paste', function(evt) {
- if (evt.data.type == 'html') {
- var fragment = CKEDITOR.htmlParser.fragment.fromHtml(evt.data.dataValue);
- var writer = new CKEDITOR.htmlParser.basicWriter();
- // html content will now be in a dom-like structure inside 'fragment'.
- this.filter.applyTo(fragment);
- if (fragment.children) {
- // If this fragment is DOM-like, it may contain nested properties
- // (being html nodes). Traverse the children and check if it is a
- // child only containing empty or .
- // new_content_children will finally contain all nodes that are
- // not empty.
- var new_content_children = [];
- _.forEach(fragment.children, function (child) {
- var empty = true;
- if (child.children){
- _.forEach(child.children, function(grandchild) {
- if (grandchild.name != 'p' && grandchild.name != 'br') {
- empty = false;
- } else if (grandchild.isEmpty !== true) {
- empty = false;
- }
- });
- if (empty === false) {
- new_content_children.push(child);
- }
- } else {
- if (child.name != 'p' && child.name != 'br' &&
- child.isEmpty !== true){
- new_content_children.push(child);
- }
- }
- });
- fragment.children = new_content_children;
- }
- fragment.writeHtml(writer);
- // Return the re-created fragment without the empty
and into the
- // editor import processing (same as at the begin of the function: by ckeditor)
- evt.data.dataValue = writer.getHtml();
- }
- });
- }
- },
- customConfig: '',
- floatSpaceDockedOffsetY: _.indexOf(arguments, 'YOffset') > -1 ? 35 : 0,
- disableNativeSpellChecker: false,
- language_list: [
- 'fr:français',
- 'es:español',
- 'pt:português',
- 'en:english',
- 'de:deutsch',
- 'cs:čeština'],
- language: gettextCatalog.getCurrentLanguage(),
- allowedContent:
- 'h1 h2 h3 b i u strike sup sub strong em;' +
- 'blockquote p pre table' +
- '(text-align-left,text-align-center,text-align-right,text-align-justify,os-split-before,os-split-after){text-align, float, padding};' +
- 'a[!href];' +
- 'img[!src,alt]{width,height,float, padding};' +
- 'tr th td caption;' +
- 'li(os-split-before,os-split-after); ol(os-split-before,os-split-after)[start]{list-style-type};' +
- 'ul(os-split-before,os-split-after){list-style};' +
- 'span[!*]{color,background-color}(os-split-before,os-split-after,os-line-number,line-number-*);' +
- 'br(os-line-break);',
-
- // there seems to be an error in CKeditor that parses spaces in extraPlugins as part of the plugin name.
- extraPlugins: extraPluginsString,
- removePlugins: 'wsc,scayt,a11yhelp,filebrowser,sourcearea,liststyle,tabletools,tableselection,contextmenu,image',
- removeButtons: 'Scayt,Anchor,Styles,HorizontalRule',
- };
- if (_.indexOf(arguments, 'inline') > -1) {
- options.toolbarGroups = [
- { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
- { name: 'colors', groups: [ 'colors' ] },
- { name: 'paragraph', groups: [ 'list'] },
- { name: 'links', groups: [ 'links' ] },
- { name: 'clipboard', groups: [ 'undo' ] },
- { name: 'document', groups: [ 'mode' ] },
- ];
- options.removeButtons = 'Underline,Subscript,Superscript,PasteFromWord,PasteText,Scayt,Link,Unlink,Anchor,HorizontalRule,Table,Image,Maximize,Source,Format,About,Paste,Cut,Copy';
- } else {
- options.toolbarGroups = [
- { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
- { name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
- { name: 'links', groups: [ 'links' ] },
- { name: 'insert', groups: [ 'insert' ] },
- { name: 'tools', groups: [ 'tools' ] },
- { name: 'document', groups: [ 'mode' ] },
- '/',
- { name: 'styles', groups: [ 'styles' ] },
- { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
- { name: 'colors', groups: [ 'colors' ] },
- { name: 'paragraph', groups: [ 'list', 'indent' ] },
- { name: 'align'},
- { name: 'paragraph', groups: [ 'blocks' ] }
- ];
- }
- return options;
- }
- };
- }
-])
-
-/* Model for a projector.
- *
- * At the moment we use only one projector, so there will be only one object
- * in this model. It has the id 1. For later releases there will be multiple
- * projector objects.
- *
- * This model uses onConfilict: 'replace' instead of 'merge'. This is necessary
- * because the keys of the projector objects can change and old keys have to
- * be removed. See http://www.js-data.io/docs/dsdefaults#onconflict for
- * more information.
- */
-.factory('Projector', [
- 'DS',
- '$http',
- 'EditForm',
- 'Config',
- function(DS, $http, EditForm, Config) {
- return DS.defineResource({
- name: 'core/projector',
- onConflict: 'replace',
- relations: {
- hasMany: {
- 'core/projection-default': {
- localField: 'projectiondefaults',
- foreignKey: 'projector_id',
- }
- },
- },
- methods: {
- controlProjector: function(action, direction) {
- $http.post('/rest/core/projector/' + this.id + '/control_view/',
- {"action": action, "direction": direction}
- );
- },
- getFormOrStateForCurrentSlide: function () {
- var return_dict;
- angular.forEach(this.elements, function(value, key) {
- if (value.name == 'agenda/list-of-speakers') {
- return_dict = {
- state: 'agenda.item.detail',
- id: value.id,
- };
- } else if (
- // TODO:
- // Find generic solution for whitelist in getFormOrStateForCurrentSlide
- // see https://github.com/OpenSlides/OpenSlides/issues/3130
- value.name === 'topics/topic' ||
- value.name === 'motions/motion' ||
- value.name === 'motions/motion-block' ||
- value.name === 'assignments/assignment' ||
- value.name === 'mediafiles/mediafile' ||
- value.name === 'users/user') {
- return_dict = {
- form: EditForm.fromCollectionString(value.name),
- id: value.id,
- };
- }
- });
- return return_dict;
- },
- toggleBlank: function () {
- $http.post('/rest/core/projector/' + this.id + '/control_blank/',
- !this.blank
- );
- },
- toggleBroadcast: function () {
- $http.post('/rest/core/projector/' + this.id + '/broadcast/');
- }
- },
- });
- }
-])
-
-// This factory sends a request to /rest/core/projectors/project
-// with the given data. Also it does the changes done by the server
-// locally and may reverts them, if something went wrong.
-.factory('ProjectHelper', [
- '$q',
- '$http',
- 'Projector',
- function ($q, $http, Projector) {
- var uuid4 = function () {
- function s8() {
- return Math.floor((1 + Math.random()) * 0x100000000)
- .toString(16)
- .substring(1);
- }
- return s8() + s8() + s8() + s8();
- };
-
- return {
- project: function (data) {
- var projector;
- // get all projectors that will be changed.
- var projectorsChanged = _.filter(_.map(data.clear_ids, function (id) {
- return Projector.get(id);
- }));
- if (data.prune && !_.includes(data.clear_ids, data.prune.id)) {
- projector = Projector.get(data.prune.id);
- if (projector) {
- projectorsChanged.push(projector);
- }
- }
-
- // copy original projectors in case we have to reconstruct those
- // _.cloneDeep and angular.clone does not work here; I'm not
- // exactly sure why..
- var originalProjectors = _.map(projectorsChanged, function (projector) {
- var elements = {};
- _.forEach(projector.elements, function (element, key) {
- elements[key] = _.cloneDeep(element);
- });
- return {
- id: projector.id,
- elements: elements,
- scroll: projector.scroll,
- scale: projector.scale,
- name: projector.name,
- blank: projector.blank,
- width: projector.width,
- height: projector.height,
- projectiondefaults: _.cloneDeep(projector.projectiondefaults),
- };
- });
-
- // Clear every projector
- _.forEach(projectorsChanged, function (projector) {
- var elements = {};
- _.forEach(projector.elements, function (element, key) {
- if (element.stable) {
- elements[key] = element;
- }
- });
- projector.elements = elements;
- });
-
- // Add the prune element if given
- if (data.prune) {
- projector = _.find(projectorsChanged, function (projector) {
- return projector.id === data.prune.id;
- });
- if (projector) {
- projector.scroll = 0;
- projector.elements[uuid4()] = data.prune.element;
- }
- }
-
- Projector.inject(projectorsChanged);
-
- return $http.post('/rest/core/projector/project/', data).catch(
- function (error) {
- // revert the changes made earlier
- Projector.inject(originalProjectors);
- return $q.reject(error);
- }
- );
- },
- };
- }
-])
-
-/* Model for all projection defaults */
-.factory('ProjectionDefault', [
- 'DS',
- function(DS) {
- return DS.defineResource({
- name: 'core/projection-default',
- relations: {
- belongsTo: {
- 'core/projector': {
- localField: 'projector',
- localKey: 'projector_id',
- }
- }
- }
- });
- }
-])
-
-/* Model for ProjectorMessages */
-.factory('ProjectorMessage', [
- 'DS',
- 'jsDataModel',
- 'gettext',
- '$http',
- 'Projector',
- function(DS, jsDataModel, gettext, $http, Projector) {
- var name = 'core/projector-message';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Message'),
- verbosenamePlural: gettext('Messages'),
- methods: {
- getResourceName: function () {
- return name;
- },
- // Override the BaseModel.project function
- project: function(projectorId) {
- // if this object is already projected on projectorId, delete this element from this projector
- var isProjectedIds = this.isProjected();
- var self = this;
- var predicate = function (element) {
- return element.name === name && element.id === self.id;
- };
- _.forEach(isProjectedIds, function (id) {
- var uuid = _.findKey(Projector.get(id).elements, predicate);
- $http.post('/rest/core/projector/' + id + '/deactivate_elements/', [uuid]);
- });
- // if it was the same projector before, just delete it but not show again
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- // Now check whether other messages are already projected and delete them
- var elements = Projector.get(projectorId).elements;
- _.forEach(elements, function (element, uuid) {
- if (element.name === name) {
- $http.post('/rest/core/projector/' + projectorId + '/deactivate_elements/', [uuid]);
- }
- });
- return $http.post(
- '/rest/core/projector/' + projectorId + '/activate_elements/',
- [{name: name, id: self.id, stable: true}]
- );
- }
- },
- }
- });
- }
-])
-
-/* Model for Countdowns */
-.factory('Countdown', [
- 'DS',
- 'jsDataModel',
- 'gettext',
- '$rootScope',
- '$http',
- 'Projector',
- function(DS, jsDataModel, gettext, $rootScope, $http, Projector) {
- var name = 'core/countdown';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Countdown'),
- verbosenamePlural: gettext('Countdowns'),
- methods: {
- getResourceName: function () {
- return name;
- },
- start: function () {
- // calculate end point of countdown (in seconds!)
- var endTimestamp = Date.now() / 1000 - $rootScope.serverOffset + this.countdown_time;
- this.running = true;
- this.countdown_time = endTimestamp;
- DS.save(name, this.id);
- },
- stop: function () {
- // calculate rest duration of countdown (in seconds!)
- var newDuration = Math.floor( this.countdown_time - Date.now() / 1000 + $rootScope.serverOffset );
- this.running = false;
- this.countdown_time = newDuration;
- DS.save(name, this.id);
- },
- reset: function () {
- this.running = false;
- this.countdown_time = this.default_time;
- DS.save(name, this.id);
- },
- // Override the BaseModel.project function
- project: function(projectorId) {
- // if this object is already projected on projectorId, delete this element from this projector
- var isProjectedIds = this.isProjected();
- var self = this;
- var predicate = function (element) {
- return element.name == name && element.id == self.id;
- };
- _.forEach(isProjectedIds, function (id) {
- var uuid = _.findKey(Projector.get(id).elements, predicate);
- $http.post('/rest/core/projector/' + id + '/deactivate_elements/', [uuid]);
- });
- // if it was the same projector before, just delete it but not show again
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- return $http.post(
- '/rest/core/projector/' + projectorId + '/activate_elements/',
- [{name: name, id: self.id, stable: true}]
- );
- }
- },
- },
- });
- }
-])
-
-/* Two functions to convert between time duration in seconds <-> human readable time span.
- * E.g. 90 sec <-> 1:30 (min), 3661 sec <-> 1:01:01 (h)
- *
- * secondsToHumanTime: Expects seconds and give [h*:]mm[:ss]. The minutes part is always given, the hours
- * and minutes could be controlled. The default are forced seconds and hours just if it is not 0.
- * - seconds ('enabled', 'auto', 'disabled'): Whether to show seconds (Default 'enabled')
- * - hours ('enabled', 'auto', 'disabled'): Whether to show hours (Default 'auto')
- *
- * humanTimeToSeconds: Expects [h*:]m*[:s*] with each part could have a variable length. The parsed time is
- * in seconds. Minutes have to be given and hours and seconds are optional. One have to set 'seconds' or
- * 'hours' to true toparse these.
- *
- * params could be an object with the given settings, e.g. {ignoreHours: true}
- */
-.factory('HumanTimeConverter', [
- function () {
- return {
- secondsToHumanTime: function (seconds, params) {
- if (!params) {
- params = {seconds: 'enabled', hours: 'auto'};
- }
- if (!params.seconds) {
- params.seconds = 'enabled';
-
- }
- if (!params.hours) {
- params.hours = 'auto';
- }
- var time;
- // floor returns the largest integer of the absolut value of seconds
- var total = Math.floor(Math.abs(seconds));
- var h = Math.floor(total / 3600);
- var m = Math.floor(total % 3600 / 60);
- var s = Math.floor(total % 60);
- // Add leading "0" for double digit values
- time = ('0'+m).slice(-2); //minutes
- if ((params.seconds == 'auto' && s > 0) || params.seconds == 'enabled') {
- s = ('0'+s).slice(-2);
- time = time + ':' + s;
- }
- if ((params.hours == 'auto' && h > 0) || params.hours == 'enabled') {
- time = h + ':' + time;
- }
- if (seconds < 0) {
- time = '-'+time;
- }
- return time;
- },
- humanTimeToSeconds: function (data, params) {
- if (!params) {
- params = {seconds: false, hours: false};
- }
- var minLength = 1;
- if (params.seconds) {
- minLength++;
- }
- if (params.hours){
- minLength++;
- }
-
- var negative = data.charAt(0) == '-';
- var time = data.split(':');
- data = 0;
- if (time.length >= minLength) {
- for (var i = 0; i < minLength; i++) {
- data = data*60;
- if (!isNaN(+time[i])) {
- data += (+time[i]);
- }
- }
- if (!params.seconds) { // the last field was minutes (e.g. h:mm)
- data *= 60;
- }
- if (negative) {
- data = -data;
- }
- }
- return data;
- },
- };
- }
-])
-
-/* Converts a snake-case string to camelCase. Example:
- * 'motion-block-config' -> 'motionBlockConfig' */
-.factory('CamelCase', [
- function () {
- return function (str) {
- return str.replace(/-([a-z])/g, function (match) {
- return match[1].toUpperCase();
- });
- };
- }
-])
-
-/* Return the specific EditForm for a given model. */
-.factory('EditForm', [
- '$injector',
- 'CamelCase',
- function ($injector, CamelCase) {
- return {
- fromCollectionString: function (collection) {
- var modelName = CamelCase(collection).split('/')[1];
- // Convert modelModel to ModelModelForm
- var formName = modelName.charAt(0).toUpperCase() + modelName.slice(1) + 'Form';
- return $injector.get(formName);
- },
- };
- }
-])
-
-/* Converts number of seconds into string "h:mm:ss" or "mm:ss" */
-.filter('osSecondsToTime', [
- 'HumanTimeConverter',
- function (HumanTimeConverter) {
- return function (seconds) {
- return HumanTimeConverter.secondsToHumanTime(seconds);
- };
- }
-])
-
-/* Converts number of minutes into string "h:mm" or "hh:mm" */
-.filter('osMinutesToTime', [
- 'HumanTimeConverter',
- function (HumanTimeConverter) {
- return function (minutes) {
- return HumanTimeConverter.secondsToHumanTime(minutes*60,
- { seconds: 'disabled',
- hours: 'enabled' }
- );
- };
- }
-])
-
-// mark HTML as "trusted"
-.filter('trusted', [
- '$sce',
- function ($sce) {
- return function(text) {
- return $sce.trustAsHtml(text);
- };
- }
-])
-
-// filters the requesting object (id=selfid) from a list of input objects
-.filter('notself', function () {
- return function (input, selfid) {
- var result;
- if (selfid) {
- result = [];
- for (var key in input){
- var obj = input[key];
- if (selfid != obj.id) {
- result.push(obj);
- }
- }
- } else {
- result = input;
- }
- return result;
- };
-})
-
-// Wraps the orderBy filter. But puts ("", null, undefined) last.
-.filter('orderByEmptyLast', [
- '$filter',
- '$parse',
- function ($filter, $parse) {
- return function (array, sortPredicate, reverseOrder, compareFn) {
- var parsed = $parse(sortPredicate);
- var falsyItems = [];
- var truthyItems = _.filter(array, function (item) {
- var falsy = parsed(item) === void 0 || parsed(item) === null || parsed(item) === '';
- if (falsy) {
- falsyItems.push(item);
- }
- return !falsy;
- });
- truthyItems = $filter('orderBy')(truthyItems, sortPredicate, reverseOrder, compareFn);
- return _.concat(truthyItems, falsyItems);
- };
- }
-])
-
-// Make sure that the DS factories are loaded by making them a dependency
-.run([
- 'ChatMessage',
- 'Config',
- 'Countdown',
- 'ProjectorMessage',
- 'Projector',
- 'ProjectionDefault',
- 'Tag',
- 'Notify', // For setting up the autoupdate callback
- function (ChatMessage, Config, Countdown, ProjectorMessage, Projector, ProjectionDefault, Tag, Notify) {}
-]);
-
-}());
diff --git a/openslides/core/static/js/core/csv.js b/openslides/core/static/js/core/csv.js
deleted file mode 100644
index 8361bbf7e..000000000
--- a/openslides/core/static/js/core/csv.js
+++ /dev/null
@@ -1,23 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.core.csv', [])
-
-.factory('CsvDownload', [
- 'Config',
- 'FileSaver',
- function (Config, FileSaver) {
- var utf8_BOM = decodeURIComponent('%EF%BB%BF');
- return function (contentRows, filename) {
- var separator = Config.get('general_csv_separator').value;
- var rows = _.map(contentRows, function (row) {
- return row.join(separator);
- });
- var blob = new Blob([utf8_BOM + rows.join('\n')]);
- FileSaver.saveAs(blob, filename);
- };
- }
-]);
-
-}());
diff --git a/openslides/core/static/js/core/docx.js b/openslides/core/static/js/core/docx.js
deleted file mode 100644
index 21c0d098c..000000000
--- a/openslides/core/static/js/core/docx.js
+++ /dev/null
@@ -1,356 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.core.docx', [])
-
-.factory('Html2DocxConverter', [
- '$q',
- 'ImageConverter',
- function ($q, ImageConverter) {
- var PAGEBREAK = ' ';
-
- var createInstance = function () {
- var converter = {
- imageMap: {},
- documentImages: [],
- relationships: [],
- contentTypes: [],
- };
-
- var html2docx = function (html) {
- var docx = '';
- var tagStack = [];
-
- // With this variable, we keep track, if we are currently inside or outside of a paragraph.
- var inParagraph = true;
- // the text may not begin with a paragraph. If so, append one because word needs it.
- var skipFirstParagraphClosing = true;
-
- var handleTag = function (tag) {
- if (tag.charAt(0) == "/") { // A closing tag
- // remove from stack
- tagStack.pop();
-
- // Special: end paragraphs
- if (tag.indexOf('/p') === 0) {
- docx += '';
- inParagraph = false;
- }
- } else { // now all other tags
- var tagname = tag.split(' ')[0];
- handleNamedTag(tagname, tag);
- }
- return docx;
- };
- var handleNamedTag = function (tagname, fullTag) {
- var tag = {
- tag: tagname,
- attrs: {},
- };
- switch (tagname) {
- case 'p':
- if (inParagraph && !skipFirstParagraphClosing) {
- // End the paragrapth, if there is one
- docx += '';
- }
- skipFirstParagraphClosing = false;
- docx += '';
- inParagraph = true;
- break;
- case 'span':
- var styleRegex = /(?:\"|\;\s?)([a-zA-z\-]+)\:\s?([a-zA-Z0-9\-\#]+)/g, matchSpan;
- while ((matchSpan = styleRegex.exec(fullTag)) !== null) {
- switch (matchSpan[1]) {
- case 'color':
- tag.attrs.color = matchSpan[2].slice(1); // cut off the #
- break;
- case 'background-color':
- tag.attrs.backgroundColor = matchSpan[2].slice(1); // cut off the #
- break;
- case 'text-decoration':
- if (matchSpan[2] === 'underline') {
- tag.attrs.underline = true;
- } else if (matchSpan[2] === 'line-through') {
- tag.attrs.strike = true;
- }
- break;
- }
- }
- break;
- case 'a':
- var hrefRegex = /href="([^"]+)"/g;
- var href = hrefRegex.exec(fullTag)[1];
- tag.href = href;
- break;
- case 'img':
- imageTag(tag, fullTag);
- break;
- }
- if (tagname !== 'img' && tagname !== 'p') {
- tagStack.push(tag);
- }
- };
- var imageTag = function (tag, fullTag) {
- // images has to be placed instantly, so there is no use of 'tag'.
- var image = {};
- var attributeRegex = /(\w+)=\"([^\"]*)\"/g, attributeMatch;
- while ((attributeMatch = attributeRegex.exec(fullTag)) !== null) {
- image[attributeMatch[1]] = attributeMatch[2];
- }
- if (image.src && converter.imageMap[image.src]) {
- image.width = converter.imageMap[image.src].width;
- image.height = converter.imageMap[image.src].height;
-
- var rrId = converter.relationships.length + 1;
- var imageId = converter.documentImages.length + 1;
-
- // set name ('pic.jpg'), title, ext ('jpg'), mime ('image/jpeg')
- image.name = _.last(image.src.split('/'));
-
- var tmp = image.name.split('.');
- image.ext = tmp.splice(-1);
-
- // set name without extension as title if there isn't a title
- if (!image.title) {
- image.title = tmp.join('.');
- }
-
- image.mime = 'image/' + image.ext;
- if (image.ext == 'jpe' || image.ext == 'jpg') {
- image.mime = 'image/jpeg';
- }
-
- // x and y for the container and picture size in EMU (assuming 96dpi)!
- var x = image.width * 914400 / 96;
- var y = image.height * 914400 / 96;
-
- // the image does not belong into a paragraph in ooxml
- if (inParagraph) {
- docx += ' ';
- }
- docx += ' ' +
- '' +
- ' ' +
- '' +
- '' +
- ' ' +
- ' ';
-
- // inParagraph stays untouched, the documents paragraph state is restored here
- if (inParagraph) {
- docx += '';
- }
-
- // entries in documentImages, relationships and contentTypes
- converter.documentImages.push({
- src: image.src,
- zipPath: 'word/media/' + image.name
- });
- converter.relationships.push({
- Id: 'rrId' + rrId,
- Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
- Target: 'media/' + image.name
- });
- converter.contentTypes.push({
- PartName: '/word/media/' + image.name,
- ContentType: image.mime
- });
- }
- };
- var handleText = function (text) {
- // Start a new paragraph, if only loose text is there
- if (!inParagraph) {
- docx += '';
- inParagraph = true;
- }
- var docxPart = '';
- var hyperlink = false;
- tagStack.forEach(function (tag) {
- switch (tag.tag) {
- case 'b':
- case 'strong':
- docxPart += ' ';
- break;
- case 'em':
- case 'i':
- docxPart += ' ';
- break;
- case 'span':
- for (var key in tag.attrs) {
- switch (key) {
- case 'color':
- docxPart += ' ';
- break;
- case 'backgroundColor':
- docxPart += ' ';
- break;
- case 'underline':
- docxPart += ' ';
- break;
- case 'strike':
- docxPart += ' ';
- break;
- }
- }
- break;
- case 'u':
- docxPart += ' ';
- break;
- case 'strike':
- docxPart += ' ';
- break;
- case 'a':
- var id = converter.relationships.length + 1;
- docxPart = '' + docxPart;
- docxPart += ' ';
- converter.relationships.push({
- Id: 'rrId' + id,
- Type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',
- Target: tag.href,
- TargetMode: 'External'
- });
- hyperlink = true;
- break;
- }
- });
- docxPart += ' ' + text + ' ';
- if (hyperlink) {
- docxPart += '';
- }
-
- // append to docx
- docx += docxPart;
- return docx;
- };
-
- var replaceEntities = function () {
- // replacing of special symbols:
- docx = docx.replace(new RegExp('\ä\;', 'g'), 'ä');
- docx = docx.replace(new RegExp('\ü\;', 'g'), 'ü');
- docx = docx.replace(new RegExp('\ö\;', 'g'), 'ö');
- docx = docx.replace(new RegExp('\Ä\;', 'g'), 'Ä');
- docx = docx.replace(new RegExp('\Ü\;', 'g'), 'Ü');
- docx = docx.replace(new RegExp('\Ö\;', 'g'), 'Ö');
- docx = docx.replace(new RegExp('\ß\;', 'g'), 'ß');
- docx = docx.replace(new RegExp('\ \;', 'g'), ' ');
- docx = docx.replace(new RegExp('\§\;', 'g'), '§');
-
- // remove all entities except gt, lt and amp
- var entityRegex = /\&(?!gt|lt|amp)\w+\;/g, matchEntry, indexes = [];
- while ((matchEntry = entityRegex.exec(docx)) !== null) {
- indexes.push({
- startId: matchEntry.index,
- stopId: matchEntry.index + matchEntry[0].length
- });
- }
- for (var i = indexes.length - 1; i>=0; i--) {
- docx = docx.substring(0, indexes[i].startId) + docx.substring(indexes[i].stopId, docx.length);
- }
- };
-
- var parse = function () {
- if (html.substring(0,3) != '') {
- docx += '';
- skipFirstParagraphClosing = false;
- }
- html = html.split(/(<|>)/g);
- // remove whitespaces and > brackets. Leave < brackets in there to check, whether
- // the following string is a tag or text.
- html = _.filter(html, function (part) {
- var skippedCharsRegex = new RegExp('^([\s\n\r]|>)*$', 'g');
- return !skippedCharsRegex.test(part);
- });
-
- for (var i = 0; i < html.length; i++) {
- if (html[i] === '<') {
- i++;
- handleTag(html[i]);
- } else {
- handleText(html[i]);
- }
- }
- // for finishing close the last paragraph (if open)
- if (inParagraph) {
- docx += ' ';
- }
-
- replaceEntities();
-
- return docx;
- };
-
- return parse();
- };
-
- // return a wrapper function for html2docx, that fetches all the images.
- converter.html2docx = function (html) {
- var imageSources = _.map($(html).find('img'), function (element) {
- return element.getAttribute('src');
- });
- // Don't get images multiple times; just if the converter has not seen them befor.
- imageSources = _.filter(imageSources, function (src) {
- return !converter.imageMap[src];
- });
- return $q(function (resolve) {
- ImageConverter.toBase64(imageSources).then(function (_imageMap) {
- _.forEach(_imageMap, function (value, key) {
- converter.imageMap[key] = value;
- });
- var docx = html2docx(html);
- resolve(docx);
- });
- });
- };
-
- converter.updateZipFile = function (zip) {
- var updateRelationships = function (oldContent) {
- var content = oldContent.split('\n');
- _.forEach(converter.relationships, function (relationship) {
- content[1] += ' ';
- });
- return content.join('\n');
- };
- var updateContentTypes = function (oldContent) {
- var content = oldContent.split('\n');
- _.forEach(converter.contentTypes, function (type) {
- content[1] += ' ';
- });
- return content.join('\n');
- };
- // update relationships from 'relationships'
- var relationships = updateRelationships(zip.file('word/_rels/document.xml.rels').asText());
- zip.file('word/_rels/document.xml.rels', relationships);
-
- // update content type from 'contentTypes'
- var contentTypes = updateContentTypes(zip.file('[Content_Types].xml').asText());
- zip.file('[Content_Types].xml', contentTypes);
-
- converter.documentImages = _.uniqBy(converter.documentImages, 'src');
- _.forEach(converter.documentImages, function (image) {
- var dataUrl = converter.imageMap[image.src].data;
- var base64 = dataUrl.split(',')[1];
- zip.file(image.zipPath, base64, {base64: true});
- });
- return zip;
- };
-
- return converter;
- };
-
- return {
- createInstance: createInstance,
- };
- }
-]);
-
-})();
diff --git a/openslides/core/static/js/core/pdf-worker.js b/openslides/core/static/js/core/pdf-worker.js
deleted file mode 100644
index 449645e82..000000000
--- a/openslides/core/static/js/core/pdf-worker.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Worker for creating PDFs in a separate thread. The creation of larger PDFs
- * needs (currently) a lot of time and we don't want to block the UI.
- */
-
-// Setup fake environment for pdfMake
-var document = {
- 'createElementNS': function () {
- return {};
- },
-};
-var window = this;
-
-// PdfMake
-importScripts('/static/js/workers/pdf-worker-libs.js');
-
-// Set default font family.
-// "PdfFont" and "OSFont-*" are generic names used here and in core/pdf.js. The
-// suffix after "OSFont-" has to be the same as the config value.
-pdfMake.fonts = {
- PdfFont: {
- normal: 'OSFont-regular.ttf',
- bold: 'OSFont-bold.ttf',
- italics: 'OSFont-italic.ttf',
- bolditalics: 'OSFont-bold_italic.ttf'
- }
-};
-
-// Function to replace layout placeholder
-//
-// Workaround for using table layout functions.
-// TODO: Needs improvement of pdfmake's web worker support.
-// Currently only functions are allowed for 'layout'.
-// But functions cannot be passed to workers (via JSON).
-var replacePlaceholder = function (content) {
- for (var i = 0; i < content.length; i++) {
- if (typeof content[i] === 'object') {
-
- // motion meta table border lines
- if (content[i].layout === "{{motion-placeholder-to-insert-functions-here}}") {
- content[i].layout = {
- hLineWidth: function(i, node) {
- return (i === 0 || i === node.table.body.length) ? 0 : 0.5;
- },
- vLineWidth: function() {
- return 0;
- },
- hLineColor: function() {
- return 'white';
- }
- };
- return true;
- }
-
- // ballot paper crop marks
- if (content[i].layout === "{{ballot-placeholder-to-insert-functions-here}}") {
- content[i].layout = {
- hLineWidth: function(i, node) {
- if (i === 0){
- return 0;
- } else {
- return 0.5;
- }
- },
- vLineWidth: function(i, node) {
- return (i === 0 || i === node.table.widths.length) ? 0 : 0.5;
- },
- hLineColor: function() {
- return 'gray';
- },
- vLineColor: function() {
- return 'gray';
- }
- };
- return true;
- }
- replacePlaceholder(content[i]);
- }
- }
-};
-
-// Workaround for using dynamic footer with page number.
-// TODO: Needs improvement of pdfmake's web worker support.
-// see https://github.com/bpampuch/pdfmake/issues/38
-var replaceFooter = function (doc) {
- if (doc.footerTpl) {
- doc.footer = function (currentPage, pageCount) {
- // One way to clone arrays/objects in js, that are serilizeable.
- var columns = JSON.parse(JSON.stringify(doc.footerTpl.columns));
- for (var i = 0; i < columns.length; i++) {
- if (columns[i].text) {
- columns[i].text = columns[i].text
- .replace('{{currentPage}}', currentPage)
- .replace('{{pageCount}}', pageCount);
- }
- }
- return {
- columns: columns,
- margin: doc.footerTpl.margin,
- };
- };
- }
-};
-
-// Create PDF on message and return the base64 decoded document
-self.addEventListener('message', function(e) {
- var data = JSON.parse(e.data);
- pdfMake.vfs = data.vfs; // Set custom fonts.
-
- var doc = data.pdfDocument;
- replaceFooter(doc);
- replacePlaceholder(doc.content);
-
- var pdf = pdfMake.createPdf(doc);
- pdf.getBase64(function (base64) {
- if (data.filename) {
- self.postMessage(JSON.stringify({
- filename: data.filename,
- base64: base64
- }));
- } else {
- self.postMessage(base64);
- }
- });
-}, false);
diff --git a/openslides/core/static/js/core/pdf.js b/openslides/core/static/js/core/pdf.js
deleted file mode 100644
index 61ceee2ea..000000000
--- a/openslides/core/static/js/core/pdf.js
+++ /dev/null
@@ -1,1414 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.core.pdf', [])
-
-/*
- * General layout functions for building PDFs with pdfmake.
- */
-.factory('PDFLayout', [
- 'gettextCatalog',
- function(gettextCatalog) {
- var PDFLayout = {};
- var BallotCircleDimensions = {
- yDistance: 6,
- size: 8
- };
-
- // page title
- PDFLayout.createTitle = function(title) {
- return {
- text: title,
- style: 'title'
- };
- };
-
- // page subtitle
- PDFLayout.createSubtitle = function(subtitle) {
- return {
- text: subtitle.join('\n'),
- style: 'subtitle'
- };
- };
-
- // pagebreak
- PDFLayout.addPageBreak = function() {
- return [
- {
- text: '',
- pageBreak: 'after'
- }
- ];
- };
-
- // table row style
- PDFLayout.flipTableRowStyle = function(currentTableSize) {
- if (currentTableSize % 2 === 0) {
- return 'tableEven';
- } else {
- return 'tableOdd';
- }
- };
-
- // draws a circle
- PDFLayout.drawCircle = function(y, size) {
- return [
- {
- type: 'ellipse',
- x: 0,
- y: y,
- lineColor: 'black',
- r1: size,
- r2: size
- }
- ];
- };
-
- // returns an entry in the ballot with a circle to draw into
- PDFLayout.createBallotEntry = function(decision) {
- return {
- margin: [40+BallotCircleDimensions.size, 10, 0, 0],
- columns: [
- {
- width: 15,
- canvas: PDFLayout.drawCircle(BallotCircleDimensions.yDistance,
- BallotCircleDimensions.size)
- },
- {
- width: 'auto',
- text: decision
- }
- ],
- };
- };
-
- // crop marks for ballot papers
- PDFLayout.getBallotLayoutLines = function() {
- return '{{ballot-placeholder-to-insert-functions-here}}';
- };
-
- // returns a promise for converting an image in data URL format with size information
- PDFLayout.imageURLtoBase64 = function(url) {
- var promise = new Promise(function(resolve, reject) {
- var img = new Image();
- img.crossOrigin = 'Anonymous';
- img.onerror = function () {
- reject({
- msg: ' ' +
- gettextCatalog.getString('Error while generating PDF file') +
- ': ' + gettextCatalog.getString('Cannot load image') + ' ' + url + '
',
- });
- };
- img.onload = function () {
- var canvas = document.createElement('canvas');
- canvas.width = img.width;
- canvas.height = img.height;
- var ctx = canvas.getContext('2d');
- ctx.drawImage(img, 0, 0);
- var dataURL = canvas.toDataURL('image/png');
- var imageData = {
- data: dataURL,
- width: img.width,
- height: img.height
- };
- resolve(imageData);
- };
- img.src = url;
- });
- return promise;
- };
-
- return PDFLayout;
- }
-])
-
-
-.factory('HTMLValidizer', function() {
- var HTMLValidizer = {};
-
- // In some cases copying from word to OpenSlides results in umlauts
- // that are the base letter and then the entity #776; to make the dots
- // above the base letter. This breaks the PDF.
- HTMLValidizer.replaceMalformedUmlauts = function (text) {
- return text.replace(/([aeiouAEIOUy])[\u0308]/g, function (match, baseChar) {
- return '&' + baseChar + 'uml;';
- });
- };
-
-
- //checks if str is valid HTML. Returns valid HTML if not,
- //return emptystring if empty
- HTMLValidizer.validize = function(str) {
- if (str) {
- str = HTMLValidizer.replaceMalformedUmlauts(str);
- // Sometimes, some \n are in the text instead of whitespaces. Replace them.
- str = str.replace(/\n/g, ' ');
-
- var a = document.createElement('div');
- a.innerHTML = str;
- angular.forEach(a.childNodes, function (child) {
- if (child.nodeType == 1) {
- return str;
- }
- });
- return '
' + str + '
';
- } else {
- return ''; //needed for blank 'reasons' field
- }
- };
- return HTMLValidizer;
-})
-
-
-.factory('PdfMakeDocumentProvider', [
- '$q',
- 'Config',
- 'PDFLayout',
- 'ImageConverter',
- function($q, Config, PDFLayout, ImageConverter) {
- /**
- * Provides the global document
- * @constructor
- * @param {object} contentProvider - Object with on method `getContent`, which
- * returns an array for content
- */
- //images shall contain the the logos as URL: base64Str, just like the converter
- var createInstance = function(contentProvider, noFooter) {
- // Logo urls
- var logoHeaderLeftUrl = Config.get('logo_pdf_header_L').value.path,
- logoHeaderRightUrl = Config.get('logo_pdf_header_R').value.path,
- logoFooterLeftUrl = Config.get('logo_pdf_footer_L').value.path,
- logoFooterRightUrl = Config.get('logo_pdf_footer_R').value.path;
- var imageMap = contentProvider.getImageMap ? contentProvider.getImageMap() : {};
-
- // PDF header
- var getHeader = function() {
- var columns = [];
-
- if (logoHeaderLeftUrl) {
- if (logoHeaderLeftUrl.indexOf('/') === 0) {
- logoHeaderLeftUrl = logoHeaderLeftUrl.substr(1); // remove trailing /
- }
- columns.push({
- image: logoHeaderLeftUrl,
- fit: [180, 40],
- width: '20%'
- });
- }
-
- var line1 = [
- Config.translate(Config.get('general_event_name').value),
- Config.translate(Config.get('general_event_description').value)
- ].filter(Boolean).join(' – ');
- var line2 = [
- Config.get('general_event_location').value,
- Config.get('general_event_date').value
- ].filter(Boolean).join(', ');
- var text = [line1, line2].join('\n');
- columns.push({
- text: text,
- fontSize: 10,
- alignment: logoHeaderRightUrl ? 'left' : 'right',
- margin: [0, 10, 0, 0],
- });
-
- if (logoHeaderRightUrl) {
- if (logoHeaderRightUrl.indexOf('/') === 0) {
- logoHeaderRightUrl = logoHeaderRightUrl.substr(1); // remove trailing /
- }
- columns.push({
- image: logoHeaderRightUrl,
- fit: [180, 40],
- width: '20%'
- });
- }
-
- return {
- color: '#555',
- fontSize: 9,
- margin: [75, 30, 75, 10], // [left, top, right, bottom]
- columns: columns,
- columnGap: 10,
- };
- };
-
-
- // PDF footer
- // Used placeholder for currentPage and pageCount which
- // are replaced by dynamic footer function in pdf-worker.js.
- var getFooter = function() {
- var columns = [];
-
- // if there is a single logo, give it a lot of space
- var logoContainerWidth;
- var logoConteinerSize;
- if (logoFooterLeftUrl && logoFooterRightUrl) {
- logoContainerWidth = '20%';
- logoConteinerSize = [180, 40];
- } else {
- logoContainerWidth = '80%';
- logoConteinerSize = [400, 50];
- }
-
- // the position of the page number depends on the logos
- var pageNumberPosition;
- if (logoFooterLeftUrl && logoFooterRightUrl) {
- pageNumberPosition = 'center';
- } else if (logoFooterLeftUrl && (!logoFooterRightUrl)) {
- pageNumberPosition = 'right';
- } else if (logoFooterRightUrl && (!logoFooterLeftUrl)) {
- pageNumberPosition = 'left';
- } else {
- pageNumberPosition = Config.get('general_export_pdf_pagenumber_alignment').value;
- }
-
- if (logoFooterLeftUrl) {
- if (logoFooterLeftUrl.indexOf('/') === 0) {
- logoFooterLeftUrl = logoFooterLeftUrl.substr(1); // remove trailing /
- }
- columns.push({
- image: logoFooterLeftUrl,
- fit: logoConteinerSize,
- width: logoContainerWidth,
- alignment: 'left',
- });
- }
- columns.push({
- text: '{{currentPage}} / {{pageCount}}',
- color: '#555',
- fontSize: 9,
- alignment: pageNumberPosition,
- margin: [0, 15, 0, 0],
- });
-
- if (logoFooterRightUrl) {
- if (logoFooterRightUrl.indexOf('/') === 0) {
- logoFooterRightUrl = logoFooterRightUrl.substr(1); // remove trailing /
- }
- columns.push({
- image: logoFooterRightUrl,
- fit: logoConteinerSize,
- width: logoContainerWidth,
- alignment: 'right',
- });
- }
- return {
- margin: [75, 0, 75, 10],
- columns: columns,
- columnGap: 10,
- };
- };
- // Generates the document(definition) for pdfMake
- var getDocument = function() {
- var content = contentProvider.getContent();
- var standardFontsize = Config.get('general_export_pdf_fontsize').value;
- return {
- pageSize: 'A4',
- pageMargins: [75, 90, 75, 75],
- defaultStyle: {
- font: 'PdfFont',
- fontSize: standardFontsize
- },
- header: getHeader(),
- footerTpl: noFooter ? '' : getFooter(),
- content: content,
- styles: {
- title: {
- fontSize: 18,
- margin: [0,0,0,20],
- bold: true
- },
- subtitle: {
- fontSize: 9,
- margin: [0,-20,0,20],
- color: 'grey'
- },
- preamble: {
- fontSize: standardFontsize,
- margin: [0,0,0,10],
- },
- userDataTitle: {
- fontSize: 26,
- margin: [0,0,0,0],
- bold: true
- },
- textItem: {
- fontSize: 11,
- margin: [0,7]
- },
- heading2: {
- fontSize: 14,
- margin: [0,0,0,10],
- bold: true
- },
- heading3: {
- fontSize: 12,
- margin: [0,10,0,0],
- bold: true
- },
- userDataHeading: {
- fontSize: 14,
- margin: [0,10],
- bold: true
- },
- userDataTopic: {
- fontSize: 12,
- margin: [0,5]
- },
- userDataValue: {
- fontSize: 12,
- margin: [15,5]
- },
- tocEntry: {
- fontSize: 12,
- margin: [0,0,0,0],
- bold: false
- },
- tocCategoryEntry: {
- fontSize: 12,
- margin: [10,0,0,0],
- bold: false
- },
- tocCategoryTitle: {
- fontSize: 12,
- margin: [0,0,0,4],
- bold: true,
- },
- tocCategorySection: {
- margin: [0,0,0,10],
- },
- listParent: {
- fontSize: 12,
- margin: [0,5]
- },
- listChild: {
- fontSize: 10,
- margin: [0,5]
- },
- tableHeader: {
- bold: true,
- fillColor: 'white'
- },
- tableEven: {
- fillColor: 'white'
- },
- tableOdd: {
- fillColor: '#eee'
- },
- tableConclude: {
- fillColor: '#ddd',
- bold: true
- },
- grey: {
- fillColor: '#ddd',
- },
- lightgrey: {
- fillColor: '#aaa',
- },
- bold: {
- bold: true,
- },
- small: {
- fontSize: 8,
- }
- }
- };
- };
-
- var getImageMap = function () {
- return imageMap;
- };
-
- return $q(function (resolve, reject) {
- var imageSources = [
- logoHeaderLeftUrl,
- logoHeaderRightUrl,
- logoFooterLeftUrl,
- logoFooterRightUrl,
- ];
- ImageConverter.toBase64(imageSources).then(function (_imageMap) {
- _.forEach(_imageMap, function (data, path) {
- if (!imageMap[path]) {
- imageMap[path] = data;
- }
- });
- resolve({
- getDocument: getDocument,
- getImageMap: getImageMap,
- });
- }, reject);
- });
- };
- return {
- createInstance: createInstance,
- };
- }
-])
-
-.factory('PdfMakeBallotPaperProvider', [
- 'PDFLayout',
- function(PDFLayout) {
- /**
- * Provides the global Document
- * @constructor
- * @param {object} contentProvider - Object with on method `getContent`, which returns an array for content
- */
- var createInstance = function(contentProvider) {
- /**
- * Generates the document(definition) for pdfMake
- * @function
- */
- var getDocument = function() {
- var content = contentProvider.getContent();
- return {
- pageSize: 'A4',
- pageMargins: [0, 0, 0, 0],
- defaultStyle: {
- font: 'PdfFont',
- fontSize: 10
- },
- content: content,
- styles: {
- title: {
- fontSize: 14,
- bold: true,
- margin: [30, 30, 0, 0]
- },
- description: {
- fontSize: 11,
- margin: [30, 0, 0, 0]
- }
- }
- };
- };
-
- var getImageMap = function() {
- return contentProvider.getImageMap();
- };
-
- return {
- getDocument: getDocument,
- getImageMap: getImageMap,
- };
- };
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('PdfMakeConverter', [
- 'HTMLValidizer',
- 'Config',
- function(HTMLValidizer, Config) {
- /**
- * Converter component for HTML->JSON for pdfMake
- * @constructor
- * @param {object} images - Key-Value structure representing image.src/BASE64 of images
- */
- var createInstance = function(images) {
- var slice = Function.prototype.call.bind([].slice),
- map = Function.prototype.call.bind([].map),
-
- DIFF_MODE_NORMAL = 0,
- DIFF_MODE_INSERT = 1,
- DIFF_MODE_DELETE = 2,
-
- // Space between list elements
- LI_MARGIN_BOTTOM = 8,
-
- /**
- * Convertes HTML for use with pdfMake
- * @function
- * @param {object} html - html
- * @param {string} lineNumberMode - [inline, outside, none]
- */
- convertHTML = function(html, lineNumberMode) {
- var elementStyles = {
- 'b': ['font-weight:bold'],
- 'strong': ['font-weight:bold'],
- 'u': ['text-decoration:underline'],
- 'em': ['font-style:italic'],
- 'i': ['font-style:italic'],
- 'h1': ['font-size:14', 'font-weight:bold'],
- 'h2': ['font-size:12', 'font-weight:bold'],
- 'h3': ['font-size:10', 'font-weight:bold'],
- 'h4': ['font-size:10', 'font-style:italic'],
- 'h5': ['font-size:10'],
- 'h6': ['font-size:10'],
- 'a': ['color:blue', 'text-decoration:underline'],
- 'strike': ['text-decoration:line-through'],
- 'del': ['color:red', 'text-decoration:line-through'],
- 'ins': ['color:green', 'text-decoration:underline']
- },
- classStyles = {
- 'delete': ['color:red', 'text-decoration:line-through'],
- 'insert': ['color:green', 'text-decoration:underline']
- },
- getLineNumber = function (element) {
- if (element && element.nodeName == 'SPAN' && element.getAttribute('class') &&
- element.getAttribute('class').indexOf('os-line-number') > -1) {
- return element.getAttribute('data-line-number');
- }
- },
- /**
- *
- * Removes all line number nodes (not line-breaks)
- * and returns an array containing the reoved numbers in this format:
- * { lineNumber: '', marginBottom: }
- * where marginBottom is optional.
- *
- * @function
- * @param {object} element
- */
- extractLineNumbers = function(element) {
- var foundLineNumbers = [];
- var lineNumber = getLineNumber(element);
- if (lineNumber) {
- foundLineNumbers.push({lineNumber: lineNumber});
- element.parentNode.removeChild(element);
- } else if (element.nodeName === 'BR') {
- // Check if there is a new line, but it does not get a line number.
- // If so, insert a dummy line, so the line nubers stays aligned with
- // the text.
- if (!getLineNumber(element.nextSibling)) {
- foundLineNumbers.push({lineNumber: ''});
- }
- } else {
- var children = element.childNodes,
- childrenLength = children.length,
- childrenLineNumbers = [];
- for (var i = 0; i < children.length; i++) {
- childrenLineNumbers = _.concat(childrenLineNumbers, extractLineNumbers(children[i]));
- if (children.length < childrenLength) {
- i -= (childrenLength - children.length);
- childrenLength = children.length;
- }
- }
- // If this is an list item, add some space to the lineNumbers:
- if (childrenLineNumbers.length && element.nodeName === 'LI') {
- _.last(childrenLineNumbers).marginBottom = LI_MARGIN_BOTTOM;
- }
- foundLineNumbers = _.concat(foundLineNumbers, childrenLineNumbers);
- }
- return foundLineNumbers;
- },
- /**
- * Parses Children of the current paragraph
- * @function
- * @param {object} converted -
- * @param {object} element -
- * @param {object} currentParagraph -
- * @param {object} styles -
- * @param {number} diff_mode
- */
- parseChildren = function(converted, element, currentParagraph, styles, diff_mode) {
- var elements = [];
- var children = element.childNodes;
- if (children.length !== 0) {
- _.forEach(children, function(child) {
- currentParagraph = ParseElement(elements, child, currentParagraph, styles, diff_mode);
- });
- }
- if (elements.length !== 0) {
- _.forEach(elements, function(el) {
- converted.push(el);
- });
- }
- return currentParagraph;
- },
- /**
- * Returns the color in a hex format (e.g. #12ff00).
- * Tries to convert the rgb form into this.
- * @function
- * @param {string} color
- */
- parseColor = function (color) {
- var hexRegex = new RegExp('^#([0-9a-f]{3}|[0-9a-f]{6})$');
- // e.g. #fff or #ff0048
- var rgbRegex = new RegExp('^rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)$');
- // e.g. rgb(0,255,34) or rgb(22, 0, 0)
- var nameRegex = new RegExp('^[a-z]+$');
- // matches just text like 'red', 'black', 'green'
-
- if (hexRegex.test(color)) {
- return color;
- } else if (rgbRegex.test(color)) {
- var decimalColors = rgbRegex.exec(color).slice(1);
- for (var i = 0; i < 3; i++) {
- var decimalValue = parseInt(decimalColors[i]);
- if (decimalValue > 255) {
- decimalValue = 255;
- }
- var hexString = '0' + decimalValue.toString(16);
- hexString = hexString.slice(-2);
- decimalColors[i] = hexString;
- }
- return '#' + decimalColors.join('');
- } else if (nameRegex.test(color)) {
- return color;
- } else {
- console.error('Could not parse color "' + color + '"');
- return color;
- }
- },
- /**
- * Extracts the style from an object
- * @function
- * @param {object} o - the current object
- * @param {object} styles - an array with styles
- */
- ComputeStyle = function(o, styles) {
- styles.forEach(function(singleStyle) {
- var styleDefinition = singleStyle.trim().toLowerCase().split(':');
- var style = styleDefinition[0];
- var value = styleDefinition[1];
- if (styleDefinition.length === 2) {
- switch (style) {
- case 'padding-left':
- o.margin = [parseInt(value), 0, 0, 0];
- break;
- case 'font-size':
- o.fontSize = parseInt(value);
- break;
- case 'text-align':
- switch (value) {
- case 'right':
- case 'center':
- case 'justify':
- o.alignment = value;
- break;
- }
- break;
- case 'font-weight':
- switch (value) {
- case 'bold':
- o.bold = true;
- break;
- }
- break;
- case 'text-decoration':
- switch (value) {
- case 'underline':
- o.decoration = 'underline';
- break;
- case 'line-through':
- o.decoration = 'lineThrough';
- break;
- }
- break;
- case 'font-style':
- switch (value) {
- case 'italic':
- o.italics = true;
- break;
- }
- break;
- case 'color':
- o.color = parseColor(value);
- break;
- case 'background-color':
- o.background = parseColor(value);
- break;
- }
- }
- });
- },
- // A little helper function to check, if an element has the given class.
- hasClass = function (element, className) {
- var classes = element.getAttribute('class');
- if (classes) {
- classes = classes.toLowerCase().split(' ');
- return _.indexOf(classes, className) > -1;
- } else {
- return false;
- }
- },
- // Helper function for determinating whether a parent of element is a list item.
- isInsideAList = function (element) {
- var parent = element.parentNode;
- while(parent !== null) {
- if (parent.nodeName.toLowerCase() === 'li') {
- return true;
- }
- parent = parent.parentNode;
- }
- return false;
- },
- /**
- * Parses a single HTML element
- * @function
- * @param {object} alreadyConverted -
- * @param {object} element -
- * @param {object} currentParagraph -
- * @param {object} styles -
- * @param {number} diff_mode
- */
- ParseElement = function(alreadyConverted, element, currentParagraph, styles, diff_mode) {
- styles = styles ? _.clone(styles) : [];
- var classes = [];
- if (element.getAttribute) {
- var nodeStyle = element.getAttribute('style');
- if (nodeStyle) {
- nodeStyle.split(';').forEach(function(nodeStyle) {
- var tmp = nodeStyle.replace(/\s/g, '');
- styles.push(tmp);
- });
- }
- var nodeClass = element.getAttribute('class');
- if (nodeClass) {
- classes = nodeClass.toLowerCase().split(' ');
- classes.forEach(function(nodeClass) {
- if (typeof(classStyles[nodeClass]) != 'undefined') {
- classStyles[nodeClass].forEach(function(style) {
- styles.push(style);
- });
- }
- if (nodeClass == 'insert') {
- diff_mode = DIFF_MODE_INSERT;
- }
- if (nodeClass == 'delete') {
- diff_mode = DIFF_MODE_DELETE;
- }
- });
- }
- }
- var nodeName = element.nodeName.toLowerCase();
- switch (nodeName) {
- case 'h1':
- case 'h2':
- case 'h3':
- case 'h4':
- case 'h5':
- case 'h6':
- if (lineNumberMode === 'outside' &&
- element.childNodes.length > 0 &&
- element.childNodes[0].getAttribute) {
- // A heading may have multiple lines, so handle line by line separated by line number elements
- var outerStack = create('stack');
- var currentCol, currentText;
- _.forEach(element.childNodes, function (node) {
- if (node.getAttribute && node.getAttribute('data-line-number')) {
- if (currentCol) {
- ComputeStyle(currentCol, elementStyles[nodeName]);
- outerStack.stack.push(currentCol);
- }
- currentText = create('text');
- currentCol = {
- columns: [
- getLineNumberObject({
- lineNumber: node.getAttribute('data-line-number')
- }),
- currentText,
- ],
- margin: [0, 2, 0, 0],
- };
- } else {
- var parsedText = ParseElement([], node, create('text'), styles, diff_mode);
- // append the parsed text to the currentText
- _.forEach(parsedText.text, function (text) {
- currentText.text.push(text);
- });
- }
- });
- ComputeStyle(currentCol, elementStyles[nodeName]);
- outerStack.stack.push(currentCol);
- outerStack.margin = [0, 0, 0, 0];
- if (!/h[1-6]/.test(element.previousSibling.nodeName.toLowerCase())) {
- outerStack.margin[1] = 10;
- }
- alreadyConverted.push(outerStack);
- } else {
- currentParagraph = create('text');
- currentParagraph.marginBottom = 4;
- currentParagraph.marginTop = 10;
- currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles.concat(elementStyles[nodeName]), diff_mode);
- alreadyConverted.push(currentParagraph);
- }
- break;
- case 'a':
- case 'b':
- case 'strong':
- case 'u':
- case 'em':
- case 'i':
- case 'ins':
- case 'del':
- case 'strike':
- currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles.concat(elementStyles[nodeName]), diff_mode);
- break;
- case 'table':
- var t = create('table', {
- widths: [],
- body: []
- });
- var border = element.getAttribute('border');
- var isBorder = false;
- if (border) {
- isBorder = (parseInt(border) === 1);
- } else {
- t.layout = 'noBorders';
- }
- currentParagraph = parseChildren(t.table.body, element, currentParagraph, styles, diff_mode);
- var widths = element.getAttribute('widths');
- if (!widths) {
- if (t.table.body.length !== 0) {
- if (t.table.body[0].length !== 0)
- for (var k = 0; k < t.table.body[0].length; k++)
- t.table.widths.push('*');
- }
- } else {
- var w = widths.split(',');
- for (var ko = 0; ko < w.length; ko++) t.table.widths.push(w[ko]);
- }
- alreadyConverted.push(t);
- break;
- case 'tbody':
- currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles, diff_mode);
- break;
- case 'tr':
- var row = [];
- currentParagraph = parseChildren(row, element, currentParagraph, styles, diff_mode);
- alreadyConverted.push(row);
- break;
- case 'td':
- currentParagraph = create('text');
- var st = create('stack');
- st.stack.push(currentParagraph);
- var rspan = element.getAttribute('rowspan');
- if (rspan)
- st.rowSpan = parseInt(rspan);
- var cspan = element.getAttribute('colspan');
- if (cspan)
- st.colSpan = parseInt(cspan);
- currentParagraph = parseChildren(st.stack, element, currentParagraph, styles, diff_mode);
- alreadyConverted.push(st);
- break;
- case 'span':
- if (element.getAttribute('data-line-number')) {
- if (lineNumberMode === 'inline') {
- if (diff_mode !== DIFF_MODE_INSERT) {
- var lineNumberInline = element.getAttribute('data-line-number'),
- lineNumberObjInline = {
- text: lineNumberInline,
- color: 'gray',
- fontSize: 5
- };
- currentParagraph.text.push(lineNumberObjInline);
- }
- } else if (lineNumberMode === 'outside') {
- var lineNumberOutline;
- if (diff_mode === DIFF_MODE_INSERT) {
- lineNumberOutline = '';
- } else {
- lineNumberOutline = element.getAttribute('data-line-number');
- }
- var col = {
- columns: [
- getLineNumberObject({
- lineNumber: lineNumberOutline,
- }),
- ]
- };
- currentParagraph = create('text');
- currentParagraph.lineHeight = 1.25;
- col.columns.push(currentParagraph);
- alreadyConverted.push(col);
- }
- }
- else {
- currentParagraph = parseChildren(alreadyConverted, element, currentParagraph, styles, diff_mode);
- }
- break;
- case 'br':
- var brParent = element.parentNode;
- var brParentNodeName = brParent.nodeName;
- //in case of no or inline-line-numbers and the ignore os-line-breaks.
- if ((lineNumberMode === 'inline' || lineNumberMode === 'none') &&
- hasClass(element, 'os-line-break')) {
- break;
- } else {
- currentParagraph = create('text');
- if (lineNumberMode === 'outside' &&
- brParentNodeName !== 'LI' &&
- element.parentNode.parentNode.nodeName !== 'LI') {
- if (brParentNodeName === 'INS' || brParentNodeName === 'DEL') {
-
- var hasPrevSiblingALineNumber = function (element) {
- // Iterare all nodes up to the top from element.
- while (element) {
- if (getLineNumber(element)) {
- return true;
- }
- if (element.previousSibling) {
- element = element.previousSibling;
- } else {
- element = element.parentNode;
- }
- }
- return false;
- };
- if (hasPrevSiblingALineNumber(brParent)) {
- currentParagraph.margin = [20, 0, 0, 0];
- }
- } else {
- currentParagraph.margin = [20, 0, 0, 0];
- }
- }
- // Add a dummy line, if the next tag is a BR tag again. The line could
- // not be empty otherwise it will be removed and the empty line is not displayed
- if (element.nextSibling && element.nextSibling.nodeName === 'BR') {
- currentParagraph.text.push(create('text', ' '));
- } else if (isInsideAList(element) && lineNumberMode === 'none') {
- // Put a spacer there, if there is one BR in a list
- var spacer = create('text', ' ');
- spacer.lineHeight = 0.25;
- alreadyConverted.push(spacer);
- }
- currentParagraph.lineHeight = 1.25;
- alreadyConverted.push(currentParagraph);
- }
- break;
- case 'li':
- case 'div':
- currentParagraph = create('text');
- currentParagraph.lineHeight = 1.25;
- var stackDiv = create('stack');
- if (_.indexOf(classes, 'os-split-before') > -1) {
- stackDiv.listType = 'none';
- }
- if (nodeName === 'li') {
- stackDiv.marginBottom = LI_MARGIN_BOTTOM;
- }
- stackDiv.stack.push(currentParagraph);
- ComputeStyle(stackDiv, styles);
- currentParagraph = parseChildren(stackDiv.stack, element, currentParagraph, [], diff_mode);
- alreadyConverted.push(stackDiv);
- break;
- case 'p':
- var pObjectToPush; //determine what to push later
- currentParagraph = create('text');
- // If this element is inside a list (happens if copied from word), do not set spaces
- // and margins. Just leave the paragraph there..
- if (!isInsideAList(element)) {
- currentParagraph.margin = [0, 0, 0, 0];
- if (classes.indexOf('os-split-before') === -1) {
- currentParagraph.margin[1] = 8;
- }
- if (classes.indexOf('insert') > -1) {
- currentParagraph.margin[0] = 20;
- }
- }
- currentParagraph.lineHeight = 1.25;
- var stackP = create('stack');
- stackP.stack.push(currentParagraph);
- ComputeStyle(stackP, styles);
- currentParagraph = parseChildren(stackP.stack, element, currentParagraph, [], diff_mode);
- pObjectToPush = stackP; //usually we want to push stackP
- if (lineNumberMode === 'outside') {
- if (element.childNodes.length > 0) { //if we hit = 0, the code would fail
- // add empty line number column for inline diff or pragraph diff mode
- if (element.childNodes[0].tagName === 'INS' ||
- element.childNodes[0].tagName === 'DEL') {
- var pLineNumberPlaceholder = {
- width: 20,
- text: '',
- fontSize: 8,
- margin: [0, 2, 0, 0]
- };
- var pLineNumberPlaceholderCol = {
- columns: [
- pLineNumberPlaceholder,
- stackP
- ]
- };
- pObjectToPush = pLineNumberPlaceholderCol; //overwrite the object to push
- }
- }
- }
- alreadyConverted.push(pObjectToPush);
- break;
- case 'img':
- var path = element.getAttribute('src');
- var height = images[path].height;
- var width = images[path].width;
- var maxWidth = 450;
- var scale = 100;
-
- var style = element.getAttribute('style');
- if (style) {
- var match = style.match(/width:\s*(\d+)\%/);
- if (match) {
- scale = parseInt(match[1]);
- }
- }
-
- // scale image
- width = (width * scale) / 100;
- height = (height * scale) / 100;
-
- if (width > maxWidth) {
- height = (height * maxWidth) / width;
- width = maxWidth;
- }
-
- // remove trailing / for the virtual file system (there is no root)
- if (path.indexOf('/') === 0) {
- path = path.substr(1);
- }
- alreadyConverted.push({
- image: path,
- width: width,
- height: height,
- });
- break;
- case 'ul':
- case 'ol':
- var list = create(nodeName);
- if (nodeName == 'ol') {
- var start = element.getAttribute('start');
- if (start) {
- list.start = start;
- }
- }
- ComputeStyle(list, styles);
- if (lineNumberMode === 'outside') {
- var lines = extractLineNumbers(element);
- currentParagraph = parseChildren(list[nodeName], element, currentParagraph, styles, diff_mode);
- if (lines.length > 0) {
- var listCol = {
- columns: [{
- width: 20,
- stack: []
- }]
- };
- _.forEach(lines, function(line) {
- listCol.columns[0].stack.push(getLineNumberObject(line));
- });
- listCol.columns.push(list);
- if (!hasClass(element, 'os-split-before')) {
- listCol.margin = [0, 5, 0, 0];
- }
- alreadyConverted.push(listCol);
- } else {
- list.margin = [20, 0, 0, 0];
- alreadyConverted.push(list);
- }
- } else {
- list.margin = [0, LI_MARGIN_BOTTOM, 0, 0];
- currentParagraph = parseChildren(list[nodeName], element, currentParagraph, styles, diff_mode);
- alreadyConverted.push(list);
- }
- break;
- default:
- var defaultText = create('text', element.textContent.replace(/\n/g, ''));
- ComputeStyle(defaultText, styles);
- if (!currentParagraph) {
- currentParagraph = {};
- currentParagraph.text = [];
- }
- currentParagraph.text.push(defaultText);
- break;
- }
- return currentParagraph;
- },
- /**
- * Parses HTML
- * @function
- * @param {string} converted -
- * @param {object} htmlText -
- */
- ParseHtml = function(converted, htmlText) {
- var html = HTMLValidizer.validize(htmlText);
- html = $(html.replace(/\t/g, '').replace(/\n/g, ''));
- var emptyParagraph = create('text');
- slice(html).forEach(function(element) {
- ParseElement(converted, element, null, [], DIFF_MODE_NORMAL);
- });
- },
- /* Returns the object to push first into every column, that represents the given line. */
- getLineNumberObject = function (line) {
- var standardFontsize = Config.get('general_export_pdf_fontsize').value;
- return {
- width: 20,
- text: [
- {
- text: ' ', // Add a blank with the normal font size here, so in rare cases the text
- // is rendered on the next page and the linenumber on the previous page.
- fontSize: standardFontsize,
- decoration: '',
- },
- {
- text: line.lineNumber,
- color: 'gray',
- fontSize: standardFontsize - 2,
- decoration: '',
- },
- ],
- marginBottom: line.marginBottom,
- lineHeight: 1.25,
- };
- },
- content = [];
- ParseHtml(content, html);
- return content;
- },
- /**
- * Creates containerelements for pdfMake
- * e.g create('text':'MyText') result in { text: 'MyText' }
- * or complex objects create('stack', [{text:'MyText'}, {text:'MyText2'}])
- *for units / paragraphs of text
- *
- * @function
- * @param {string} name - name of the attribute holding content
- * @param {object} content - the actual content (maybe empty)
- */
- create = function(name, content) {
- var o = {};
- content = content || [];
- o[name] = content;
- return o;
- };
- return {
- convertHTML: convertHTML,
- createElement: create
- };
- };
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('ImageConverter', [
- '$q',
- 'PDFLayout',
- function ($q, PDFLayout) {
- return {
- toBase64: function (imageSources) {
- var imageMap = {};
- var imagePromises = _.map(imageSources, function (imageSource) {
- if (imageSource) {
- return PDFLayout.imageURLtoBase64(imageSource).then(function (imgInfo) {
- imageMap[imageSource] = imgInfo;
- });
- }
- });
-
- return $q(function (resolve, reject) {
- //resolve promises to get base64
- $q.all(imagePromises).then(function() {
- resolve(imageMap);
- }, reject);
- });
- }
- };
- }
-])
-
-// Creates the virtual filesystem for PdfMake.
-.factory('PdfVfs', [
- '$q',
- '$http',
- 'Fonts',
- 'Config',
- function ($q, $http, Fonts, Config) {
- var urlCache = {}; // Caches the get request. Maps urls to base64 data ready to use.
-
- var loadFont = function (url) {
- return $q(function (resolve, reject) {
- // Get font
- return $http.get(url, {responseType: 'blob'}).then(function (success) {
- // Convert to base64
- var reader = new FileReader();
- reader.readAsDataURL(success.data);
- reader.onloadend = function() {
- resolve(reader.result.split(',')[1]);
- };
- }, function (error) {
- reject(error);
- });
- });
- };
-
- /*
- * Returns a map from urls to arrays of font types used by PdfMake.
- * E.g. if the font 'regular' and 'bold' have the urls 'fonts/myFont.ttf',
- * the map fould be 'fonts/myFont.ttf': ['OSFont-regular.ttf', 'OSFont-bold.ttf']
- */
- var getUrlMapping = function () {
- var urlMap = {};
- var fonts = ['regular', 'italic', 'bold', 'bold_italic'];
- _.forEach(fonts, function (font) {
- var url = Fonts.getUrl('font_' + font);
- if (!urlMap[url]) {
- urlMap[url] = [];
- }
- urlMap[url].push('OSFont-' + font + '.ttf');
- });
- return urlMap;
- };
-
- /*
- * Create the virtual filesystem needed by PdfMake for the fonts. Gets the url
- * mapping and loads all fonts via get requests or the urlCache.
- * Adds all image sources to the vfs given by the imageMap.
- */
- var getVfs = function (imageMap) {
- var vfs = {};
- _.forEach(imageMap || {}, function (data, path) {
- if (path.indexOf('/') === 0) {
- path = path.substr(1); // remove trailing /
- }
- vfs[path] = data.data.split(',')[1];
- });
- return $q(function (resolve, reject) {
- var urls = getUrlMapping();
- var promises = _.chain(urls)
- .map(function (filenames, url) {
- if (urlCache[url]) {
- // Just save the cache data into vfs.
- _.forEach(filenames, function (filename) {
- vfs[filename] = urlCache[url];
- });
- return false; // No promise here, it was all cached.
- } else {
- // Not in the cache, get the font and save the data into vfs.
- return loadFont(url).then(function (data) {
- urlCache[url] = data;
- _.forEach(filenames, function (filename) {
- vfs[filename] = data;
- });
- });
- }
- })
- .filter(function (promise) {
- return promise;
- })
- .value();
- $q.all(promises).then(function () {
- resolve(vfs);
- });
- });
- };
-
- return {
- get: getVfs,
- };
- }
-])
-
-.factory('PdfCreate', [
- '$timeout',
- '$q',
- 'gettextCatalog',
- 'FileSaver',
- 'PdfVfs',
- 'Messaging',
- function ($timeout, $q, gettextCatalog, FileSaver, PdfVfs, Messaging) {
- var filenameMessageMap = {};
- var b64toBlob = function(b64Data) {
- var byteCharacters = atob(b64Data);
- var byteNumbers = new Array(byteCharacters.length);
- for (var i = 0; i < byteCharacters.length; i++) {
- byteNumbers[i] = byteCharacters.charCodeAt(i);
- }
- var byteArray = new Uint8Array(byteNumbers);
- var blob = new Blob([byteArray]);
- return blob;
- };
- var stateChange = function (state, filename, error) {
- var text, timeout;
- switch (state) {
- case 'info':
- text = ' ' +
- gettextCatalog.getString('Generating PDF file') + ' (' + filename + ') ...';
- break;
- case 'success':
- text = ' ' +
- gettextCatalog.getString('PDF successfully generated.');
- timeout = 3000;
- break;
- case 'error':
- text = ' ' +
- gettextCatalog.getString('Error while generating PDF file') +
- ' (' + filename + '): ' + error + '
';
- break;
- }
- $timeout(function () {
- filenameMessageMap[filename] = Messaging.createOrEditMessage(
- filenameMessageMap[filename], text, state, {timeout: timeout});
- }, 1);
- };
- return {
- getBase64FromDocument: function (documentProvider) {
- return $q(function (resolve, reject) {
- PdfVfs.get(documentProvider.getImageMap()).then(function (vfs) {
- var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
- pdfWorker.addEventListener('message', function (event) {
- resolve(event.data);
- });
- pdfWorker.addEventListener('error', function (event) {
- reject(event);
- });
- pdfWorker.postMessage(JSON.stringify({
- pdfDocument: documentProvider.getDocument(),
- vfs: vfs,
- }));
- });
- });
- },
- // Struckture of pdfDocuments: { filname1: doc, filename2: doc, ...}
- getBase64FromMultipleDocuments: function (pdfDocuments) {
- // concat all image sources together
- var imageMap = {};
- _.forEach(pdfDocuments, function (doc) {
- _.forEach(doc.getImageMap(), function (data, path) {
- if (!imageMap[path]) {
- imageMap[path] = data;
- }
- });
- });
- return $q(function (resolve, reject) {
- PdfVfs.get(imageMap).then(function (vfs) {
- var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
- var resultCount = 0;
- var base64Map = {}; // Maps filename to base64
- pdfWorker.addEventListener('message', function (event) {
- resultCount++;
- var data = JSON.parse(event.data);
- base64Map[data.filename] = data.base64;
- if (resultCount === _.keys(pdfDocuments).length) {
- resolve(base64Map);
- }
- });
- pdfWorker.addEventListener('error', function (event) {
- reject(event);
- });
- _.forEach(pdfDocuments, function (doc, filename) {
- pdfWorker.postMessage(JSON.stringify({
- filename: filename,
- pdfDocument: doc.getDocument(),
- vfs: vfs,
- }));
- });
- });
- });
- },
- download: function (documentProvider, filename) {
- stateChange('info', filename);
-
- this.getBase64FromDocument(documentProvider).then(function (data) {
- var blob = b64toBlob(data);
- stateChange('success', filename);
- FileSaver.saveAs(blob, filename);
- }, function (error) {
- stateChange('error', filename, error.message);
- });
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/core/static/js/core/projector.js b/openslides/core/static/js/core/projector.js
deleted file mode 100644
index 4dd98042b..000000000
--- a/openslides/core/static/js/core/projector.js
+++ /dev/null
@@ -1,409 +0,0 @@
-(function () {
-
-'use strict';
-
-// The core module for the OpenSlides projector
-angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
-
-// Can be used to find out if the projector or the side is used
-.constant('REALM', 'projector')
-
-.run([
- '$http',
- 'autoupdate',
- 'DS',
- function ($http, autoupdate, DS) {
- autoupdate.newConnect();
-
- // If the connection aborts, we try to ping the server with whoami requests. If
- // the server is flushed, we clear the datastore, so the message 'this projector
- // cannot be shown' will be displayed. Otherwise establish the websocket connection.
- autoupdate.registerRetryConnectCallback(function () {
- return $http.get('/users/whoami').then(function (success) {
- if (success.data.user_id === null && !success.data.guest_enabled) {
- DS.clear();
- } else {
- autoupdate.newConnect();
- }
- });
- });
- }
-])
-
-// Provider to register slides in a .config() statement.
-.provider('slides', [
- function() {
- var slidesMap = {};
-
- this.registerSlide = function(name, config) {
- slidesMap[name] = config;
- return this;
- };
-
- this.$get = function($templateRequest, $q) {
- var self = this;
- return {
- getElements: function(projector) {
- var elements = [];
- var factory = this;
- _.forEach(projector.elements, function(element) {
- if (element.name in slidesMap) {
- element.template = slidesMap[element.name].template;
- elements.push(element);
- } else {
- console.error("Unknown slide: " + element.name);
- }
- });
- return elements;
- }
- };
- };
- }
-])
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('core/clock', {
- template: 'static/templates/core/slide_clock.html',
- });
-
- slidesProvider.registerSlide('core/countdown', {
- template: 'static/templates/core/slide_countdown.html',
- });
-
- slidesProvider.registerSlide('core/projector-message', {
- template: 'static/templates/core/slide_message.html',
- });
- }
-])
-
-.controller('LanguageAndFontCtrl', [
- '$scope',
- 'Languages',
- 'Config',
- 'Projector',
- 'ProjectorID',
- 'Fonts',
- function ($scope, Languages, Config, Projector, ProjectorID, Fonts) {
- // for the dynamic title
- $scope.projectorId = ProjectorID();
- $scope.$watch(function () {
- return Projector.lastModified($scope.projectorId);
- }, function () {
- var projector = Projector.get($scope.projectorId);
- if (projector) {
- $scope.projectorName = projector.name;
- }
- });
-
- $scope.$watch(function () {
- return Config.lastModified('projector_language');
- }, function () {
- var lang = Config.get('projector_language');
- if (!lang || lang.value == 'browser') {
- $scope.selectedLanguage = Languages.getBrowserLanguage();
- } else {
- $scope.selectedLanguage = lang.value;
- }
- Languages.setCurrentLanguage($scope.selectedLanguage);
- });
-
- $scope.$watch(function () {
- return Config.lastModified('font_regular') +
- Config.lastModified('font_italic') +
- Config.lastModified('font_bold') +
- Config.lastModified('font_bold_italic');
- }, function () {
- $scope.font = Fonts.getForCss('font_regular');
- $scope.font_medium = Fonts.getForCss('font_italic');
- $scope.font_condensed = Fonts.getForCss('font_bold');
- $scope.font_condensed_light = Fonts.getForCss('font_bold_italic');
- });
- }
-])
-
-// Projector Container Controller
-.controller('ProjectorContainerCtrl', [
- '$scope',
- '$timeout',
- '$location',
- 'gettext',
- 'Projector',
- function($scope, $timeout, $location, gettext, Projector) {
- $scope.showError = true;
-
- // watch for changes in Projector
- $scope.$watch(function () {
- return Projector.lastModified($scope.projectorId);
- }, function () {
- var projector = Projector.get($scope.projectorId);
- if (projector) {
- $scope.showError = false;
- $scope.projectorWidth = projector.width;
- $scope.projectorHeight = projector.height;
- $scope.recalculateIframe();
- } else {
- $scope.showError = true;
- // delay displaying the error message, because with a slow internet
- // connection, the autoupdate with the projector may be delayed. We
- // de not want to irritate the user by showing this error to early.
- $scope.error = '';
- $timeout(function () {
- if ($scope.showError) {
- $scope.error = gettext('Can not open the projector.');
- }
- }, 3000);
- }
- });
-
- // recalculate the actual Iframesize and scale
- $scope.recalculateIframe = function () {
- var scale_width = window.innerWidth / $scope.projectorWidth;
- var scale_height = window.innerHeight / $scope.projectorHeight;
-
- // Iframe has to be scaled down or saceUp is activated
- if (scale_width <= scale_height) {
- // width is the reference
- $scope.iframeWidth = window.innerWidth;
- $scope.scale = scale_width;
- $scope.iframeHeight = $scope.projectorHeight * scale_width;
- } else {
- // height is the reference
- $scope.iframeHeight = window.innerHeight;
- $scope.scale = scale_height;
- $scope.iframeWidth = $scope.projectorWidth * scale_height;
- }
- };
-
- // watch for changes in the windowsize
- $(window).on("resize.doResize", function () {
- $scope.$apply(function() {
- $scope.recalculateIframe();
- });
- });
-
- $scope.$on("$destroy",function (){
- $(window).off("resize.doResize");
- });
- }
-])
-
-.controller('ProjectorCtrl', [
- '$scope',
- '$location',
- '$timeout',
- 'Projector',
- 'slides',
- 'Config',
- 'ProjectorID',
- 'Logos',
- function($scope, $location, $timeout, Projector, slides, Config, ProjectorID, Logos) {
- var projectorId = ProjectorID();
-
- $scope.broadcast = 0;
-
- var setElements = function (projector) {
- // Get all elements, that should be projected.
- var newElements = [];
- var enable_clock = Config.get('projector_enable_clock');
- enable_clock = enable_clock ? enable_clock.value : true;
- _.forEach(slides.getElements(projector), function (element) {
- if (!element.error) {
- // Exclude the clock if it should be disabled.
- if (enable_clock || element.name !== 'core/clock') {
- newElements.push(element);
- }
- } else {
- console.error("Error for slide " + element.name + ": " + element.error);
- }
- });
-
- // Now we have to align $scope.elements to newElements:
- // We cannot just assign them, because the ng-repeat would reload every
- // element. This should be prevented (see #3259). To change $scope.elements:
- // 1) remove all elements from scope, that are not in newElements (compared by the uuid)
- // 2) Every new element in newElements, that is not in $scope.elements, get inserted there.
- // 3) If there is the same element in newElements and $scope.elements every changed property
- // is copied from the new element to the scope element.
-
- $scope.elements = _.filter($scope.elements, function (element) {
- return _.some(newElements, function (newElement) {
- return element.uuid === newElement.uuid;
- });
- });
-
- _.forEach(newElements, function (newElement) {
- var matchingElement = _.find($scope.elements, function (element) {
- return element.uuid === newElement.uuid;
- });
- if (matchingElement) {
- // copy all changed properties.
- _.forEach(newElement, function (value, key) {
- // key has own property and does not start with a '$'.
- if (newElement.hasOwnProperty(key) && key.indexOf('$') != 0) {
- if (typeof matchingElement[key] === 'undefined' || matchingElement[key] !== value) {
- matchingElement[key] = value;
- }
- }
- });
- } else {
- $scope.elements.push(newElement);
- }
- });
- };
-
- $scope.scroll = 0;
- var setScroll = function (scroll) {
- $scope.scroll = -250 * scroll;
- };
-
- $scope.$watch(function () {
- return Projector.lastModified(projectorId);
- }, function () {
- $scope.projector = Projector.get(projectorId);
- if ($scope.projector) {
- if ($scope.broadcast === 0) {
- setElements($scope.projector);
- $scope.blank = $scope.projector.blank;
- }
- setScroll($scope.projector.scroll);
- } else {
- // Blank projector on error
- $scope.elements = [];
- $scope.projector = {
- scale: 0,
- blank: true
- };
- setScroll(0);
- }
- });
-
- $scope.$watch(function () {
- return Config.lastModified('projector_broadcast');
- }, function () {
- var bc = Config.get('projector_broadcast');
- if (bc) {
- if ($scope.broadcast != bc.value) {
- $scope.broadcast = bc.value;
- if ($scope.broadcastDeregister) {
- // revert to original $scope.projector
- $scope.broadcastDeregister();
- $scope.broadcastDeregister = null;
- setElements($scope.projector);
- $scope.blank = $scope.projector.blank;
- }
- }
- if ($scope.broadcast > 0) {
- // get elements and blank from broadcast projector
- $scope.broadcastDeregister = $scope.$watch(function () {
- return Projector.lastModified($scope.broadcast);
- }, function () {
- if ($scope.broadcast > 0) {
- var broadcast_projector = Projector.get($scope.broadcast);
- if (broadcast_projector) {
- setElements(broadcast_projector);
- $scope.blank = broadcast_projector.blank;
- }
- }
- });
- }
- }
- });
-
- $scope.$watch(function () {
- return Config.lastModified('projector_enable_clock');
- }, function () {
- setElements($scope.projector);
- });
-
- $scope.$on('$destroy', function() {
- if ($scope.broadcastDeregister) {
- $scope.broadcastDeregister();
- $scope.broadcastDeregister = null;
- }
- });
- }
-])
-
-.controller('SlideClockCtrl', [
- '$scope',
- '$interval',
- function($scope, $interval) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
- var interval = $interval(function () {
- $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
- }, 30000); // Update the clock every 30 seconds
-
- $scope.$on('$destroy', function() {
- if (interval) {
- $interval.cancel(interval);
- }
- });
- }
-])
-
-.controller('SlideCountdownCtrl', [
- '$scope',
- '$interval',
- 'Countdown',
- function($scope, $interval, Countdown) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- var interval;
- var calculateCountdownTime = function (countdown) {
- countdown.seconds = Math.floor( $scope.countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
- };
- $scope.$watch(function () {
- return Countdown.lastModified(id);
- }, function () {
- $scope.countdown = Countdown.get(id);
- if (interval) {
- $interval.cancel(interval);
- }
- if ($scope.countdown) {
- if ($scope.countdown.running) {
- calculateCountdownTime($scope.countdown);
- interval = $interval(function () { calculateCountdownTime($scope.countdown); }, 1000);
- } else {
- $scope.countdown.seconds = $scope.countdown.countdown_time;
- }
- }
- });
- $scope.$on('$destroy', function() {
- // Cancel the interval if the controller is destroyed
- if (interval) {
- $interval.cancel(interval);
- }
- });
- }
-])
-
-.controller('SlideMessageCtrl', [
- '$scope',
- 'ProjectorMessage',
- 'Projector',
- 'ProjectorID',
- 'gettextCatalog',
- function($scope, ProjectorMessage, Projector, ProjectorID, gettextCatalog) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
-
- if ($scope.element.identify) {
- var projector = Projector.get(ProjectorID());
- $scope.identifyMessage = gettextCatalog.getString('Projector') + ' ' + projector.id + ': ' + gettextCatalog.getString(projector.name);
- } else {
- $scope.message = ProjectorMessage.get(id);
- ProjectorMessage.bindOne(id, $scope, 'message');
- }
- }
-]);
-
-}());
diff --git a/openslides/core/static/js/core/remove-format-plugin.js b/openslides/core/static/js/core/remove-format-plugin.js
deleted file mode 100644
index 046dce06c..000000000
--- a/openslides/core/static/js/core/remove-format-plugin.js
+++ /dev/null
@@ -1,50 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.core.remove-format-plugin', [
- 'OpenSlidesApp.core',
-])
-
-/*
- * Plugin for the CKEditor that hooks into the removeformat plugin
- * which is a default plugin enabled by 'cleanup' in the config
- * toolbar.
- * We change the behavior of the removeformat command here:
- * It should not remove any tags and styles, but only the
- * 'DISALLOWED_STYLES'. Removeformat traverses through the DOM
- * and calles for every element the custom filter down below.
- * We change the element and return false, so the removeformat
- * plugin does not clean it up.
- */
-.factory('OSRemoveFormatPlugin', [
- 'Editor',
- 'gettextCatalog',
- function (Editor, gettextCatalog) {
- var DISALLOWED_STYLES = ['color', 'background-color'];
- return {
- getPlugin: function () {
- return {
- init: function (editor) {
- editor.addRemoveFormatFilter(function (element) {
- _.forEach(DISALLOWED_STYLES, function (style) {
- element.removeStyle(style);
- });
- return false;
- });
- },
- };
- },
- };
- }
-])
-
-.run([
- 'Editor',
- 'OSRemoveFormatPlugin',
- function (Editor, OSRemoveFormatPlugin, gettext) {
- Editor.registerPlugin('OSRemoveFormat', OSRemoveFormatPlugin.getPlugin());
- }
-]);
-
-}());
diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js
deleted file mode 100644
index 4059a376a..000000000
--- a/openslides/core/static/js/core/site.js
+++ /dev/null
@@ -1,2135 +0,0 @@
-(function () {
-
-'use strict';
-
-// The core module for the OpenSlides site
-angular.module('OpenSlidesApp.core.site', [
- 'OpenSlidesApp.core',
- 'OpenSlidesApp.core.start',
- 'OpenSlidesApp.core.csv',
- 'OpenSlidesApp.core.remove-format-plugin',
- 'OpenSlidesApp.poll.majority',
- 'ui.router',
- 'colorpicker.module',
- 'formly',
- 'formlyBootstrap',
- 'localytics.directives',
- 'ngDialog',
- 'ngFileSaver',
- 'ngMessages',
- 'ckeditor',
- 'luegg.directives',
- 'xeditable',
- 'rzModule',
-])
-
-// Can be used to find out if the projector or the side is used
-.constant('REALM', 'site')
-
-.factory('DateTimePickerTranslation', [
- 'gettextCatalog',
- function (gettextCatalog) {
- return {
- getButtons: function () {
- return {
- show: true,
- now: {
- show: true,
- text: gettextCatalog.getString('now')
- },
- today: {
- show: true,
- text: gettextCatalog.getString('today')
- },
- clear: {
- show: true,
- text: gettextCatalog.getString('clear')
- },
- date: {
- show: true,
- text: gettextCatalog.getString('date')
- },
- time: {
- show: true,
- text: gettextCatalog.getString('time')
- },
- close: {
- show: true,
- text: gettextCatalog.getString('close')
- }
- };
- }
- };
- }
-
-])
-
-// Provider to register entries for the main menu.
-.provider('mainMenu', [
- function() {
- var mainMenuList = [];
- var scope;
-
- this.register = function(config) {
- mainMenuList.push(config);
- };
-
- this.$get = ['operator', function(operator) {
- return {
- registerScope: function (scope) {
- this.scope = scope;
- },
- updateMainMenu: function () {
- if (this.scope) {
- this.scope.elements = this.getElements();
- }
- },
- getElements: function() {
- var elements = mainMenuList.filter(function (element) {
- return typeof element.perm === "undefined" || operator.hasPerms(element.perm);
- });
-
- elements.sort(function (a, b) {
- return a.weight - b.weight;
- });
- return elements;
- }
- };
- }];
- }
-])
-
-// Provider to register a searchable module/app.
-.provider('Search', [
- function() {
- var searchModules = [];
-
- this.register = function(module) {
- searchModules.push(module);
- };
-
- this.$get = [
- function () {
- return {
- getAll: function () {
- return searchModules;
- }
- };
- }
- ];
- }
-])
-
-.run([
- 'editableOptions',
- 'gettext',
- function (editableOptions, gettext) {
- editableOptions.theme = 'bs3';
- editableOptions.cancelButtonAriaLabel = gettext('Cancel');
- editableOptions.cancelButtonTitle = gettext('Cancel');
- editableOptions.clearButtonAriaLabel = gettext('Clear');
- editableOptions.clearButtonTitle = gettext('Clear');
- editableOptions.submitButtonAriaLabel = gettext('Submit');
- editableOptions.submitButtonTitle = gettext('Submit');
- }
-])
-
-.factory('WebpageTitle', [
- '$rootScope',
- function ($rootScope) {
- $rootScope.activeAppTitle = '';
- return {
- updateTitle: function (text) {
- $rootScope.activeAppTitle = text || '';
- },
- };
- }
-])
-
-// Watch for the basePerm on a stateChange and initialize the WebpageTitle factory
-.run([
- '$rootScope',
- 'operator',
- 'WebpageTitle',
- function ($rootScope, operator, WebpageTitle) {
- $rootScope.$on('$stateChangeSuccess', function(event, toState) {
- WebpageTitle.updateTitle(toState.data ? toState.data.title : '');
- if (toState.data) {
- $rootScope.baseViewPermissionsGranted = toState.data.basePerm ?
- operator.hasPerms(toState.data.basePerm) : true;
- } else {
- $rootScope.baseViewPermissionsGranted = true;
- }
- // Scroll to top on every state change
- $rootScope.gotoTop();
- });
- }
-])
-
-// Make the main content expandable
-.run([
- '$rootScope',
- function ($rootScope) {
- $rootScope.$on('$stateChangeSuccess', function() {
- $rootScope.expandContent = false;
- });
- $rootScope.toggleExpandContent = function () {
- $rootScope.expandContent = !$rootScope.expandContent;
- };
- }
-])
-
-.config([
- 'mainMenuProvider',
- 'gettext',
- function (mainMenuProvider, gettext) {
- mainMenuProvider.register({
- 'ui_sref': 'home',
- 'img_class': 'home',
- 'title': gettext('Home'),
- 'weight': 100,
- 'perm': 'core.can_see_frontpage',
- });
-
- mainMenuProvider.register({
- 'ui_sref': 'config',
- 'img_class': 'cog',
- 'title': gettext('Settings'),
- 'weight': 1000,
- 'perm': 'core.can_manage_config',
- });
- }
-])
-
-.config([
- '$urlRouterProvider',
- '$locationProvider',
- function($urlRouterProvider, $locationProvider) {
- // define fallback url and html5Mode
- $urlRouterProvider.otherwise('/');
- $locationProvider.html5Mode(true);
- }
-])
-
-.config([
- '$httpProvider',
- function($httpProvider) {
- // Combine the django csrf system with the angular csrf system
- $httpProvider.defaults.xsrfCookieName = 'OpenSlidesCsrfToken';
- $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
- }
-])
-
-
-.config([
- '$stateProvider',
- '$urlMatcherFactoryProvider',
- function($stateProvider, $urlMatcherFactoryProvider) {
- // Make the trailing slash optional
- $urlMatcherFactoryProvider.strictMode(false);
-
- // Use stateProvider.decorator to give default values to our states
- $stateProvider.decorator('views', function(state, parent) {
- var result = {},
- views = parent(state);
-
- if (state.abstract || state.data && state.data.extern) {
- return views;
- }
-
- angular.forEach(views, function(config, name) {
- // Sets additional default values for templateUrl
- var templateUrl,
- controller,
- defaultControllers = {
- create: 'CreateCtrl',
- update: 'UpdateCtrl',
- list: 'ListCtrl',
- detail: 'DetailCtrl',
- };
-
- // Split up state name
- // example: "motions.motion.detail.update" -> ['motions', 'motion', 'detail', 'update']
- var patterns = state.name.split('.');
-
- // set app and module name from state
- // - appName: patterns[0] (e.g. "motions")
- // - moduleNames: patterns without first element (e.g. ["motion", "detail", "update"])
- var appName = '';
- var moduleName = '';
- var moduleNames = [];
- if (patterns.length > 0) {
- appName = patterns[0];
- moduleNames = patterns.slice(1);
- }
- if (moduleNames.length > 0) {
- // convert from camcelcase to dash notation
- // example: ["motionBlock", "detail"] -> ["motion-block", "detail"]
- for (var i = 0; i < moduleNames.length; i++) {
- moduleNames[i] = moduleNames[i].replace(/([a-z\d])([A-Z])/g, '$1-$2').toLowerCase();
- }
-
- // use special templateUrl for create and update view
- // example: ["motion", "detail", "update"] -> "motion-form"
- if (_.last(moduleNames).match(/(create|update)/)) {
- moduleName = '/' + moduleNames[0] + '-form';
- } else {
- // convert modelNames array to url string
- // example: ["motion-block", "detail"] -> "motion-block-detail"
- moduleName = '/' + moduleNames.join('-');
- }
- }
- templateUrl = 'static/templates/' + appName + moduleName + '.html';
- config.templateUrl = state.templateUrl || templateUrl;
-
- // controller
- if (patterns.length >= 3) {
- controller = _.upperFirst(patterns[1]) + defaultControllers[_.last(patterns)];
- config.controller = state.controller || controller;
- }
- result[name] = config;
- });
- return result;
- })
-
- .decorator('url', function(state, parent) {
- var defaultUrl;
-
- if (state.abstract) {
- defaultUrl = '';
- } else {
- var patterns = state.name.split('.'),
- defaultUrls = {
- create: '/new',
- update: '/edit',
- list: '',
- // The id is expected to be an integer, if not, the url has to
- // be defined manually
- detail: '/{id:int}',
- };
-
- defaultUrl = defaultUrls[_.last(patterns)];
- }
-
- state.url = state.url || defaultUrl;
- return parent(state);
- });
- }
-])
-
-.config([
- '$stateProvider',
- '$locationProvider',
- 'gettext',
- function($stateProvider, $locationProvider, gettext) {
- // Core urls
- $stateProvider
- .state('home', {
- url: '/',
- templateUrl: 'static/templates/home.html',
- data: {
- title: gettext('Home'),
- basePerm: 'core.can_see_frontpage',
- },
- })
- .state('projector', {
- url: '/projector/{id:int}/',
- templateUrl: 'static/templates/projector-container.html',
- data: {extern: true},
- onEnter: function($window) {
- $window.location.href = this.url;
- }
- })
- .state('real-projector', {
- url: '/real-projector/{id:int}/',
- templateUrl: 'static/templates/projector.html',
- data: {extern: true},
- onEnter: function($window) {
- $window.location.href = this.url;
- }
- })
- .state('manage-projectors', {
- url: '/manage-projectors',
- templateUrl: 'static/templates/core/manage-projectors.html',
- controller: 'ManageProjectorsCtrl',
- data: {
- title: gettext('Manage projectors'),
- basePerm: 'core.can_manage_projector',
- },
- })
- .state('core', {
- url: '/core',
- abstract: true,
- template: " ",
- })
-
- // legal notice and version
- .state('legalnotice', {
- url: '/legalnotice',
- controller: 'LegalNoticeCtrl',
- data: {
- title: gettext('Legal notice'),
- },
- })
-
- // privacy policy
- .state('privacypolicy', {
- url: '/privacypolicy',
- controller: 'PrivacyPolicyCtrl',
- data: {
- title: gettext('Privacy policy'),
- },
- })
-
- //config
- .state('config', {
- url: '/config',
- controller: 'ConfigCtrl',
- data: {
- title: gettext('Settings'),
- basePerm: 'core.can_manage_config',
- },
- })
-
- // search
- .state('search', {
- url: '/search?q',
- controller: 'SearchCtrl',
- templateUrl: 'static/templates/search.html',
- data: {
- title: gettext('Search'),
- },
- })
-
- // tag
- .state('core.tag', {
- url: '/tag',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Tags'),
- basePerm: 'core.can_manage_tags',
- },
- })
- .state('core.tag.list', {})
-
- // Countdown
- .state('core.countdown', {
- url: '/countdown',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Countdown'),
- basePerm: 'core.can_manage_projector',
- },
- })
- .state('core.countdown.detail', {
- resolve: {
- countdownId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- });
-
- $locationProvider.html5Mode(true);
- }
-])
-
-.factory('ProjectorMessageForm', [
- 'Editor',
- 'gettextCatalog',
- function (Editor, gettextCatalog) {
- return {
- getDialog: function (message) {
- return {
- template: 'static/templates/core/projector-message-form.html',
- controller: 'ProjectorMessageEditCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- projectorMessageId: function () {
- return message.id;
- }
- },
- };
- },
- getFormFields: function () {
- return [
- {
- key: 'message',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('Message'),
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- }
- },
- ];
- },
- };
- }
-])
-
-.factory('TagForm', [
- 'gettextCatalog',
- function (gettextCatalog) {
- return {
- getDialog: function (tag) {
- return {
- template: 'static/templates/core/tag-form.html',
- controller: (tag) ? 'TagUpdateCtrl' : 'TagCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- tagId: function () {return tag ? tag.id : void 0;},
- },
- };
- },
- getFormFields: function() {
- return [
- {
- key: 'name',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Name'),
- required: true
- }
- },
- ];
- },
- };
- }
-])
-
-/* This factory handles the filtering of the OS-data-tables. It contains
- * all logic needed for the table header filtering. Things to configure:
- * - multiselectFilters: A dict associating the filter name to a list (empty per default). E.g.
- * { tag: [],
- * category: [], }
- * - booleanFilters: A dict containing a dict for every filter. The value property is a must.
- * For displaying properties like displayName, choiceYes and choiceNo could be usefull. E.g.
- * { isPresent: {
- * value: undefined,
- * displayName: gettext('Is present'), } }
- * - propertyList, propertyFunctionList, propertyDict: See function getObjectQueryString
- */
-.factory('osTableFilter', [
- '$sessionStorage',
- function ($sessionStorage) {
- var createInstance = function (tableName) {
- var self = {
- multiselectFilters: {},
- booleanFilters: {},
- filterString: '',
- };
- var existsStorageEntry = function () {
- return $sessionStorage[tableName];
- };
- var storage = existsStorageEntry();
- if (storage) {
- self = storage;
- }
-
- self.existsStorageEntry = existsStorageEntry;
- self.save = function () {
- $sessionStorage[tableName] = self;
- self.changed();
- };
- self.areFiltersSet = function () {
- var areFiltersSet = _.find(self.multiselectFilters, function (filterList) {
- return filterList.length > 0;
- });
- areFiltersSet = areFiltersSet || _.find(self.booleanFilters, function (filterDict) {
- return filterDict.value !== undefined;
- });
- areFiltersSet = areFiltersSet || (self.filterString !== '');
- return areFiltersSet !== false;
- };
- self.reset = function (danger) {
- if (danger) {
- return;
- }
- _.forEach(self.multiselectFilters, function (filterList, filter) {
- self.multiselectFilters[filter] = [];
- });
- _.forEach(self.booleanFilters, function (filterDict, filter) {
- self.booleanFilters[filter].value = undefined;
- });
- self.filterString = '';
- self.save();
- };
- self.operateMultiselectFilter = function (filter, id, danger) {
- if (!danger) {
- if (_.indexOf(self.multiselectFilters[filter], id) > -1) {
- // remove id
- self.multiselectFilters[filter].splice(_.indexOf(self.multiselectFilters[filter], id), 1);
- } else {
- // add id
- self.multiselectFilters[filter].push(id);
- }
- self.save();
- }
- };
- /* Three things are could be given to create the query string:
- * - propertyList: Just a list of object's properties like ['title', 'name']
- * - propertyFunktionList: A list of functions returning a property (e.g. [function(motion) {return motion.getTitle();}] for retrieving the motions title)
- * - propertyDict: A dict association properties that are lists to functions on how to handle them.
- * E.g.: {'tags': function (tag) {return tag.name;}, }
- * The list of tags will be mapped with this function to a list of strings (tag names).
- */
- self.getObjectQueryString = function (obj) {
- var stringList = [];
- _.forEach(self.propertyList, function (property) {
- stringList.push(obj[property]);
- });
- _.forEach(self.propertyFunctionList, function (fn) {
- stringList.push(fn(obj));
- });
- _.forEach(self.propertyDict, function (idFunction, property) {
- stringList.push(_.map(obj[property], idFunction).join(' '));
- });
- return stringList.join(' ');
- };
- // Stub for callback
- self.changed = function () {};
- return self;
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-/* This factory takes care of the sorting of OS-data-tables. Things to configure:
- * - column: the default column which is the list sorted by (e.g.
- * instance.column='title')
- */
-.factory('osTableSort', [
- '$sessionStorage',
- function ($sessionStorage) {
- var createInstance = function (tableName) {
- var self = {
- column: '',
- reverse: false,
- };
- var storage = $sessionStorage[tableName];
- if (storage) {
- self = storage;
- }
-
- self.save = function () {
- $sessionStorage[tableName] = self;
- };
- self.toggle = function (column) {
- if (self.column === column) {
- self.reverse = !self.reverse;
- }
- self.column = column;
- self.save();
- };
- return self;
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-/* Factory for pagination of the tables. Saves all settings (currentPage, ...)
- * to the session storage and recovers them when the table is reloaded.
- * You have to provide a 'tableName' where the settings are saved in the session
- * storage. Has to be unique for obvious reasons.
- * The 'itemsPerPage' is optional. If not given, it defaults to 25.
- */
-.factory('osTablePagination', [
- '$rootScope',
- '$sessionStorage',
- function ($rootScope, $sessionStorage) {
- var createInstance = function (tableName, itemsPerPage) {
- // Defaults
- var self = {
- currentPage: 1,
- itemsPerPage: itemsPerPage || 25,
- limitBegin: 0,
- };
-
- // Check storage; maybe recover old state.
- var storage = $sessionStorage[tableName];
- if (storage) {
- self = storage;
- }
-
- self.save = function () {
- $sessionStorage[tableName] = self;
- };
- self.pageChanged = function () {
- self.limitBegin = (self.currentPage - 1) * self.itemsPerPage;
- self.save();
- $rootScope.gotoTop();
- };
- self.getPageCount = function (objs) {
- if (objs) {
- return Math.ceil(objs.length/self.itemsPerPage);
- }
- };
- self.showNextPageArrow = function (objs) {
- if (objs) {
- return self.currentPage != self.getPageCount(objs);
- }
- };
- self.showPrevPageArrow = function () {
- return self.currentPage != 1;
- };
- self.nextPage = function (objs) {
- if (objs && self.currentPage < self.getPageCount(objs)) {
- self.currentPage++;
- self.pageChanged();
- }
- };
- self.prevPage = function () {
- if (self.currentPage > 1) {
- self.currentPage--;
- self.pageChanged();
- }
- };
- return self;
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-/* This Factory could be used in any dialog, if the user should be warned, if another user
- * also has this dialog open. Use it like in this example in any dialog controller:
- var editingStoppedCallback = EditingWarning.editingStarted('editing_name' + item.id);
- $scope.$on('$destroy', editingStoppedCallback);
- */
-.factory('EditingWarning', [
- 'operator',
- 'gettextCatalog',
- 'Notify',
- 'Messaging',
- function (operator, gettextCatalog, Notify, Messaging) {
- return {
- // This returns the callback function that the controller should call, if
- // the dialog got closed by the user. Provide a unique dialog name.
- editingStarted: function (dialogName) {
- // List of active editors
- var editorNames = [];
- var messagingId = dialogName + 'EditingWarning';
- // Add an editor (may come from open_request or open_response)
- var addActiveEditor = function (editorName) {
- editorNames.push(editorName);
- updateActiveEditors();
- };
- // Remove an editor, if he closes his dialog (dialog_closed)
- var removeActiveEditor = function (editorName) {
- var firstIndex = _.indexOf(editorNames, editorName);
- editorNames.splice(firstIndex, 1);
- updateActiveEditors();
- };
- // Show a warning.
- var updateActiveEditors = function () {
- if (editorNames.length === 0) {
- Messaging.deleteMessage(messagingId);
- } else {
- // This block is only for getting the message string together...
- var editorsWithoutAnonymous = _.filter(editorNames, function (name) {
- return name;
- });
- var text = gettextCatalog.getString('Warning') + ': ';
- if (editorsWithoutAnonymous.length === 0) { // Only anonymous
- // Singular vs. plural
- if (editorNames.length === 1) {
- text += gettextCatalog.getString('One anonymous users is also editing this.');
- } else {
- text += editorNames.length + ' ' + gettextCatalog.getString('anonymous users are also editing this.');
- }
- } else {
- // At least one named user. The max users to display is 5. Anonymous users doesn't get displayed
- // by name, but the amount of users is shown.
- text += _.slice(editorsWithoutAnonymous, 0, 5).join(', ');
- if (editorsWithoutAnonymous.length > 5) {
- // More than 5 users with names.
- text += ', ... [+' + (editorNames.length - 5) + ']';
- } else if (editorsWithoutAnonymous.length !== editorNames.length) {
- // Less than 5 users, so the difference is calculated different.
- text += ', ... [+' + (editorNames.length - editorsWithoutAnonymous.length) + ']';
- }
- // Singular vs. plural
- if (editorNames.length === 1) {
- text += ' ' + gettextCatalog.getString('is also editing this.');
- } else {
- text += ' ' + gettextCatalog.getString('are also editing this.');
- }
- }
- Messaging.createOrEditMessage(messagingId, text, 'warning');
- }
- };
-
- // The stucture of determinating which users are editing this dialog:
- // - send an open_query to every user with the name of this operator in the parameter. With
- // this information all clients that listen to this request knows that this operator has
- // opened the dialog.
- // - The clients, which have recieved the query send an answer (open_resonse) to this operator.
- // - The operator collects all resonses and fills the editornames list.
- // - If the dialog get closed, a dialog_closed is send. All recieven clients remove this
- // operato from their editorNames list.
- var responseCallbackId = Notify.registerCallback(dialogName + '_open_response', function (notify) {
- if (!notify.sendBySelf) {
- addActiveEditor(notify.params.name);
- }
- });
- var queryCallbackId = Notify.registerCallback(dialogName + '_open_query', function (notify) {
- if (!notify.sendBySelf) {
- addActiveEditor(notify.params.name);
- if (notify.senderUserId) {
- Notify.notify(dialogName + '_open_response', {
- name: operator.user ? operator.user.short_name : '',
- }, [notify.senderUserId]);
- } else {
- Notify.notify(dialogName + '_open_response', {
- name: operator.user ? operator.user.short_name : '',
- }, null, [notify.senderReplyChannelName]);
- }
- }
- });
- var closeCallbackId = Notify.registerCallback(dialogName + '_dialog_closed', function (notify) {
- removeActiveEditor(notify.params.name);
- });
- // Send here the open_query to get the notify-chain started.
- Notify.notify(dialogName + '_open_query', {
- name: operator.user ? operator.user.short_name : '',
- });
- // The function returned is to deregister the callbacks and send the dialog_closed notify, if
- // the dialog get closed.
- return function () {
- Notify.deregisterCallbacks(responseCallbackId, queryCallbackId, closeCallbackId);
- Messaging.deleteMessage(messagingId);
- Notify.notify(dialogName + '_dialog_closed', {
- name: operator.user ? operator.user.short_name : '',
- });
- };
- },
- };
- }
-])
-
-/*
- * This filter filters all items in an array. If the filterArray is empty, the
- * array is passed. The filterArray contains numbers of the multiselect, e. g. [1, 3, 4].
- * Then, all items in the array are passed, if the item_id (get with id_function) matches
- * one of the ids in filterArray. id_function could also return a list of ids. Example:
- * Item 1 has two tags with ids [1, 4]. filterArray == [3, 4] --> match
- *
- * If -1 is in the array items without an id will not be filtered. This is for implementing
- * a filter option like: "All items without a category"
- */
-.filter('MultiselectFilter', [
- function () {
- return function (array, filterArray, idFunction) {
- if (filterArray.length === 0) {
- return array;
- }
- var itemsWithoutProperty = _.indexOf(filterArray, -1) > -1;
- return Array.prototype.filter.call(array, function (item) {
- var id = idFunction(item);
- if (typeof id === 'number') {
- id = [id];
- } else if (id === null || !id.length) {
- return itemsWithoutProperty;
- }
- return _.intersection(id, filterArray).length > 0;
- });
- };
- }
-])
-
-.filter('osFilter', [
- function () {
- return function (array, string, getFilterString) {
- if (!string) {
- return array;
- }
- return Array.prototype.filter.call(array, function (item) {
- return getFilterString(item).toLowerCase().indexOf(string.toLowerCase()) > -1;
- });
- };
- }
-])
-
-// angular formly config options
-.run([
- 'formlyConfig',
- function (formlyConfig) {
- // NOTE: This next line is highly recommended. Otherwise Chrome's autocomplete
- // will appear over your options!
- formlyConfig.extras.removeChromeAutoComplete = true;
-
- // Configure custom types
- formlyConfig.setType({
- name: 'editor',
- extends: 'textarea',
- templateUrl: 'static/templates/core/editor.html',
- });
- formlyConfig.setType({
- name: 'password',
- extends: 'input',
- templateUrl: 'static/templates/core/password.html',
- });
- formlyConfig.setType({
- name: 'checkbox',
- templateUrl: 'static/templates/core/checkbox.html',
- overwriteOk: true,
- });
- formlyConfig.setType({
- name: 'checkbox-buttons',
- templateUrl: 'static/templates/core/checkbox-buttons.html',
- overwriteOk: true,
- });
- formlyConfig.setType({
- name: 'select-single',
- extends: 'select',
- templateUrl: 'static/templates/core/select-single.html'
- });
- formlyConfig.setType({
- name: 'select-multiple',
- extends: 'select',
- templateUrl: 'static/templates/core/select-multiple.html'
- });
- formlyConfig.setType({
- name: 'radio-buttons',
- templateUrl: 'static/templates/core/radio-buttons.html',
- wrapper: ['bootstrapHasError'],
- defaultOptions: {
- noFormControl: false
- }
- });
- formlyConfig.setType({
- name: 'file',
- extends: 'input',
- templateUrl: 'static/templates/core/file.html',
- });
- }
-])
-
-// html-tag os-form-field to generate generic from fields
-// TODO: make it possible to use other fields then config fields
-.directive('osFormField', [
- '$parse',
- 'Config',
- 'gettextCatalog',
- function($parse, Config, gettextCatalog) {
- var getHtmlType = function (type) {
- return {
- string: 'text',
- text: 'textarea',
- markupText: 'editor',
- integer: 'number',
- boolean: 'checkbox',
- choice: 'choice',
- comments: 'comments',
- colorpicker: 'colorpicker',
- datetimepicker: 'datetimepicker',
- majorityMethod: 'choice',
- translations: 'translations',
- }[type];
- };
-
- return {
- restrict: 'E',
- scope: true,
- templateUrl: 'static/templates/config-form-field.html',
- link: function ($scope, iElement, iAttrs, controller, transcludeFn) {
- var field = $parse(iAttrs.field)($scope);
- var config = Config.get(field.key);
- $scope.type = getHtmlType(field.input_type);
- if ($scope.type == 'choice') {
- $scope.choices = field.choices;
- $scope.value = config.value;
- } else {
- $scope.value = gettextCatalog.getString(config.value);
- }
- $scope.label = field.label;
- $scope.key = 'field-' + field.key;
- $scope.help_text = field.help_text;
- $scope.default_value = field.default_value;
- $scope.reset = function () {
- if ($scope.type == 'choice') {
- $scope.value = $scope.default_value;
- } else {
- $scope.value = gettextCatalog.getString($scope.default_value);
- }
- $scope.save(field, $scope.value);
- };
- }
- };
- }
-])
-
-/* This directive provides a csv import template.
- * Papa Parse is used to parse the csv file. Accepted attributes:
- * * change:
- * Callback if file changes. The one parameter is csv passing the parsed file
- * * config (optional):
- * - accept: String with extensions: default '.csv .txt'
- * - encodingOptions: List with encodings. Default ['UTF-8', 'ISO-8859-1']
- * - parseConfig: a dict passed to PapaParse
- */
-.directive('csvImport', [
- function () {
- return {
- restrict: 'E',
- templateUrl: 'static/templates/csv-import.html',
- scope: {
- change: '&',
- config: '=?',
- },
- controller: function ($scope, $element, $attrs, $location) {
- // set config if it is not given
- if (!$scope.config) {
- $scope.config = {};
- }
- if (!$scope.config.parseConfig) {
- $scope.config.parseConfig = {};
- }
-
- $scope.inputElement = angular.element($element[0].querySelector('#csvFileSelector'));
-
- // set accept and encoding
- $scope.accept = $scope.config.accept || '.csv';
- $scope.encodingOptions = $scope.config.encodingOptions || ['UTF-8'];
- $scope.encoding = $scope.encodingOptions[0];
-
- $scope.parse = function () {
- var inputElement = $scope.inputElement[0];
- if (!inputElement.files.length) {
- $scope.change({csv: {data: {}}});
- } else {
- var parseConfig = _.defaults(_.clone($scope.config.parseConfig), {
- delimiter: $scope.delimiter,
- encoding: $scope.encoding,
- header: false, // we do not want to have dicts in result
- complete: function (csv) {
- if (csv.data.length) {
- csv.meta.fields = csv.data[0];
- }
- else {
- csv.meta.fields = [];
- }
- csv.data = csv.data.splice(1); // do not interpret the header as data
- $scope.$apply(function () {
- if (csv.meta.delimiter) {
- $scope.autodelimiter = csv.meta.delimiter;
- }
- $scope.change({csv: csv});
- });
- },
- error: function () {
- $scope.$apply(function () {
- $scope.change({csv: {data: {}}});
- });
- },
- });
-
- Papa.parse(inputElement.files[0], parseConfig);
- }
- };
-
- $scope.clearFile = function () {
- $scope.inputElement[0].value = '';
- $scope.selectedFile = undefined;
- $scope.parse();
- };
-
- $scope.inputElement.on('change', function () {
- $scope.selectedFile = _.last($scope.inputElement[0].value.split('\\'));
- $scope.parse();
- });
- },
- };
- }
-])
-
-.directive('messaging', [
- '$timeout',
- 'Messaging',
- function ($timeout, Messaging) {
- return {
- restrict: 'E',
- templateUrl: 'static/templates/messaging.html',
- scope: {},
- controller: function ($scope, $element, $attrs, $location) {
- $scope.messages = {};
-
- var update = function () {
- $scope.messages = Messaging.getMessages();
- };
- Messaging.registerMessageChangeCallback(update);
-
- $scope.close = function (id) {
- Messaging.deleteMessage(id);
- };
- },
- };
- }
-])
-
-.controller('MainMenuCtrl', [
- '$scope',
- 'mainMenu',
- function ($scope, mainMenu) {
- mainMenu.registerScope($scope);
- $scope.isMenuOpen = false;
- $scope.closeMenu = function () {
- $scope.isMenuOpen = false;
- };
- }
-])
-
-.controller('LanguageCtrl', [
- '$scope',
- 'gettextCatalog',
- 'Languages',
- 'filterFilter',
- function ($scope, gettextCatalog, Languages, filterFilter) {
- $scope.languages = Languages.getLanguages();
- $scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
- // controller to switch app language
- $scope.switchLanguage = function (lang) {
- $scope.languages = Languages.setCurrentLanguage(lang);
- $scope.selectedLanguage = filterFilter($scope.languages, {selected: true});
- };
- }
-])
-
-.controller('GotoTopCtrl', [
- '$scope',
- '$window',
- '$timeout',
- function ($scope, $window, $timeout) {
- $scope.show = false;
- angular.element($window).bind('scroll', function () {
- $timeout(function () {
- $scope.show = ($window.pageYOffset >= 150);
- });
- });
- }
-])
-
-.run([
- '$rootScope',
- '$window',
- function ($rootScope, $window) {
- $rootScope.gotoTop = function () {
- $window.scrollTo(0, 0);
- };
- }
-])
-
-// Prevent scrolling in number inputs. Instead of changing the number, the input
-// is blurred and the window is scrolled. This is very important for our dialog
-// forms, so a user didn't change a value, when he wants to scroll the form.
-.run(function () {
- $('body').on('mousewheel', function (e) {
- if (e.target.nodeName === 'INPUT' && e.target.type === 'number') {
- $(e.target).blur();
- }
- });
-})
-
-// Projector Sidebar Controller
-.controller('ProjectorSidebarCtrl', [
- '$scope',
- '$document',
- '$window',
- function ($scope, $document, $window) {
- $scope.isProjectorSidebar = false;
- $scope.showProjectorSidebar = function (show) {
- $scope.isProjectorSidebar = show;
- };
-
- // Sidebar scroll
- var marginTop = 20, // margin-top from #content
- marginBottom = 30, // 30px + 20px sidebar margin-bottom = 50px from footer
- sidebar;
-
- var sidebarScroll = function () {
- var sidebarHeight = sidebar.height(),
- sidebarOffset = sidebar.offset().top,
- sidebarMinOffset = $('#header').height() + $('#nav').height() + marginTop,
- documentHeight = $document.height(),
- windowHeight = $window.innerHeight,
- scrollTop = $window.pageYOffset;
-
- // First, check if there is a need to scroll: scroll if the sidebar is smaller then the content
- if (sidebarHeight < $('.col1').height()) {
- if ((scrollTop + marginTop + sidebarHeight) > (documentHeight - marginBottom)) {
- // Stick to the bottom
- var bottom = marginBottom + scrollTop + windowHeight - documentHeight;
- sidebar.css({'position': 'fixed', 'top': '', 'bottom': bottom});
- } else if ((scrollTop + marginTop) > sidebarMinOffset) {
- // scroll with the user
- sidebar.css({'position': 'fixed', 'top': marginTop, 'bottom': ''});
- } else {
- // Stick to the top
- sidebar.css({'position': 'relative', 'top': 0, 'bottom': ''});
- }
- } else {
- // Stick to the top, if the sidebar is larger then the content
- sidebar.css({'position': 'relative', 'top': 0, 'bottom': ''});
- }
- };
-
- $scope.initSidebar = function () {
- sidebar = $('#sidebar');
- $scope.$watch(function () {
- return sidebar.height();
- }, sidebarScroll);
- angular.element($window).bind('scroll', sidebarScroll);
- };
-
- }
-])
-
-// Legal Notice Controller
-.controller('LegalNoticeCtrl', [
- '$scope',
- '$http',
- function ($scope, $http) {
- $http.get('/core/version/').then(function (success) {
- $scope.core_version = success.data.openslides_version;
- $scope.core_license = success.data.openslides_license;
- $scope.core_url = success.data.openslides_url;
- $scope.plugins = success.data.plugins;
- });
- }
-])
-
-// Privacy Policy Controller
-.controller('PrivacyPolicyCtrl', function () {})
-
-// Config Controller
-.controller('ConfigCtrl', [
- '$scope',
- '$timeout',
- 'MajorityMethodChoices',
- 'Config',
- 'OpenSlidesConfigVariables',
- 'gettextCatalog',
- 'DateTimePickerTranslation',
- 'Editor',
- function($scope, $timeout, MajorityMethodChoices, Config, OpenSlidesConfigVariables,
- gettextCatalog, DateTimePickerTranslation, Editor) {
- Config.bindAll({}, $scope, 'configs');
- $scope.configGroups = OpenSlidesConfigVariables;
- $scope.dateTimePickerTranslatedButtons = DateTimePickerTranslation.getButtons();
-
- $scope.ckeditorOptions = Editor.getOptions();
- $scope.ckeditorOptions.on.change = function (event) {
- // we could just retrieve the key, but we need the configOption object.
- var configOption_key = event.editor.element.$.id;
-
- // find configOption object
- var subgroups = _.flatMap($scope.configGroups, function (group) {
- return group.subgroups;
- });
- var items = _.flatMap(subgroups, function (subgroup) {
- return subgroup.items;
- });
- var configOption = _.find(items, function (_item) {
- return _item.key === configOption_key;
- });
-
- var editor = this;
- // The $timeout executes the given function in an angular context. Because
- // this is a standard JS event, all changes may not happen in the digist-cylce.
- // By using $timeout angular calls $apply for us that we do not have to care
- // about starting the digist-cycle.
- $timeout(function () {
- $scope.save(configOption, editor.getData());
- }, 1);
- };
-
- // save changed config value
- $scope.save = function(configOption, value) {
- Config.get(configOption.key).value = value;
- Config.save(configOption.key).then(function (success) {
- configOption.success = true;
- // fade out the success symbol after 2 seconds.
- $timeout(function () {
- var element = $('#success-field-' + configOption.key);
- element.fadeOut(800, function () {
- configOption.success = void 0;
- });
- }, 2000);
- }, function (error) {
- configOption.success = false;
- configOption.errorMessage = error.data.detail;
- });
- };
-
- // For comments input
- $scope.addComment = function (configOption, parent) {
- var maxId = _.max(_.keys(parent.value));
- if (maxId === undefined) {
- maxId = 1;
- } else {
- maxId = parseInt(maxId) + 1;
- }
- parent.value[maxId] = {
- name: gettextCatalog.getString('New'),
- public: false,
- };
- $scope.save(configOption, parent.value);
- };
- $scope.removeComment = function (configOption, parent, id) {
- parent.value[id] = null;
- $scope.save(configOption, parent.value);
- };
-
- // For custom translations input
- $scope.addTranslation = function (configOption, parent) {
- parent.value.push({
- original: gettextCatalog.getString('New'),
- translation: gettextCatalog.getString('New'),
- });
- $scope.save(configOption, parent.value);
- };
- $scope.removeTranslation = function (configOption, parent, index) {
- parent.value.splice(index, 1);
- $scope.save(configOption, parent.value);
- };
-
- // For majority method
- angular.forEach(
- _.filter($scope.configGroups, function (configGroup) {
- return configGroup.name === 'Motions' || configGroup.name === 'Elections';
- }),
- function (configGroup) {
- var configItem;
- _.forEach(configGroup.subgroups, function (subgroup) {
- configItem = _.find(subgroup.items, ['input_type', 'majorityMethod']);
- if (configItem !== undefined) {
- // Break the forEach loop if we found something.
- return false;
- }
- });
- if (configItem !== undefined) {
- configItem.choices = MajorityMethodChoices;
- }
- }
- );
- }
-])
-
-// Search Bar Controller
-.controller('SearchBarCtrl', [
- '$scope',
- '$state',
- '$sanitize',
- function ($scope, $state, $sanitize) {
- $scope.search = function() {
- var query = _.escape($scope.querybar);
- $scope.querybar = '';
- $state.go('search', {q: query});
- };
- }
-])
-
-// Search Controller
-.controller('SearchCtrl', [
- '$scope',
- '$filter',
- '$stateParams',
- 'Search',
- 'DS',
- 'Motion',
- function ($scope, $filter, $stateParams, Search, DS, Motion) {
- $scope.searchresults = [];
- var searchModules = Search.getAll();
-
- // search function
- $scope.search = function() {
- $scope.results = [];
- var foundObjects = [];
- // search in rest properties of all defined searchModule
- // (does not found any related objects, e.g. speakers of items)
- _.forEach(searchModules, function(searchModule) {
- var result = {};
- result.verboseName = searchModule.verboseName;
- result.collectionName = searchModule.collectionName;
- result.urlDetailState = searchModule.urlDetailState;
- result.weight = searchModule.weight;
- result.checked = true;
- result.elements = $filter('filter')(DS.getAll(searchModule.collectionName), $scope.searchquery);
- $scope.results.push(result);
- _.forEach(result.elements, function(element) {
- foundObjects.push(element);
- });
- });
- // search additionally in specific releations of all defined searchModules
- _.forEach(searchModules, function(searchModule) {
- _.forEach(DS.getAll(searchModule.collectionName), function(object) {
- if (_.isFunction(object.hasSearchResult)) {
- if (object.hasSearchResult(foundObjects, $scope.searchquery)) {
- // releation found, check if object is not yet in search results
- _.forEach($scope.results, function(result) {
- if ((object.getResourceName() === result.collectionName) &&
- _.findIndex(result.elements, {'id': object.id}) === -1) {
- result.elements.push(object);
- }
- });
- }
- } else {
- return false;
- }
- });
- });
- };
-
- //get search string from parameters submitted from outside the scope
- if ($stateParams.q) {
- $scope.searchquery = $stateParams.q;
- $scope.search();
- }
- }
-])
-
-// Projector Control Controller
-.controller('ProjectorControlCtrl', [
- '$scope',
- '$http',
- '$interval',
- '$state',
- '$q',
- '$filter',
- 'Config',
- 'Projector',
- 'CurrentListOfSpeakersItem',
- 'CurrentListOfSpeakersSlide',
- 'ProjectionDefault',
- 'ProjectorMessage',
- 'Countdown',
- 'gettextCatalog',
- 'ngDialog',
- 'ProjectorMessageForm',
- function($scope, $http, $interval, $state, $q, $filter, Config, Projector, CurrentListOfSpeakersItem,
- CurrentListOfSpeakersSlide, ProjectionDefault, ProjectorMessage, Countdown, gettextCatalog,
- ngDialog, ProjectorMessageForm) {
- ProjectorMessage.bindAll({}, $scope, 'messages');
-
- var intervals = [];
- var calculateCountdownTime = function (countdown) {
- countdown.seconds = Math.floor( countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
- };
- var cancelIntervalTimers = function () {
- intervals.forEach(function (interval) {
- $interval.cancel(interval);
- });
- };
- $scope.$watch(function () {
- return Countdown.lastModified();
- }, function () {
- $scope.countdowns = Countdown.getAll();
-
- // stop ALL interval timer
- cancelIntervalTimers();
- $scope.countdowns.forEach(function (countdown) {
- if (countdown.running) {
- calculateCountdownTime(countdown);
- intervals.push($interval(function () { calculateCountdownTime(countdown); }, 1000));
- } else {
- countdown.seconds = countdown.countdown_time;
- }
- });
- });
- $scope.$on('$destroy', function() {
- // Cancel all intervals if the controller is destroyed
- cancelIntervalTimers();
- });
-
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- $scope.projectors = Projector.getAll();
- if (!$scope.active_projector) {
- $scope.active_projector = $filter('orderBy')($scope.projectors, 'id')[0];
- }
- $scope.setIframeSize($scope.active_projector);
- if ($scope.projectors.length === 1) {
- $scope.currentListOfSpeakersAsOverlay = true;
- }
-
- $scope.messageDefaultProjectorId = ProjectionDefault.filter({name: 'messages'})[0].projector_id;
- $scope.countdownDefaultProjectorId = ProjectionDefault.filter({name: 'countdowns'})[0].projector_id;
- $scope.listOfSpeakersDefaultProjectorId = ProjectionDefault.filter({name: 'agenda_current_list_of_speakers'})[0].projector_id;
- });
- // watch for changes in projector_broadcast and currentListOfSpeakersReference
- var last_broadcast;
- $scope.$watch(function () {
- return Config.lastModified();
- }, function () {
- var broadcast = Config.get('projector_broadcast').value;
- if (!last_broadcast || last_broadcast != broadcast) {
- last_broadcast = broadcast;
- $scope.broadcast = broadcast;
- }
- $scope.currentListOfSpeakersReference = $scope.config('projector_currentListOfSpeakers_reference');
- });
-
- $scope.changeProjector = function (projector) {
- $scope.active_projector = projector;
- $scope.setIframeSize(projector);
- };
- $scope.setIframeSize = function (projector) {
- $scope.scale = 256.0 / projector.width;
- $scope.iframeHeight = $scope.scale * projector.height;
- };
-
- $scope.editCurrentSlide = function (projector) {
- var data = projector.getFormOrStateForCurrentSlide();
- if (data) {
- if (data.form) {
- ngDialog.open(data.form.getDialog({id: data.id}));
- } else {
- $state.go(data.state, {id: data.id});
- }
- }
- };
-
- // *** countdown functions ***
- $scope.calculateCountdownTime = function (countdown) {
- countdown.seconds = Math.floor( countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
- };
- $scope.editCountdown = function (countdown) {
- countdown.editFlag = false;
- countdown.description = countdown.new_description;
- Countdown.save(countdown);
- if (!countdown.running) {
- countdown.reset();
- }
- };
- $scope.addCountdown = function () {
- var default_time = parseInt($scope.config('projector_default_countdown'));
- var countdown = {
- description: '',
- default_time: default_time,
- countdown_time: default_time,
- running: false,
- };
- Countdown.create(countdown);
- };
- $scope.removeCountdown = function (countdown) {
- Countdown.destroy(countdown.id);
- };
-
- // *** message functions ***
- $scope.editMessage = function (message) {
- ngDialog.open(ProjectorMessageForm.getDialog(message));
- };
- $scope.addMessage = function () {
- var message = {message: ''};
- ProjectorMessage.create(message);
- };
- $scope.removeMessage = function (message) {
- ProjectorMessage.destroy(message.id);
- };
-
- /* Current list of speakers */
- $scope.currentListOfSpeakers = CurrentListOfSpeakersSlide;
- // Set the current overlay status
- if ($scope.currentListOfSpeakers.isProjected().length) {
- var isProjected = $scope.currentListOfSpeakers.isProjectedWithOverlayStatus();
- $scope.currentListOfSpeakersAsOverlay = isProjected[0].overlay;
- } else {
- $scope.currentListOfSpeakersAsOverlay = true;
- }
- // go to the list of speakers(management) of the currently displayed list of speakers reference slide
- $scope.goToListOfSpeakers = function() {
- var item = $scope.currentListOfSpeakersItem();
- if (item) {
- $state.go('agenda.item.detail', {id: item.id});
- }
- };
- $scope.currentListOfSpeakersItem = function () {
- return CurrentListOfSpeakersItem.getItem($scope.currentListOfSpeakersReference);
- };
- $scope.setOverlay = function (overlay) {
- $scope.currentListOfSpeakersAsOverlay = overlay;
- var isProjected = $scope.currentListOfSpeakers.isProjectedWithOverlayStatus();
- if (isProjected.length) {
- _.forEach(isProjected, function (mapping) {
- if (mapping.overlay != overlay) { // change the overlay if it is different
- $scope.currentListOfSpeakers.project(mapping.projectorId, overlay);
- }
- });
- }
- };
- }
-])
-
-.controller('ProjectorMessageEditCtrl', [
- '$scope',
- 'projectorMessageId',
- 'ProjectorMessage',
- 'ProjectorMessageForm',
- function ($scope, projectorMessageId, ProjectorMessage, ProjectorMessageForm) {
- $scope.formFields = ProjectorMessageForm.getFormFields();
- $scope.model = angular.copy(ProjectorMessage.get(projectorMessageId));
-
- $scope.save = function (message) {
- ProjectorMessage.inject(message);
- ProjectorMessage.save(message);
- $scope.closeThisDialog();
- };
- }
-])
-
-.controller('ManageProjectorsCtrl', [
- '$scope',
- '$http',
- '$timeout',
- 'Projector',
- 'ProjectionDefault',
- 'Config',
- 'ProjectorMessage',
- 'ngDialog',
- function ($scope, $http, $timeout, Projector, ProjectionDefault, Config,
- ProjectorMessage, ngDialog) {
- ProjectionDefault.bindAll({}, $scope, 'projectiondefaults');
-
- /* Info on resolution calculating:
- * Internally the resolution is saved as (width, height) but the user has
- * an aspect ratio to choose and a width from 800 to 3840 (4K).*/
- $scope.aspectRatios = {
- '4:3': 4/3,
- '16:9': 16/9,
- '16:10': 16/10,
- };
- // when converting (x,y) -> (ratio, percentage) round issues may occur
- // (e.g. 800/600 != 4/3 with internal calculation issues). With this environment
- // is tested, if the calculated value is in the following interval:
- // [expected-environment; expected+environment]
- var RATIO_ENVIRONMENT = 0.05;
-
- // watch for changes in projector_broadcast
- // and projector_currentListOfSpeakers_reference
- var last_broadcast, last_clos;
- $scope.$watch(function () {
- return Config.lastModified();
- }, function () {
- var broadcast = $scope.config('projector_broadcast'),
- currentListOfSpeakers = $scope.config('projector_currentListOfSpeakers_reference');
- if (!last_broadcast || last_broadcast != broadcast) {
- last_broadcast = broadcast;
- $scope.broadcast = broadcast;
- }
- if (!last_clos || last_clos != currentListOfSpeakers) {
- last_clos = currentListOfSpeakers;
- $scope.currentListOfSpeakers = currentListOfSpeakers;
- }
- });
-
- // watch for changes in Projector, and recalc scale and iframeHeight
- var first_watch = true;
- $scope.resolutions = {};
- $scope.edit = [];
- $scope.sliders = {};
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- $scope.projectors = Projector.getAll();
- $scope.projectors.forEach(function (projector) {
- projector.iframeScale = 256.0 / projector.width;
- projector.iframeHeight = projector.iframeScale * projector.height;
- if (first_watch) {
- $scope.resolutions[projector.id] = {
- width: projector.width,
- height: projector.height
- };
- $scope.edit[projector.id] = false;
- $scope.sliders[projector.id] = {
- value: projector.width,
- options: {
- id: projector.id,
- floor: 800,
- ceil: 3840,
- step: 10,
- translate: function (value) {
- return value + 'px';
- },
- onChange: function (v) {
- $scope.calcResolution(projector);
- },
- onEnd: function (v) {
- $scope.saveResolution(projector);
- },
- hideLimitLabels: true,
- },
- };
- $scope.setAspectRatio(projector, $scope.getAspectRatio(projector));
- }
- });
- if ($scope.projectors.length) {
- first_watch = false;
- }
- });
-
- $scope.getAspectRatio = function (projector) {
- var ratio = projector.width/projector.height;
- var foundRatio = _.findKey($scope.aspectRatios, function (value) {
- return value >= (ratio-RATIO_ENVIRONMENT) && value <= (ratio+RATIO_ENVIRONMENT);
- });
- if (foundRatio === undefined) {
- return _.keys($scope.aspectRatios)[0];
- } else {
- return foundRatio;
- }
- };
- $scope.setAspectRatio = function (projector, aspectRatio) {
- $scope.resolutions[projector.id].aspectRatio = aspectRatio;
- $scope.resolutions[projector.id].aspectRatioNumber = $scope.aspectRatios[aspectRatio];
- $scope.calcResolution(projector);
- };
- $scope.calcResolution = function (projector) {
- var ratio = $scope.resolutions[projector.id].aspectRatioNumber;
- var width = $scope.sliders[projector.id].value;
- $scope.resolutions[projector.id].width = width;
- $scope.resolutions[projector.id].height = Math.round(width/ratio);
- };
-
- $scope.toggleEditMenu = function (projectorId) {
- $scope.edit[projectorId] = !$scope.edit[projectorId];
- $timeout(function () {
- $scope.$broadcast('rzSliderForceRender');
- });
- };
-
- // Set list of speakers reference
- $scope.setListOfSpeakers = function (projector) {
- Config.get('projector_currentListOfSpeakers_reference').value = projector.id;
- Config.save('projector_currentListOfSpeakers_reference');
- };
-
- // Projector functions
- $scope.setProjectionDefault = function (projector, projectiondefault) {
- if (projectiondefault.projector_id !== projector.id) {
- $http.post('/rest/core/projector/' + projector.id + '/set_projectiondefault/', projectiondefault.id);
- }
- };
- $scope.createProjector = function (name) {
- var projector = {
- name: name,
- config: {},
- scale: 0,
- scroll: 0,
- blank: false,
- projectiondefaults: [],
- };
- Projector.create(projector).then(function (projector) {
- $http.post('/rest/core/projector/' + projector.id + '/activate_elements/', [{
- name: 'core/clock',
- stable: true
- }]);
- $scope.resolutions[projector.id] = {
- width: projector.width,
- height: projector.height
- };
- });
- };
- $scope.deleteProjector = function (projector) {
- if (projector.id != 1) {
- Projector.destroy(projector.id);
- }
- };
- $scope.editCurrentSlide = function (projector) {
- var data = projector.getFormOrStateForCurrentSlide();
- if (data) {
- if (data.form) {
- ngDialog.open(data.form.getDialog({id: data.id}));
- } else {
- $state.go(data.state, {id: data.id});
- }
- }
- };
- $scope.editName = function (projector) {
- projector.config = projector.elements;
- Projector.save(projector);
- };
- $scope.saveResolution = function (projector) {
- $http.post(
- '/rest/core/projector/' + projector.id + '/set_resolution/',
- $scope.resolutions[projector.id]
- ).then(function (success) {
- $scope.resolutions[projector.id].error = null;
- }, function (error) {
- if (error.data) {
- $scope.resolutions[projector.id].error = error.data.detail;
- } else {
- $scope.resolutions[projector.id].error = null;
- }
- });
- };
-
- // Identify projectors
- $scope.identifyProjectors = function () {
- if ($scope.identifyPromise) {
- $timeout.cancel($scope.identifyPromise);
- $scope.removeIdentifierMessages();
- } else {
- // Create new Message
- var message = {
- message: '',
- };
- ProjectorMessage.create(message).then(function(message){
- $scope.projectors.forEach(function (projector) {
- $http.post('/rest/core/projector/' + projector.id + '/activate_elements/', [{
- name: 'core/projector-message',
- stable: true,
- id: message.id,
- identify: true,
- }]);
- });
- $scope.identifierMessage = message;
- });
- $scope.identifyPromise = $timeout($scope.removeIdentifierMessages, 3000);
- }
- };
- $scope.removeIdentifierMessages = function () {
- Projector.getAll().forEach(function (projector) {
- _.forEach(projector.elements, function (element, uuid) {
- if (element.name === 'core/projector-message' && element.id === $scope.identifierMessage.id) {
- $http.post('/rest/core/projector/' + projector.id + '/deactivate_elements/', [uuid]);
- }
- });
- });
- ProjectorMessage.destroy($scope.identifierMessage.id);
- $scope.identifyPromise = null;
- };
- }
-])
-
-// Tag Controller
-.controller('TagListCtrl', [
- '$scope',
- 'Tag',
- 'ngDialog',
- 'TagForm',
- 'gettext',
- 'ErrorMessage',
- function($scope, Tag, ngDialog, TagForm, gettext, ErrorMessage) {
- Tag.bindAll({}, $scope, 'tags');
- $scope.alert = {};
-
- // setup table sorting
- $scope.sortColumn = 'name';
- $scope.reverse = false;
- // function to sort by clicked column
- $scope.toggleSort = function ( column ) {
- if ( $scope.sortColumn === column ) {
- $scope.reverse = !$scope.reverse;
- }
- $scope.sortColumn = column;
- };
- $scope.delete = function (tag) {
- Tag.destroy(tag.id).then(
- function(success) {
- $scope.alert = {
- type: 'success',
- msg: gettext('The delete was successful.'),
- show: true,
- };
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- $scope.editOrCreate = function (tag) {
- ngDialog.open(TagForm.getDialog(tag));
- };
- }
-])
-
-.controller('TagCreateCtrl', [
- '$scope',
- 'Tag',
- 'TagForm',
- 'ErrorMessage',
- function($scope, Tag, TagForm, ErrorMessage) {
- $scope.model = {};
- $scope.alert = {};
- $scope.formFields = TagForm.getFormFields();
- $scope.save = function (tag) {
- Tag.create(tag).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('TagUpdateCtrl', [
- '$scope',
- 'Tag',
- 'tagId',
- 'TagForm',
- 'ErrorMessage',
- function($scope, Tag, tagId, TagForm, ErrorMessage) {
- $scope.model = angular.copy(Tag.get(tagId));
- $scope.alert = {};
- $scope.formFields = TagForm.getFormFields();
- $scope.save = function (tag) {
- Tag.inject(tag);
- Tag.save(tag).then(function(success) {
- $scope.closeThisDialog();
- }, function (error) {
- // save error: revert all changes by restore
- // the original object
- Tag.refresh(tag);
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('CountdownDetailCtrl', [
- '$scope',
- '$interval',
- 'Countdown',
- 'countdownId',
- function ($scope, $interval, Countdown, countdownId) {
- var interval;
- var calculateCountdownTime = function (countdown) {
- countdown.seconds = Math.floor( $scope.countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
- };
- $scope.$watch(function () {
- return Countdown.lastModified(countdownId);
- }, function () {
- $scope.countdown = Countdown.get(countdownId);
- if (interval) {
- $interval.cancel(interval);
- }
- if ($scope.countdown) {
- if ($scope.countdown.running) {
- calculateCountdownTime($scope.countdown);
- interval = $interval(function () { calculateCountdownTime($scope.countdown); }, 1000);
- } else {
- $scope.countdown.seconds = $scope.countdown.countdown_time;
- }
- }
- });
- $scope.$on('$destroy', function() {
- // Cancel the interval if the controller is destroyed
- if (interval) {
- $interval.cancel(interval);
- }
- });
- }
-])
-
-// counter of new (unread) chat messages
-.value('NewChatMessages', [])
-
-// ChatMessage Controller
-.controller('ChatMessageCtrl', [
- '$scope',
- '$http',
- '$timeout',
- 'ChatMessage',
- 'NewChatMessages',
- function ($scope, $http, $timeout, ChatMessage, NewChatMessages) {
- ChatMessage.bindAll({}, $scope, 'chatmessages');
- $scope.unreadMessages = NewChatMessages.length;
- $scope.chatboxIsCollapsed = true;
- $scope.openChatbox = function () {
- $scope.chatboxIsCollapsed = !$scope.chatboxIsCollapsed;
- NewChatMessages = [];
- $scope.unreadMessages = NewChatMessages.length;
- $timeout(function () {
- angular.element('#messageInput').focus();
- }, 0);
- };
- $scope.sendMessage = function () {
- angular.element('#messageSendButton').addClass('disabled');
- angular.element('#messageInput').attr('disabled', '');
- $http.post(
- '/rest/core/chat-message/',
- {message: $scope.newMessage}
- ).then(function (success) {
- $scope.newMessage = '';
- angular.element('#messageSendButton').removeClass('disabled');
- angular.element('#messageInput').removeAttr('disabled');
- $timeout(function () {
- angular.element('#messageInput').focus();
- }, 0);
- }, function (error) {
- angular.element('#messageSendButton').removeClass('disabled');
- angular.element('#messageInput').removeAttr('disabled');
- });
- };
- // increment unread messages counter for each new message
- $scope.$watch('chatmessages', function (newVal, oldVal) {
- // add new message id if there is really a new message which is not yet tracked
- if (oldVal.length > 0 && newVal.length > 0) {
- if ((oldVal[oldVal.length-1].id != newVal[newVal.length-1].id) &&
- ($.inArray(newVal[newVal.length-1].id, NewChatMessages) == -1)) {
- NewChatMessages.push(newVal[newVal.length-1].id);
- $scope.unreadMessages = NewChatMessages.length;
- }
- } else if (newVal.length === 0) {
- NewChatMessages = [];
- $scope.unreadMessages = 0;
- }
- });
-
- $scope.clearChatHistory = function () {
- $http.post('/rest/core/chat-message/clear/');
- };
- }
-])
-
-// format time string for model ("s") and view format ("h:mm:ss" or "mm:ss")
-.directive('minSecFormat', [
- 'HumanTimeConverter',
- function (HumanTimeConverter) {
- return {
- require: 'ngModel',
- link: function(scope, element, attrs, ngModelController) {
- ngModelController.$parsers.push(function(data) {
- //convert data from view format (mm:ss) to model format (s)
- return HumanTimeConverter.humanTimeToSeconds(data, {seconds: true});
- });
-
- ngModelController.$formatters.push(function(data) {
- //convert data from model format (s) to view format (mm:ss)
- return HumanTimeConverter.secondsToHumanTime(data);
- });
- }
- };
- }
-])
-
-// format time string for model ("m") and view format ("h:mm" or "hh:mm")
-.directive('hourMinFormat', [
- 'HumanTimeConverter',
- function (HumanTimeConverter) {
- return {
- require: 'ngModel',
- link: function(scope, element, attrs, ngModelController) {
- ngModelController.$parsers.push(function(data) {
- //convert data from view format (hh:mm) to model format (m)
- return HumanTimeConverter.humanTimeToSeconds(data, {hours: true})/60;
- });
-
- ngModelController.$formatters.push(function(data) {
- //convert data from model format (m) to view format (hh:mm)
- return HumanTimeConverter.secondsToHumanTime(data*60,
- { seconds: 'disabled',
- hours: 'enabled' }
- );
- });
- }
- };
- }
-])
-
-.directive('osFocusMe', [
- '$timeout',
- function ($timeout) {
- return {
- link: function (scope, element, attrs, model) {
- $timeout(function () {
- element[0].focus();
- });
- }
- };
- }
-])
-
-.filter('toArray', function(){
- /*
- * Transforms an object to an array. Items of the array are the values of
- * the object elements.
- */
- return function(obj) {
- var result = [];
- angular.forEach(obj, function(val, key) {
- result.push(val);
- });
- return result;
- };
-})
-
-//Mark all core config strings for translation in Javascript
-.config([
- 'gettext',
- function (gettext) {
- gettext('Presentation and assembly system');
- gettext('Event name');
- gettext('OpenSlides is a free ' +
- 'web based presentation and assembly system for visualizing ' +
- 'and controlling agenda, motions and elections of an ' +
- 'assembly.');
- gettext('General');
- gettext('Event');
- gettext('Short description of event');
- gettext('Event date');
- gettext('Event location');
- gettext('Event organizer');
- gettext('Legal notice');
- gettext('Privacy policy');
- gettext('Front page title');
- gettext('Welcome to OpenSlides');
- gettext('Front page text');
- gettext('[Space for your welcome text.]');
- gettext('Allow access for anonymous guest users');
- gettext('Show this text on the login page');
- gettext('Separator used for all csv exports and examples');
- gettext('Page number alignment in PDF');
- gettext('Left');
- gettext('Center');
- gettext('Right');
- gettext('Standard font size in PDF');
- gettext('Show logo on projector');
- gettext('You can replace the logo by uploading an image and set it as ' +
- 'the "Projector logo" in "files".');
- gettext('Projector');
- gettext('Projector language');
- gettext('Current browser language');
- gettext('Show title and description of event on projector');
- gettext('Display header and footer');
- gettext('Show the clock on projector');
- gettext('Background color of projector header and footer');
- gettext('Font color of projector header and footer');
- gettext('Font color of projector headline');
- gettext('Predefined seconds of new countdowns');
- gettext('Color for blanked projector');
- gettext('List of speakers overlay');
- gettext('Projector logo');
- gettext('Projector header image');
- gettext('PDF header logo (left)');
- gettext('PDF header logo (right)');
- gettext('PDF footer logo (left)');
- gettext('PDF footer logo (right)');
- gettext('Web interface header logo');
- gettext('PDF ballot paper logo');
- gettext('Custom translations');
-
- // Mark the string 'Default projector' here, because it does not appear in the templates.
- gettext('Default projector');
- }
-]);
-
-}());
diff --git a/openslides/core/static/js/core/start.js b/openslides/core/static/js/core/start.js
deleted file mode 100644
index 6eeba1f58..000000000
--- a/openslides/core/static/js/core/start.js
+++ /dev/null
@@ -1,117 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.core.start', [])
-
-.factory('OpenSlides', [
- '$http',
- '$rootScope',
- '$state',
- '$q',
- 'DS',
- 'autoupdate',
- 'operator',
- 'Group',
- 'mainMenu',
- 'ngDialog',
- 'LoginDialog',
- function($http, $rootScope, $state, $q, DS, autoupdate, operator, Group, mainMenu, ngDialog, LoginDialog) {
- var OpenSlides = {
- bootup: function () {
- $rootScope.openslidesBootstrapDone = false;
- $http.get('/users/whoami/').then(function (success) {
- $rootScope.guest_enabled = success.data.guest_enabled;
- if (success.data.user_id === null && !success.data.guest_enabled) {
- // Redirect to login dialog if user is not logged in.
- $state.go('login', {guest_enabled: success.data.guest_enabled});
- } else {
- autoupdate.newConnect();
- autoupdate.firstMessageDeferred.promise.then(function () {
- operator.setUser(success.data.user_id, success.data.user);
- $rootScope.operator = operator;
- mainMenu.updateMainMenu();
- $rootScope.openslidesBootstrapDone = true;
- });
- }
- });
- },
- shutdown: function () {
- // Close connection, clear the store and show the OS overlay.
- autoupdate.closeConnection();
- DS.clear();
- operator.setUser(null);
- $rootScope.openslidesBootstrapDone = false;
- $rootScope.operator = operator;
- // close all open dialogs (except the login dialog)
- _.forEach(ngDialog.getOpenDialogs(), function (id) {
- if (id !== LoginDialog.id) {
- ngDialog.close(id);
- }
- });
- },
- reboot: function () {
- this.shutdown();
- this.bootup();
- },
- };
-
- // We need to 'ping' the server with a get request to whoami, because then we can decide,
- // if the server is down or respond with a 403 (this cannot be differentiated with websockets)
- autoupdate.registerRetryConnectCallback(function () {
- return $http.get('/users/whoami').then(function (success) {
- if (success.data.user_id === null && !success.data.guest_enabled) {
- OpenSlides.shutdown();
- // Redirect to login dialog if user is not logged in.
- $state.go('login', {guest_enabled: success.data.guest_enabled});
- } else {
- autoupdate.newConnect();
- }
- });
- });
-
- return OpenSlides;
- }
-])
-
-.run([
- 'OpenSlides',
- function (OpenSlides) {
- OpenSlides.bootup();
- }
-])
-
-.run([
- '$rootScope',
- '$state',
- 'operator',
- 'User',
- 'Group',
- 'mainMenu',
- function ($rootScope, $state, operator, User, Group, mainMenu) {
- var permissionChangeCallback = function () {
- operator.reloadPerms();
- mainMenu.updateMainMenu();
- var stateData = $state.current.data;
- var basePerm = stateData ? stateData.basePerm : '';
- $rootScope.baseViewPermissionsGranted = basePerm ?
- operator.hasPerms(basePerm) : true;
- };
-
- $rootScope.$watch(function () {
- return Group.lastModified();
- }, function () {
- if (Group.getAll().length) {
- permissionChangeCallback();
- }
- });
-
- $rootScope.$watch(function () {
- return operator.user ? User.lastModified(operator.user.id) : true;
- }, function () {
- permissionChangeCallback();
- });
- }
-]);
-
-}());
diff --git a/openslides/core/static/templates/config-form-field.html b/openslides/core/static/templates/config-form-field.html
deleted file mode 100644
index 756bd441f..000000000
--- a/openslides/core/static/templates/config-form-field.html
+++ /dev/null
@@ -1,152 +0,0 @@
-
diff --git a/openslides/core/static/templates/config.html b/openslides/core/static/templates/config.html
deleted file mode 100644
index d670f212a..000000000
--- a/openslides/core/static/templates/config.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
{{ subgroup.name | translate }}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/core/checkbox-buttons.html b/openslides/core/static/templates/core/checkbox-buttons.html
deleted file mode 100644
index a8feb84ed..000000000
--- a/openslides/core/static/templates/core/checkbox-buttons.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/openslides/core/static/templates/core/checkbox.html b/openslides/core/static/templates/core/checkbox.html
deleted file mode 100644
index da3bf5403..000000000
--- a/openslides/core/static/templates/core/checkbox.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- {{to.label}}
- {{to.required ? '*' : ''}}
-
-
diff --git a/openslides/core/static/templates/core/countdown-detail.html b/openslides/core/static/templates/core/countdown-detail.html
deleted file mode 100644
index c73252506..000000000
--- a/openslides/core/static/templates/core/countdown-detail.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
{{ countdown.seconds | osSecondsToTime}}
-
-
-
- {{ countdown.description }}
-
-
-
-
-
diff --git a/openslides/core/static/templates/core/editor.html b/openslides/core/static/templates/core/editor.html
deleted file mode 100644
index 13fd511d8..000000000
--- a/openslides/core/static/templates/core/editor.html
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/openslides/core/static/templates/core/file.html b/openslides/core/static/templates/core/file.html
deleted file mode 100644
index a303b22d1..000000000
--- a/openslides/core/static/templates/core/file.html
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/openslides/core/static/templates/core/login-form.html b/openslides/core/static/templates/core/login-form.html
deleted file mode 100644
index c33858d59..000000000
--- a/openslides/core/static/templates/core/login-form.html
+++ /dev/null
@@ -1,30 +0,0 @@
-
diff --git a/openslides/core/static/templates/core/manage-projectors.html b/openslides/core/static/templates/core/manage-projectors.html
deleted file mode 100644
index f9b3829ee..000000000
--- a/openslides/core/static/templates/core/manage-projectors.html
+++ /dev/null
@@ -1,219 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Name :
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ projector.scale }}
-
-
-
-
{{ projector.scroll }}
-
-
-
-
-
-
-
- Broadcast
-
-
-
- Blank
-
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/core/password.html b/openslides/core/static/templates/core/password.html
deleted file mode 100644
index da77f0bfb..000000000
--- a/openslides/core/static/templates/core/password.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/openslides/core/static/templates/core/projector-controls.html b/openslides/core/static/templates/core/projector-controls.html
deleted file mode 100644
index 828321c3f..000000000
--- a/openslides/core/static/templates/core/projector-controls.html
+++ /dev/null
@@ -1,312 +0,0 @@
-
-
-
-
-
-
-
- Live view
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ active_projector.scale }}
-
-
-
-
{{ active_projector.scroll }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/core/projector-message-form.html b/openslides/core/static/templates/core/projector-message-form.html
deleted file mode 100644
index 39acae226..000000000
--- a/openslides/core/static/templates/core/projector-message-form.html
+++ /dev/null
@@ -1,12 +0,0 @@
-Edit message
-
-
diff --git a/openslides/core/static/templates/core/radio-buttons.html b/openslides/core/static/templates/core/radio-buttons.html
deleted file mode 100644
index 528179ed8..000000000
--- a/openslides/core/static/templates/core/radio-buttons.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/openslides/core/static/templates/core/select-multiple.html b/openslides/core/static/templates/core/select-multiple.html
deleted file mode 100644
index 93e9fa1ad..000000000
--- a/openslides/core/static/templates/core/select-multiple.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/openslides/core/static/templates/core/select-single.html b/openslides/core/static/templates/core/select-single.html
deleted file mode 100644
index 67e7978b1..000000000
--- a/openslides/core/static/templates/core/select-single.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/openslides/core/static/templates/core/slide_clock.html b/openslides/core/static/templates/core/slide_clock.html
deleted file mode 100644
index ff12cb007..000000000
--- a/openslides/core/static/templates/core/slide_clock.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- {{ servertime | date:'HH:mm' }}
-
diff --git a/openslides/core/static/templates/core/slide_countdown.html b/openslides/core/static/templates/core/slide_countdown.html
deleted file mode 100644
index 47d519abd..000000000
--- a/openslides/core/static/templates/core/slide_countdown.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- {{ countdown.seconds | osSecondsToTime}}
-
{{ countdown.description }}
-
-
diff --git a/openslides/core/static/templates/core/slide_message.html b/openslides/core/static/templates/core/slide_message.html
deleted file mode 100644
index 0ea8c2a0f..000000000
--- a/openslides/core/static/templates/core/slide_message.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/openslides/core/static/templates/core/tag-form.html b/openslides/core/static/templates/core/tag-form.html
deleted file mode 100644
index d76e8c114..000000000
--- a/openslides/core/static/templates/core/tag-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-Edit tag
-New tag
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/core/static/templates/core/tag-list.html b/openslides/core/static/templates/core/tag-list.html
deleted file mode 100644
index f119f14e7..000000000
--- a/openslides/core/static/templates/core/tag-list.html
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
- Name
-
-
-
-
-
- {{ tag.name }}
-
-
-
diff --git a/openslides/core/static/templates/csv-import.html b/openslides/core/static/templates/csv-import.html
deleted file mode 100644
index 54eb63efe..000000000
--- a/openslides/core/static/templates/csv-import.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
diff --git a/openslides/core/static/templates/home.html b/openslides/core/static/templates/home.html
deleted file mode 100644
index 46e7040e3..000000000
--- a/openslides/core/static/templates/home.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
diff --git a/openslides/core/static/templates/index.html b/openslides/core/static/templates/index.html
deleted file mode 100644
index c049346e8..000000000
--- a/openslides/core/static/templates/index.html
+++ /dev/null
@@ -1,279 +0,0 @@
-
-
-
-
-
-OpenSlides
-{{ activeAppTitle | translate }} – OpenSlides
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/legalnotice.html b/openslides/core/static/templates/legalnotice.html
deleted file mode 100644
index 68e2e77b9..000000000
--- a/openslides/core/static/templates/legalnotice.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
diff --git a/openslides/core/static/templates/messaging.html b/openslides/core/static/templates/messaging.html
deleted file mode 100644
index f12308dcc..000000000
--- a/openslides/core/static/templates/messaging.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/openslides/core/static/templates/privacypolicy.html b/openslides/core/static/templates/privacypolicy.html
deleted file mode 100644
index 3a5293d19..000000000
--- a/openslides/core/static/templates/privacypolicy.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/openslides/core/static/templates/privacypolicydialog.html b/openslides/core/static/templates/privacypolicydialog.html
deleted file mode 100644
index a314af267..000000000
--- a/openslides/core/static/templates/privacypolicydialog.html
+++ /dev/null
@@ -1,9 +0,0 @@
-Privacy policy
-
-
- The event manager hasn't set up a privacy policy yet.
-
-
-
- Close
-
diff --git a/openslides/core/static/templates/projector-button.html b/openslides/core/static/templates/projector-button.html
deleted file mode 100644
index ab236c6c2..000000000
--- a/openslides/core/static/templates/projector-button.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- {{ content | translate }}
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/projector-container.html b/openslides/core/static/templates/projector-container.html
deleted file mode 100644
index 4c58e9777..000000000
--- a/openslides/core/static/templates/projector-container.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-Projector – OpenSlides
-{{ 'Projector' | translate }} {{ projectorName }} – OpenSlides
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ error | translate }}
-
-
-
-
-
diff --git a/openslides/core/static/templates/projector.html b/openslides/core/static/templates/projector.html
deleted file mode 100644
index c28cf4f52..000000000
--- a/openslides/core/static/templates/projector.html
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-OpenSlides – Projector
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/core/static/templates/search.html b/openslides/core/static/templates/search.html
deleted file mode 100644
index b229c09a0..000000000
--- a/openslides/core/static/templates/search.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
- {{ filter.verboseName | translate }}
-
-
-
-
diff --git a/openslides/core/views.py b/openslides/core/views.py
index 081d2dbc7..383962a55 100644
--- a/openslides/core/views.py
+++ b/openslides/core/views.py
@@ -1,21 +1,23 @@
-import json
+import os
import uuid
-from textwrap import dedent
-from typing import Any, Dict, List, cast
+from typing import Any, Dict, List
-from django.apps import apps
from django.conf import settings
+from django.contrib.staticfiles import finders
+from django.contrib.staticfiles.views import serve
from django.db.models import F
from django.http import Http404, HttpResponse
from django.utils.timezone import now
from django.utils.translation import ugettext as _
+from django.views import static
+from django.views.generic.base import View
from mypy_extensions import TypedDict
from .. import __license__ as license, __url__ as url, __version__ as version
from ..utils import views as utils_views
+from ..utils.arguments import arguments
from ..utils.auth import anonymous_is_enabled, has_perm
from ..utils.autoupdate import inform_changed_data, inform_deleted_data
-from ..utils.constants import get_constants
from ..utils.plugins import (
get_plugin_description,
get_plugin_license,
@@ -53,132 +55,38 @@ from .models import (
# Special Django views
-class IndexView(utils_views.CSRFMixin, utils_views.TemplateView):
+class IndexView(View):
"""
- The primary view for OpenSlides using AngularJS.
-
- The default base template is 'openslides/core/static/templates/index.html'.
- You can override it by simply adding a custom 'templates/index.html' file
- to the custom staticfiles directory. See STATICFILES_DIRS in settings.py.
+ The primary view for the OpenSlides client. Serves static files. If a file
+ does not exist or a directory is requested, the index.html is delivered instead.
"""
- template_name = 'templates/index.html'
-
-class ProjectorView(utils_views.TemplateView):
- """
- The primary view for OpenSlides projector using AngularJS.
-
- The projector container template is 'openslides/core/static/templates/projector-container.html'.
- This container is for controlling the projector resolution.
- """
- template_name = 'templates/projector-container.html'
-
-
-class RealProjectorView(utils_views.TemplateView):
- """
- The original view without resolutioncontrol for OpenSlides projector using AngularJS.
-
- The default base template is 'openslides/core/static/templates/projector.html'.
- You can override it by simply adding a custom 'templates/projector.html'
- file to the custom staticfiles directory. See STATICFILES_DIRS in
- settings.py.
- """
- template_name = 'templates/projector.html'
-
-
-class WebclientJavaScriptView(utils_views.View):
- """
- This view returns JavaScript code for the main entry point in the
- AngularJS app for the requested realm (site or projector). Also code
- for plugins is appended. The result is not uglified.
- """
cache: Dict[str, str] = {}
+ """
+ Saves the path to the index.html.
+
+ May be extended later to cache every template.
+ """
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
- if 'site' not in self.cache:
- self.init_cache('site')
- if 'projector' not in self.cache:
- self.init_cache('projector')
+ no_caching = arguments.get('no_template_caching', False)
+ if 'index' not in self.cache or no_caching:
+ self.cache['index'] = finders.find('index.html')
- def init_cache(self, realm: str) -> None:
- angular_modules: List[str] = []
- js_files: List[str] = []
- for app_config in apps.get_app_configs():
- # Add the angular app if the module has one.
- if getattr(app_config, 'angular_{}_module'.format(realm), False):
- angular_modules.append('OpenSlidesApp.{app_name}.{realm}'.format(
- app_name=app_config.label,
- realm=realm))
+ self.index_document_root, self.index_path = os.path.split(self.cache['index'])
- # Add all JavaScript files that the module needs. Our core apps
- # are delivered by an extra file js/openslides.js which can be
- # created via gulp.
- core_apps = (
- 'openslides.core',
- 'openslides.agenda',
- 'openslides.motions',
- 'openslides.assignments',
- 'openslides.users',
- 'openslides.mediafiles',
- )
- if app_config.name not in core_apps:
- try:
- app_js_files = app_config.js_files
- except AttributeError:
- # The app needs no JavaScript files.
- pass
- else:
- js_files.extend(app_js_files)
-
- # angular constants
- angular_constants = ''
- for key, value in get_constants().items():
- value = json.dumps(value)
- angular_constants += ".constant('{}', {})".format(key, value)
-
- # Use JavaScript loadScript function from
- # http://balpha.de/2011/10/jquery-script-insertion-and-its-consequences-for-debugging/
- # jQuery is required.
- content = dedent(
- """
- (function () {
- var loadScript = function (path) {
- var result = $.Deferred(),
- script = document.createElement("script");
- script.async = "async";
- script.type = "text/javascript";
- script.src = path;
- script.onload = script.onreadystatechange = function(_, isAbort) {
- if (!script.readyState || /loaded|complete/.test(script.readyState)) {
- if (isAbort)
- result.reject();
- else
- result.resolve();
- }
- };
- script.onerror = function () { result.reject(); };
- $("head")[0].appendChild(script);
- return result.promise();
- };
- """ +
- """
- angular.module('OpenSlidesApp.{realm}', {angular_modules}){angular_constants};
- var deferres = [];
- {js_files}.forEach( function(js_file) {{ deferres.push(loadScript(js_file)); }} );
- $.when.apply(this,deferres).done( function() {{
- angular.bootstrap(document,['OpenSlidesApp.{realm}']);
- }} );
- """.format(realm=realm, angular_modules=angular_modules, angular_constants=angular_constants, js_files=js_files) +
- """
- }());
- """).replace('\n', '')
- self.cache[realm] = content
-
- def get(self, *args: Any, **kwargs: Any) -> HttpResponse:
- realm = cast(str, kwargs.get('realm')) # Result is 'site' or 'projector'
- return HttpResponse(self.cache[realm], content_type='application/javascript')
+ def get(self, request, path, **kwargs) -> HttpResponse:
+ """
+ Tries to serve the requested file. If it is not found or a directory is
+ requested, the index.html is delivered.
+ """
+ try:
+ response = serve(request, path, **kwargs)
+ except Http404:
+ response = static.serve(request, self.index_path, document_root=self.index_document_root, **kwargs)
+ return response
# Viewsets for the REST API
diff --git a/openslides/mediafiles/static/css/mediafiles/_image-browser.scss b/openslides/mediafiles/static/css/mediafiles/_image-browser.scss
deleted file mode 100644
index 89964deb1..000000000
--- a/openslides/mediafiles/static/css/mediafiles/_image-browser.scss
+++ /dev/null
@@ -1,67 +0,0 @@
-/** image plugin for CKEditor **/
-#imageBrowserContainer {
- .imageTable {
- table-layout: fixed;
- width: 100%;
- }
-
- #imagePreviewSection {
- position: absolute;
- margin: 0px 20px 20px 20px;
-
- input {
- width: 65px;
- }
-
- .hidden {
- display: none;
- }
-
- i {
- font-size: 130%;
- cursor: pointer;
- }
-
- > div {
- margin-bottom: 10px;
- }
- }
-
- #imagePreview {
- max-width: 400px;
- max-height: 300px;
- overflow: auto;
- padding: 2px;
- border: 3px solid #317796;
-
- img[src=""] {
- display: none;
- }
- }
-
- #imageBrowser {
- max-height: 500px;
- overflow: auto;
-
- .image {
- position: relative;
- float: left;
- width: 75px;
- height: 75px;
- margin: 5px;
- background-size: 125%;
- background-repeat: no-repeat;
- background-position: center center;
- border: 2px solid #bed4de;
- cursor: pointer;
-
- &:hover {
- border-color: #317796;
- }
-
- &.selected {
- border-color: #317796;
- }
- }
- }
-}
diff --git a/openslides/mediafiles/static/css/mediafiles/_projector.scss b/openslides/mediafiles/static/css/mediafiles/_projector.scss
deleted file mode 100644
index b2f1a2ded..000000000
--- a/openslides/mediafiles/static/css/mediafiles/_projector.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-/* PDF presentation */
-.rotate0 {
- transform: rotate(0deg);
-}
-.rotate90 {
- transform: rotate(90deg);
-}
-.rotate180 {
- transform: rotate(180deg);
-}
-.rotate270 {
- transform: rotate(270deg);
-}
-
-/* Video and Image projection */
-img.projector-image {
- width: 100%;
-}
-
-div.projector-image {
- width: 100%;
- height: 100%;
- background-size: contain;
- background-repeat: no-repeat;
- background-position: 50% 50%;
- background-color: #fff;
-}
-
-.video-container {
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
-
- & > * {
- flex: 1 1 auto;
- max-width: 100%;
- max-height: 100%;
- width: 100%;
- height: 100%;
- }
-}
diff --git a/openslides/mediafiles/static/css/mediafiles/_site.scss b/openslides/mediafiles/static/css/mediafiles/_site.scss
deleted file mode 100644
index 81a9f3aaa..000000000
--- a/openslides/mediafiles/static/css/mediafiles/_site.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-@import "image-browser";
-
-#mediafile-table {
- .icon-column {
- width: 10%;
- }
- .title-column {
- padding: 0px 10px;
- width: 90%;
- }
-}
-
-#dropzone {
- padding: 20px 10px;
- border-radius: 4px;
- border: 1px solid #e6e8eb;
- text-align: center;
- background-color: #fff;
-
- &.dragover {
- border-color: #317796;
- }
-}
diff --git a/openslides/mediafiles/static/js/mediafiles/forms.js b/openslides/mediafiles/static/js/mediafiles/forms.js
deleted file mode 100644
index 8e9124609..000000000
--- a/openslides/mediafiles/static/js/mediafiles/forms.js
+++ /dev/null
@@ -1,73 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.forms', [
- 'gettext',
- 'ngFileUpload',
- 'ui.router',
- //TODO: Add deps for operator, User
-])
-
-// Service for mediafile form
-.factory('MediafileForm', [
- 'gettextCatalog',
- 'operator',
- 'User',
- function (gettextCatalog, operator, User) {
- return {
- // ngDialog for mediafile form
- getDialog: function (mediafile) {
- var dialog = {
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- };
- if (mediafile) {
- dialog.template = 'static/templates/mediafiles/mediafile-form.html';
- dialog.controller = 'MediafileUpdateCtrl';
- dialog.resolve = {
- mediafileId: function () {return mediafile ? mediafile.id : void 0;}
- };
- } else {
- dialog.template = 'static/templates/mediafiles/mediafile-upload-form.html';
- dialog.controller = 'MediafileUploadCtrl';
- }
- return dialog;
- },
- getFormFields: function () {
- return [
- {
- key: 'title',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Title'),
- },
- },
- {
- key: 'hidden',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Hidden'),
- },
- hide: !operator.hasPerms('mediafiles.can_see_hidden'),
- },
- {
- key: 'uploader_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Uploaded by'),
- options: User.getAll(),
- ngOptions: 'option.id as option.full_name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a participant ...')
- },
- hide: !operator.hasPerms('mediafiles.can_manage')
- },
- ];
-
- }
- };
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/image-plugin.js b/openslides/mediafiles/static/js/mediafiles/image-plugin.js
deleted file mode 100644
index 169397204..000000000
--- a/openslides/mediafiles/static/js/mediafiles/image-plugin.js
+++ /dev/null
@@ -1,206 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.image-plugin', [
- 'OpenSlidesApp.mediafiles.resources',
- 'gettext',
- 'OpenSlidesApp.core',
-])
-
-.factory('ImageBrowserPlugin', [
- '$templateCache',
- 'Mediafile',
- 'gettextCatalog',
- 'Editor',
- function ($templateCache, Mediafile, gettextCatalog, Editor) {
- return {
- getPlugin: function () {
- return {
- init: function (editor) {
- CKEDITOR.tools.imagebrowser = {};
-
- // Initialize this dialog, if it is opened.
- editor.on('dialogShow', function (event) {
- var dialog = event.data;
- if (dialog.getName() === 'imagebrowser-dialog') {
- CKEDITOR.dialog.getCurrent().disableButton('ok');
-
- // Load the main plugin template and paste it into the container
- var template = $templateCache.get('mediafiles/static/templates/mediafiles/image-plugin.html');
- if (!template) {
- throw 'Template for image plugin not found!';
- }
- $('#imageBrowserContainer').html(template);
-
- // Load all images.
- var images = '';
- _.forEach(Mediafile.getAllImages(), function (image) {
- images += '
';
- });
- $('#imageBrowser').html(images);
-
- // Translate some strings. Angular tags are not available in CKEditor.
- $('#scaleLabel').html(gettextCatalog.getString('Scale'));
-
- // If the dialog was opened via double click, check the selected element. It
- // may be an image, so preselect it.
- var selectedElement = editor.getSelection().getStartElement();
- if (selectedElement.is('img')) {
- // Check for given scale of this image.
- var styleAttr = $(selectedElement).attr('style');
- var scale;
- var scaleRegex = /width\s*:\s*(\d+)\s*%/g;
- var scaleMatch = scaleRegex.exec(styleAttr);
- if (scaleMatch) {
- scale = parseInt(scaleMatch[1]);
- }
- CKEDITOR.tools.imagebrowser.selectImage(
- selectedElement.getAttribute('src'), scale);
- }
- // Setup event listeners.
- $('#image-scale').bind('keyup mouseup', function (event) {
- var scale = parseInt($('#image-scale').val());
- if (scale !== CKEDITOR.tools.imagebrowser.scale) {
- CKEDITOR.tools.imagebrowser.updateImageSize(scale);
- }
- });
-
- // Hack: call the resize event, so the dom does an update.
- CKEDITOR.tools.callFunction(224, {});
- }
- });
- // React on double clicks in the textarea. If an image was selected, open this dialog.
- editor.on('doubleclick', function (event) {
- var element = event.data.element;
- if (!element.isReadOnly()) {
- if (element.is('img')) {
- event.data.dialog = 'imagebrowser-dialog';
- editor.getSelection().selectElement(element);
- }
- }
- });
- // Handler for selecting an image. It may be called by clicking on a thumbnail or by
- // just giving the url. The scale is optional.
- CKEDITOR.tools.imagebrowser.selectImage = function (url, scale) {
- var browser = $('#imageBrowser');
- _.forEach(browser.children(), function (child) { // check every available image
- if (child.getAttribute('data-image') == url) { //match
- child.classList.add('selected');
- var image = $('#imagePreview img');
- // Setup an load event handler, so we can get the size of the image when loaded.
- image.on('load', function (event) {
- var w = event.target.naturalWidth;
- var h = event.target.naturalHeight;
- $('#originalSizeText').html(gettextCatalog.getString('Original size') +
- ': ' + w + ' × ' + h );
- $('#fullSizeContainer').width(w).height(h);
- if (scale !== undefined) {
- // Use custom scale.
- CKEDITOR.tools.imagebrowser.updateImageSize(scale);
- } else {
- CKEDITOR.tools.imagebrowser.updateImageSize(100);
- }
- });
- // Set the url of the main preview image.
- image.attr('src', url);
- $('#imagePreviewSection').removeClass('hidden');
- CKEDITOR.tools.imagebrowser.selected = url;
- } else {
- // Wrong image, deselect it in the preview window.
- child.classList.remove('selected');
- }
- });
- };
- // Handler for updateing the image size.
- CKEDITOR.tools.imagebrowser.updateImageSize = function (scale) {
- if (isNaN(scale) || scale <= 0) {
- CKEDITOR.dialog.getCurrent().disableButton('ok');
- } else {
- CKEDITOR.dialog.getCurrent().enableButton('ok');
- CKEDITOR.tools.imagebrowser.scale = scale;
- $('#imagePreview img').width(scale + '%');
- $('#image-scale').val(scale);
- }
- };
- // Insert the selected image into the textarea.
- CKEDITOR.tools.imagebrowser.insertImage = function (url, scale) {
- var editor = CKEDITOR.currentInstance;
- var dialog = CKEDITOR.dialog.getCurrent();
- var html = '
';
- editor.config.allowedContent = true;
- editor.insertHtml(html.trim());
- dialog.hide();
- };
- editor.addCommand('imagebrowser-open', new CKEDITOR.dialogCommand('imagebrowser-dialog'));
- // By naming the button 'image', it gets the same image as the original image button.
- editor.ui.addButton('image', {
- label: gettextCatalog.getString('Open image browser'),
- command: 'imagebrowser-open',
- toolbar: 'insert',
- });
- },
- };
- },
- getDialog: function () {
- return function (editor) {
- return {
- title: gettextCatalog.getString('Image browser'),
- minWidth: 1000,
- minHeight: 500,
- contents: [
- {
- id: 'imagebrowser-tab1',
- label: gettextCatalog.getString('Browse for images'),
- elements: [
- {
- type: 'html',
- align: 'left',
- id: 'titleid',
- style: 'font-size: 20px; font-weight: bold;',
- html: gettextCatalog.getString('Browse for images'),
- }, {
- type: 'html',
- align: 'left',
- id: 'msg',
- style: '',
- html: '
'
- }
- ],
- },
- ],
- // insert image on OK.
- onOk: function (event) {
- var url = CKEDITOR.tools.imagebrowser.selected;
- if (url) {
- var scale = CKEDITOR.tools.imagebrowser.scale;
- CKEDITOR.tools.imagebrowser.insertImage(url, scale);
- }
- },
- };
- };
- },
- };
- }
-])
-
-.run([
- 'Editor',
- 'ImageBrowserPlugin',
- 'gettext',
- function (Editor, ImageBrowserPlugin, gettext) {
- Editor.registerDialog('imagebrowser-dialog', ImageBrowserPlugin.getDialog());
- Editor.registerPlugin('imagebrowser', ImageBrowserPlugin.getPlugin());
-
- // mark all plugin strings
- gettext('Original size');
- gettext('Scale');
- gettext('Image browser');
- gettext('Browse for images');
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/list.js b/openslides/mediafiles/static/js/mediafiles/list.js
deleted file mode 100644
index 74231b35e..000000000
--- a/openslides/mediafiles/static/js/mediafiles/list.js
+++ /dev/null
@@ -1,293 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.list', [
- 'gettext',
- 'ngDialog',
- 'OpenSlidesApp.mediafiles.forms',
- 'OpenSlidesApp.mediafiles.resources',
- //TODO: Add deps for operator, User, Projector, ProjectionDefault, osTableFilter, osTableSort,
-])
-
-.controller('MediafileListCtrl', [
- '$http',
- '$scope',
- 'gettext',
- 'ngDialog',
- 'osTableFilter',
- 'osTableSort',
- 'osTablePagination',
- 'ProjectionDefault',
- 'Projector',
- 'User',
- 'Mediafile',
- 'MediafileForm',
- 'Logos',
- 'Fonts',
- function ($http, $scope, gettext, ngDialog, osTableFilter, osTableSort, osTablePagination,
- ProjectionDefault, Projector, User, Mediafile, MediafileForm, Logos, Fonts) {
- $scope.$watch(function () {
- return Mediafile.lastModified();
- }, function () {
- $scope.mediafiles = _.orderBy(Mediafile.getAll(), ['title']);
- });
- User.bindAll({}, $scope, 'users');
- $scope.$watch(function() {
- return Projector.lastModified();
- }, function() {
- $scope.projectors = Projector.getAll();
- updatePresentedMediafiles();
- var projectiondefault = ProjectionDefault.filter({name: 'mediafiles'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
-
- function updatePresentedMediafiles () {
- $scope.presentedMediafiles = [];
- Projector.getAll().forEach(function (projector) {
- var projectorElements = _.map(projector.elements, function(element) { return element; });
- var mediaElements = _.filter(projectorElements, function (element) {
- return element.name === 'mediafiles/mediafile';
- });
- mediaElements.forEach(function (element) {
- $scope.presentedMediafiles.push(element);
- });
- });
- if ($scope.presentedMediafiles.length) {
- $scope.isMeta = false;
- } else {
- $scope.isMeta = true;
- }
- }
-
- updatePresentedMediafiles();
-
- // Filtering
- $scope.filter = osTableFilter.createInstance('MediafilesTableFilter');
-
- if (!$scope.filter.existsStorageEntry()) {
- $scope.filter.booleanFilters = {
- isHidden: {
- value: undefined,
- displayName: gettext('Hidden'),
- choiceYes: gettext('Is hidden'),
- choiceNo: gettext('Is not hidden'),
- needExtraPermission: true,
- },
- isPdf: {
- value: undefined,
- displayName: gettext('Is PDF'),
- choiceYes: gettext('Is PDF file'),
- choiceNo: gettext('Is no PDF file'),
- },
- };
- }
- $scope.filter.propertyList = ['title_or_filename'];
- $scope.filter.propertyFunctionList = [
- function (mediafile) {return mediafile.uploader.get_short_name();},
- function (mediafile) {return mediafile.mediafile.type;},
- function (mediafile) {return mediafile.mediafile.name;},
- ];
- // Sorting
- $scope.sort = osTableSort.createInstance('MediafileTableSort');
- if (!$scope.sort.column) {
- $scope.sort.column = 'title_or_filename';
- }
- $scope.sortOptions = [
- {name: 'title_or_filename',
- display_name: gettext('Title')},
- {name: 'mediafile.type',
- display_name: gettext('Type')},
- {name: 'filesize',
- display_name: gettext('File size')},
- {name: 'timestamp',
- display_name: gettext('Upload time')},
- {name: 'uploader.get_short_name()',
- display_name: gettext('Uploaded by')},
- ];
-
- // pagination
- $scope.pagination = osTablePagination.createInstance('MediafileTablePagination');
-
- // open new/edit dialog
- $scope.openDialog = function (mediafile) {
- ngDialog.open(MediafileForm.getDialog(mediafile));
- };
-
- // *** select mode functions ***
- $scope.isSelectMode = false;
- // check all checkboxes
- $scope.checkAll = function () {
- $scope.selectedAll = !$scope.selectedAll;
- _.forEach($scope.mediafiles, function (mediafile) {
- mediafile.selected = $scope.selectedAll;
- });
- };
- // uncheck all checkboxes if SelectMode is closed
- $scope.uncheckAll = function () {
- if (!$scope.isSelectMode) {
- $scope.selectedAll = false;
- _.forEach($scope.mediafiles, function (mediafile) {
- mediafile.selected = false;
- });
- }
- };
- // delete all selected mediafiles
- $scope.deleteMultiple = function () {
- angular.forEach($scope.mediafiles, function (mediafile) {
- if (mediafile.selected)
- Mediafile.destroy(mediafile.id);
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // delete single mediafile
- $scope.delete = function (mediafile) {
- Mediafile.destroy(mediafile.id);
- };
-
- // ** PDF presentation functions **/
- // show document on projector
- $scope.showMediafile = function (projectorId, mediafile) {
- var isProjectedIds = mediafile.isProjected();
- _.forEach(isProjectedIds, function (id) {
- $http.post('/rest/core/projector/' + id + '/clear_elements/');
- });
- if (_.indexOf(isProjectedIds, projectorId) == -1) {
- var postUrl = '/rest/core/projector/' + projectorId + '/prune_elements/';
- var data = [{
- name: 'mediafiles/mediafile',
- id: mediafile.id,
- numPages: mediafile.mediafile.pages,
- page: 1,
- scale: 'page-fit',
- rotate: 0,
- visible: true,
- playing: false,
- fullscreen: mediafile.is_pdf || mediafile.is_image
- }];
- $http.post(postUrl, data);
- }
- };
-
- var sendMediafileCommand = function (mediafile, data) {
- var updateData = _.extend({}, mediafile);
- _.extend(updateData, data);
- var postData = {};
- postData[mediafile.uuid] = updateData;
-
- // Find Projector where the mediafile is projected
- $scope.projectors.forEach(function (projector) {
- if (_.find(projector.elements, function (e) {return e.uuid == mediafile.uuid;})) {
- $http.post('/rest/core/projector/' + projector.id + '/update_elements/', postData);
- }
- });
- };
-
- $scope.getTitle = function (mediafile) {
- return Mediafile.get(mediafile.id).title;
- };
-
- $scope.getType = function (presentedMediafile) {
- var mediafile = Mediafile.get(presentedMediafile.id);
- return mediafile.is_pdf ? 'pdf' : mediafile.is_image ? 'image' : 'video';
- };
-
- $scope.mediafileGoToPage = function (mediafile, page) {
- page = parseInt(page);
- if (page > 0 && page <= mediafile.numPages) {
- sendMediafileCommand(
- mediafile,
- {page: page}
- );
- }
- };
- $scope.mediafileZoomIn = function (mediafile) {
- var scale = 1;
- if (parseFloat(mediafile.scale)) {
- scale = mediafile.scale;
- }
- sendMediafileCommand(
- mediafile,
- {scale: scale + 0.2}
- );
- };
- $scope.mediafileFit = function (mediafile) {
- sendMediafileCommand(
- mediafile,
- {scale: 'page-fit'}
- );
- };
- $scope.mediafileZoomOut = function (mediafile) {
- var scale = 1;
- if (parseFloat(mediafile.scale)) {
- scale = mediafile.scale;
- }
- sendMediafileCommand(
- mediafile,
- {scale: scale - 0.2}
- );
- };
- $scope.mediafileChangePage = function (mediafile, pageNum) {
- sendMediafileCommand(
- mediafile,
- {pageToDisplay: pageNum}
- );
- };
- $scope.mediafileRotate = function (mediafile) {
- var rotation = mediafile.rotate;
- if (rotation === 270) {
- rotation = 0;
- } else {
- rotation = rotation + 90;
- }
- sendMediafileCommand(
- mediafile,
- {rotate: rotation}
- );
- };
- $scope.mediafileToggleFullscreen = function (mediafile) {
- sendMediafileCommand(
- mediafile,
- {fullscreen: !mediafile.fullscreen}
- );
- };
- $scope.mediafileTogglePlaying = function (mediafile) {
- sendMediafileCommand(
- mediafile,
- {playing: !mediafile.playing}
- );
- };
-
- /** Logos and fonts **/
- $scope.logos = Logos.getAll();
- $scope.fonts = Fonts.getAll();
- $scope.hasProjectorHeaderLogo = function (mediafile) {
- return _.some(mediafile.getLogos(), function (logo) {
- return logo.key === 'logo_projector_header';
- });
- };
- }
-])
-
-/*
- * Special filter only for mediafile list view.
- */
-.filter('hiddenFilter', [
- '$filter',
- 'operator',
- function ($filter, operator) {
- return function (array) {
- if (operator.hasPerms('mediafiles.can_see_hidden')) {
- return array;
- }
- return Array.prototype.filter.call(array, function (item) {
- return !item.hidden;
- });
- };
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/projector.js b/openslides/mediafiles/static/js/mediafiles/projector.js
deleted file mode 100644
index 175377ae8..000000000
--- a/openslides/mediafiles/static/js/mediafiles/projector.js
+++ /dev/null
@@ -1,70 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.projector', [
- 'OpenSlidesApp.mediafiles.resources',
- //TODO: Add deps for slidesProvider
-])
-
-.config([
- 'slidesProvider',
- function (slidesProvider) {
- slidesProvider.registerSlide('mediafiles/mediafile', {
- template: 'static/templates/mediafiles/slide_mediafile.html'
- });
- }
-])
-
-.controller('SlideMediafileCtrl', [
- '$scope',
- '$timeout',
- 'Mediafile',
- function ($scope, $timeout, Mediafile) {
- // load mediafile object
- Mediafile.bindOne($scope.element.id, $scope, 'mediafile');
-
- $scope.showPdf = true;
-
- // Watch for page changes in the projector element. Adjust the page
- // in the canvas scope, so the viewer can change the size automatically.
- $scope.$watch(function () {
- return $scope.element.page;
- }, function () {
- var canvasScope = angular.element('#pdf-canvas').scope();
- if (canvasScope) {
- canvasScope.pageNum = $scope.element.page;
- }
- });
-
- // Watch for scale changes. If the scale is changed, reload the pdf
- // viewer by just disable and re-enable it.
- $scope.$watch(function () {
- return $scope.element.scale;
- }, function () {
- $scope.showPdf = false;
- $timeout(function () {
- $scope.showPdf = true;
- }, 1);
- });
-
- // Allow the elements to render properly
- setTimeout(function() {
- if ($scope.mediafile) {
- if ($scope.mediafile.is_pdf) {
- $scope.pdfName = $scope.mediafile.title;
- $scope.pdfUrl = $scope.mediafile.mediafileUrl;
- } else if ($scope.mediafile.is_video) {
- var player = angular.element.find('#video-player')[0];
- if ($scope.element.playing) {
- player.play();
- } else {
- player.pause();
- }
- }
- }
- }, 0);
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/resources.js b/openslides/mediafiles/static/js/mediafiles/resources.js
deleted file mode 100644
index 4c7a8b3e9..000000000
--- a/openslides/mediafiles/static/js/mediafiles/resources.js
+++ /dev/null
@@ -1,161 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.resources', [
- 'gettext',
- 'js-data',
- //TODO: Add deps for jsDataModel
-])
-
-.factory('Mediafile', [
- 'DS',
- 'gettext',
- 'jsDataModel',
- 'Logos',
- 'Fonts',
- function (DS, gettext, jsDataModel, Logos, Fonts) {
- var name = 'mediafiles/mediafile';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Files'),
- verboseNamePlural: gettext('Files'),
- getAllImages: function () {
- var images = [];
- angular.forEach(this.getAll(), function(file) {
- if (file.is_image) {
- images.push({title: file.title, value: file.mediafileUrl});
- }
- });
- return images;
- },
- methods: {
- getResourceName: function () {
- return name;
- },
- // link name which is shown in search result
- getSearchResultName: function () {
- return this.title;
- },
- // return true if a specific relation matches for given searchquery
- // (here: speakers)
- hasSearchResult: function (results) {
- var mediafile = this;
- // search for speakers (check if any user.id from already found users matches)
- return _.some(results, function(result) {
- if ((result.getResourceName() === "users/user") &&
- (mediafile.uploader_id === result.id)) {
- return true;
- }
- });
- },
- isUsedAsLogo: function () {
- var mediafile = this;
- return _.find(Logos.getAll(), function (logoPlaceholder) {
- return logoPlaceholder.path === mediafile.mediafileUrl;
- });
- },
- canBeUsedAsLogo: function () {
- return this.is_image;
- },
- getLogos: function () {
- var mediafile = this;
- return _.filter(Logos.getAll(), function (logoPlaceholder) {
- return logoPlaceholder.path === mediafile.mediafileUrl;
- });
- },
- hasLogo: function (logo) {
- var allUrls = _.map(this.getLogos(), function (logo) {
- return logo.path;
- });
- return _.includes(allUrls, logo.path);
- },
- toggleLogo: function (logo) {
- if (this.hasLogo(logo)) {
- Logos.set(logo.key);
- } else {
- Logos.set(logo.key, this.mediafileUrl);
- }
- },
- isUsedAsFont: function () {
- var mediafile = this;
- return _.find(Fonts.getAll(), function (font) {
- return font.path === mediafile.mediafileUrl;
- });
- },
- canBeUsedAsFont: function () {
- return this.is_font;
- },
- getFonts: function () {
- var mediafile = this;
- return _.filter(Fonts.getAll(), function (font) {
- return font.path === mediafile.mediafileUrl;
- });
- },
- hasFont: function (font) {
- var allUrls = _.map(this.getFonts(), function (font) {
- return font.path;
- });
- return _.includes(allUrls, font.path);
- },
- toggleFont: function (font) {
- if (this.hasFont(font)) {
- Fonts.set(font.key);
- } else {
- Fonts.set(font.key, this.mediafileUrl);
- }
- },
- },
- computed: {
- is_pdf: ['filetype', function (filetype) {
- var PDF_FILE_TYPES = ['application/pdf'];
- return _.includes(PDF_FILE_TYPES, filetype);
- }],
- is_image: ['filetype', function (filetype) {
- var IMAGE_FILE_TYPES = ['image/png', 'image/jpeg', 'image/gif'];
- return _.includes(IMAGE_FILE_TYPES, filetype);
- }],
- is_video: ['filetype', function (filetype) {
- var VIDEO_FILE_TYPES = [ 'video/quicktime', 'video/mp4', 'video/webm',
- 'video/ogg', 'video/x-flv', 'application/x-mpegURL', 'video/MP2T',
- 'video/3gpp', 'video/x-msvideo', 'video/x-ms-wmv', 'video/x-matroska' ];
- return _.includes(VIDEO_FILE_TYPES, filetype);
- }],
- is_presentable: ['is_pdf', 'is_image', 'is_video', function (is_pdf, is_image, is_video) {
- return (is_pdf && !this.mediafile.encrypted) || is_image || is_video;
- }],
- is_font: [function () {
- var FONT_FILE_EXTENSIONS = ['ttf', 'woff'];
- var ext = _.last(this.mediafile.name.split('.'));
- return _.includes(FONT_FILE_EXTENSIONS, ext);
- }],
- mediafileUrl: [function () {
- return this.media_url_prefix + this.mediafile.name;
- }],
- filename: [function () {
- var filename = this.mediafile.name;
- return /\/(.+?)$/.exec(filename)[1];
- }],
- filetype: [function () {
- return this.mediafile.type || gettext('undefined');
- }],
- title_or_filename: ['title', 'mediafile', function (title) {
- return title || this.filename;
- }]
- },
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'uploader',
- localKey: 'uploader_id',
- }
- }
- }
- });
- }
-])
-
-.run(['Mediafile', function (Mediafile) {}]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/site.js b/openslides/mediafiles/static/js/mediafiles/site.js
deleted file mode 100644
index 5eda99266..000000000
--- a/openslides/mediafiles/static/js/mediafiles/site.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.site', [
- 'OpenSlidesApp.mediafiles.list',
- 'OpenSlidesApp.mediafiles.states',
- 'OpenSlidesApp.mediafiles.update',
- 'OpenSlidesApp.mediafiles.upload',
- 'OpenSlidesApp.mediafiles.image-plugin',
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/states.js b/openslides/mediafiles/static/js/mediafiles/states.js
deleted file mode 100644
index c8c806781..000000000
--- a/openslides/mediafiles/static/js/mediafiles/states.js
+++ /dev/null
@@ -1,60 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.states', [
- 'gettext',
- 'ui.router',
- //TODO: Add deps for mainMenuProvider
-])
-
-.config([
- 'gettext',
- 'mainMenuProvider',
- function (gettext, mainMenuProvider) {
- mainMenuProvider.register({
- 'ui_sref': 'mediafiles.mediafile.list',
- 'img_class': 'paperclip',
- 'title': gettext('Files'),
- 'weight': 600,
- 'perm': 'mediafiles.can_see',
- });
- }
-])
-
-.config([
- 'SearchProvider',
- 'gettext',
- function (SearchProvider, gettext) {
- SearchProvider.register({
- 'verboseName': gettext('Files'),
- 'collectionName': 'mediafiles/mediafile',
- 'urlDetailState': 'mediafiles.mediafile.detail',
- 'weight': 600,
- });
- }
-])
-
-.config([
- 'gettext',
- '$stateProvider',
- function (gettext, $stateProvider) {
- $stateProvider
- .state('mediafiles', {
- url: '/mediafiles',
- abstract: true,
- template: "
",
- data: {
- title: gettext('Files'),
- basePerm: 'mediafiles.can_see',
- },
- })
- .state('mediafiles.mediafile', {
- abstract: true,
- template: "
",
- })
- .state('mediafiles.mediafile.list', {});
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/update.js b/openslides/mediafiles/static/js/mediafiles/update.js
deleted file mode 100644
index 8243753f6..000000000
--- a/openslides/mediafiles/static/js/mediafiles/update.js
+++ /dev/null
@@ -1,51 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.update', [
- 'OpenSlidesApp.mediafiles.resources',
- //TODO: Add deps for operator, User
-])
-
-.controller('MediafileUpdateCtrl', [
- '$scope',
- 'operator',
- 'User',
- 'Mediafile',
- 'mediafileId',
- 'MediafileForm',
- 'ErrorMessage',
- function ($scope, operator, User, Mediafile, mediafileId, MediafileForm, ErrorMessage) {
- $scope.alert = {};
- $scope.formFields = MediafileForm.getFormFields();
-
- // set initial values for form model by create deep copy of motion object
- // so list/detail view is not updated while editing
- $scope.model = angular.copy(Mediafile.get(mediafileId));
-
- // save mediafile
- $scope.save = function (mediafile) {
- // reset title and uploader_id if empty
- if (!mediafile.title) {
- mediafile.title = mediafile.filename;
- }
- if (!mediafile.uploader_id) {
- mediafile.uploader_id = operator.user.id;
- }
- // inject the changed mediafile (copy) object back into DS store
- Mediafile.inject(mediafile);
- // save change mediafile object on server
- Mediafile.save(mediafile).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- Mediafile.refresh(mediafile);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/js/mediafiles/upload.js b/openslides/mediafiles/static/js/mediafiles/upload.js
deleted file mode 100644
index 53c2dc007..000000000
--- a/openslides/mediafiles/static/js/mediafiles/upload.js
+++ /dev/null
@@ -1,154 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.mediafiles.upload', [
- 'OpenSlidesApp.mediafiles.forms',
- 'ngFileUpload',
-])
-
-.controller('MediafileUploadCtrl', [
- '$scope',
- '$q',
- 'User',
- 'Upload',
- 'operator',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, $q, User, Upload, operator, gettextCatalog, ErrorMessage) {
- User.bindAll({}, $scope, 'users');
- $scope.alert = {};
- $scope.files = [];
- $scope.uploading = false;
- var idCounter = 0; // Used for uniqly identifing each file in $scope.files.
-
- // Convert bytes to human readable si units.
- var humanFileSize = function (bytes) {
- if(Math.abs(bytes) < 1000) {
- return bytes + ' B';
- }
- var units = ['kB','MB','GB','TB','PB','EB','ZB','YB'];
- var i = -1;
- do {
- bytes /= 1000;
- i++;
- } while(bytes >= 1000 && i < units.length - 1);
-
- return bytes.toFixed(1) + ' ' + units[i];
- };
-
- $scope.addFiles = function (files) {
- files = _.map(files, function (file) {
- idCounter += 1;
- // This is a client side representation used for the template
- return {
- id: idCounter,
- file: file,
- title: file.name,
- hidden: false,
- uploader_id: operator.user.id,
- name: file.name,
- size: file.size,
- humanSize: humanFileSize(file.size),
- type: file.type,
- progress: 0,
- };
- });
- // Add each file, that is not a duplicate to $scope.files
- _.forEach(files, function (file) {
- var duplicate = _.some($scope.files, function (_file) {
- return file.name === _file.name &&
- file.size === _file.size &&
- file.type === _file.type;
- });
- if (!duplicate) {
- $scope.files.push(file);
- }
- });
- };
-
- $scope.removeFile = function (id) {
- $scope.files = _.filter($scope.files, function (file) {
- return file.id !== id;
- });
- };
-
- // Add files via drag and drop
- $scope.$watch('dropFiles', function () {
- if ($scope.dropFiles) {
- $scope.addFiles($scope.dropFiles);
- }
- });
-
- // upload all files
- $scope.upload = function () {
- $scope.uploading = true;
- var promises = _.map($scope.files, function (file) {
- // clear error
- file.error = void 0;
-
- // Check, if all necessary fields are set.
- if (!file.title) {
- file.title = file.file.name;
- }
- if (!file.uploader_id) {
- file.uploader_id = operator.user.id;
- }
-
- return Upload.upload({
- url: '/rest/mediafiles/mediafile/',
- method: 'POST',
- data: {
- mediafile: file.file,
- title: file.title,
- uploader_id: file.uploader_id,
- hidden: file.hidden
- },
- }).then(
- function (success) {
- $scope.removeFile(file.id);
- },
- function (error) {
- file.error = ErrorMessage.forAlert(error).msg;
- return error;
- },
- function (progress) {
- file.progress = parseInt(100.0 * progress.loaded / progress.total);
- }
- );
- });
-
- $q.all(promises).then(function (success) {
- var errors = _.filter(success, function (entry) {
- return entry;
- });
-
- if (errors.length) {
- $scope.uploading = false;
- var message = gettextCatalog.getString('Some files could not be uploaded');
- $scope.alert = { type: 'danger', msg: message, show: true };
- } else {
- $scope.close();
- }
- });
- };
-
- $scope.clear = function () {
- $scope.uploading = false;
- $scope.files = [];
- };
-
- $scope.close = function () {
- $scope.closeThisDialog();
- };
- }
-])
-
-.run([
- 'gettext',
- function (gettext) {
- gettext('Some files could not be uploaded');
- }
-]);
-
-}());
diff --git a/openslides/mediafiles/static/templates/mediafiles/image-plugin.html b/openslides/mediafiles/static/templates/mediafiles/image-plugin.html
deleted file mode 100644
index f0f71af81..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/image-plugin.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %
-
-
-
-
-
-
diff --git a/openslides/mediafiles/static/templates/mediafiles/mediafile-form.html b/openslides/mediafiles/static/templates/mediafiles/mediafile-form.html
deleted file mode 100644
index a9f3e4c13..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/mediafile-form.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
Edit File
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html b/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html
deleted file mode 100644
index b13f36553..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/mediafile-list.html
+++ /dev/null
@@ -1,432 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- {{ mediafilesFiltered.length }} /
- {{ mediafiles.length }} {{ "files" | translate }},
- {{(mediafiles|filter:{selected:true}).length}} {{ "selected" | translate }}
-
-
-
-
- Page {{ pagination.currentPage }} /
- {{ pagination.getPageCount(mediafilesFiltered) }}
-
-
-
-
-
-
-
-
-
diff --git a/openslides/mediafiles/static/templates/mediafiles/mediafile-upload-form.html b/openslides/mediafiles/static/templates/mediafiles/mediafile-upload-form.html
deleted file mode 100644
index e6428634e..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/mediafile-upload-form.html
+++ /dev/null
@@ -1,97 +0,0 @@
-
Upload files
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/mediafiles/static/templates/mediafiles/slide_mediafile.html b/openslides/mediafiles/static/templates/mediafiles/slide_mediafile.html
deleted file mode 100644
index c28f06f48..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/slide_mediafile.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/mediafiles/static/templates/mediafiles/slide_mediafile_partial.html b/openslides/mediafiles/static/templates/mediafiles/slide_mediafile_partial.html
deleted file mode 100644
index cdcc7179f..000000000
--- a/openslides/mediafiles/static/templates/mediafiles/slide_mediafile_partial.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/openslides/motions/static/css/motions/_amendments.scss b/openslides/motions/static/css/motions/_amendments.scss
deleted file mode 100644
index 0368198c2..000000000
--- a/openslides/motions/static/css/motions/_amendments.scss
+++ /dev/null
@@ -1,94 +0,0 @@
-.paragraph-select-list {
- display: table;
- border: 1px solid #d3d3d3;
- width: 100%;
- margin-bottom: 10px;
-
- .paragraph-select-holder {
- display: table-row;
- cursor: pointer;
- border-bottom: 1px solid #d3d3d3;
-
- .paragraph-select {
- display: table-cell;
- width: 30px;
- padding-top: 5px;
- text-align: center;
- }
- .text-holder {
- display: table-cell;
- background-color: white;
- padding: 5px 10px;
-
- :last-child {
- margin-bottom: 0;
- }
-
- // Show line numbers at the side
- @media screen and (min-width: 800px) {
- padding-left: 30px;
- position: relative;
-
- .os-line-number {
- display: inline-block;
- font-size: 0;
- line-height: 0;
- width: 22px;
- height: 22px;
- position: absolute;
- left: -15px;
- padding-right: 45px;
-
- &:after {
- content: attr(data-line-number);
- position: absolute;
- top: 8px;
- right: 5px;
- vertical-align: top;
- color: #a9a9a9;
- font-size: 12px;
- font-weight: normal;
- }
- }
- }
-
- // Show line numbers at the side
- @media screen and (max-width: 799px) {
- .os-line-break {
- display: none;
- }
-
- .os-line-number {
- display: inline-block;
-
- &:after {
- display: inline-block;
- content: attr(data-line-number);
- vertical-align: top;
- font-size: 10px;
- font-weight: normal;
- color: gray;
- margin-top: -3px;
- margin-left: 0;
- margin-right: 0;
- }
- }
- }
- }
-
- &:hover {
- .text-holder {
- background-color: #f0f0f0;
- }
- }
- &.selected {
- .paragraph-select {
- background-color: #ddd;
- }
- .text-holder {
- background-color: #ddd;
- }
-
- }
- }
-}
diff --git a/openslides/motions/static/css/motions/_change-recommendation-overview.scss b/openslides/motions/static/css/motions/_change-recommendation-overview.scss
deleted file mode 100644
index 7df8e3e50..000000000
--- a/openslides/motions/static/css/motions/_change-recommendation-overview.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-.change-recommendation-overview {
- background-color: #eee;
- border: solid 1px #ddd;
- border-radius: 3px;
- margin-bottom: 5px;
- margin-top: -15px;
- padding: 5px 5px 0 5px;
-
- h3 {
- margin-top: 10px;
- }
-
- ul {
- list-style: none;
- display: table;
- }
-
- li {
- display: table-row;
- cursor: pointer;
-
- &:hover {
- text-decoration: underline;
- }
-
- & > * {
- display: table-cell;
- padding: 1px;
- }
- }
-
- .status {
- color: gray;
- font-style: italic;
-
- & > *:before {
- content: '(';
- }
-
- & > *:after {
- content: ')';
- }
- }
-
- .no-changes {
- font-style: italic;
- color: grey;
- }
-}
diff --git a/openslides/motions/static/css/motions/_diff.scss b/openslides/motions/static/css/motions/_diff.scss
deleted file mode 100644
index db0cb60f5..000000000
--- a/openslides/motions/static/css/motions/_diff.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Diff view */
-p {
- &.os-split-after {
- margin-bottom: 0;
- }
-
- &.os-split-before {
- margin-top: 0;
- }
-}
-
-ul.os-split-after, ol.os-split-after {
- margin-bottom: 0;
-}
-
-.motion-text-holder li.os-split-before {
- list-style-type: none;
-}
-
-.motion-text-with-diffs {
- li.os-split-before {
- list-style-type: none;
- }
-
- .original-text {
- ul:last-child, ol:last-child {
- padding-bottom: 16px;
- }
-
- ul.os-split-after:last-child, ol.os-split-after:last-child {
- padding-bottom: 0;
- }
- }
- .collission-hint {
- color: red;
- float: left;
- margin-left: -19px;
- margin-top: 10px;
- }
-}
-
-.motion-text-diff {
- .delete {
- color: red;
- text-decoration: line-through;
- }
-
- .insert {
- color: green;
- text-decoration: underline;
- }
-
- &.line-numbers-outside .insert .os-line-number {
- display: none;
- }
-
- &.line-numbers-inline .insert .os-line-number {
- display: none;
- }
- .paragraph-context {
- opacity: 0.5;
- }
- &.amendment-context {
- .paragraph-context {
- opacity: 1;
- }
- }
- .amendment-line-header {
- margin: 10px 0 0 0;
- }
-}
diff --git a/openslides/motions/static/css/motions/_inline-editing.scss b/openslides/motions/static/css/motions/_inline-editing.scss
deleted file mode 100644
index 6583585ee..000000000
--- a/openslides/motions/static/css/motions/_inline-editing.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Toolbar to save motion in inline editing mode */
-.motion-save-toolbar {
- position: fixed;
- bottom: 0;
- left: 50%;
- height: 75px;
- width: 300px;
- background: #d3d3d3;
- color: black;
- text-align: center;
- padding: 5px;
- z-index: 1000001;
- display: none;
- border: 1px solid #d3d3d3;
- margin-left: -150px;
- border-bottom: none;
- -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75);
- -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75);
- box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75);
-
- &.visible {
- display: block;
- }
-
- .changed-hint {
- display: block;
- line-height: 16px;
- text-align: center;
- margin-bottom: 10px;
- font-weight: bold;
- }
-
- label {
- font-weight: normal;
- line-height: 16px;
- text-align: left;
- padding-left: 16px;
- margin-top: 5px;
- margin-left: 15px;
-
- input {
- margin-left: -16px;
- }
- }
-}
diff --git a/openslides/motions/static/css/motions/_line-numbering.scss b/openslides/motions/static/css/motions/_line-numbering.scss
deleted file mode 100644
index 5317ee7b9..000000000
--- a/openslides/motions/static/css/motions/_line-numbering.scss
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Line numbers */
-.motion-text {
- ins {
- color: green;
- text-decoration: underline;
- }
-
- del {
- color: red;
- text-decoration: line-through;
- }
-
- li {
- padding-bottom: 10px;
- }
-
- ol, ul {
- margin-left: 15px;
- margin-bottom: 0;
- }
-
- .highlight {
- background-color: #ff0;
- }
- &.line-numbers-outside {
- padding-left: 40px;
- position: relative;
-
- .os-line-number {
- display: inline-block;
- font-size: 0;
- line-height: 0;
- width: 22px;
- height: 22px;
- position: absolute;
- left: -20px;
- padding-right: 55px;
-
- &:after {
- content: attr(data-line-number);
- position: absolute;
- top: 10px;
- vertical-align: top;
- color: gray;
- font-size: 12px;
- font-weight: normal;
- }
- }
- }
-
- &.line-numbers-inline {
- .os-line-break {
- display: none;
- }
-
- .os-line-number {
- display: inline-block;
-
- &:after {
- display: inline-block;
- content: attr(data-line-number);
- vertical-align: top;
- font-size: 10px;
- font-weight: normal;
- color: gray;
- margin-top: -3px;
- margin-left: 0;
- margin-right: 0;
- }
- }
- }
-
- &.line-numbers-none {
- .os-line-break {
- display: none;
- }
-
- .os-line-number {
- display: none;
- }
- }
-}
diff --git a/openslides/motions/static/css/motions/_personal-note.scss b/openslides/motions/static/css/motions/_personal-note.scss
deleted file mode 100644
index 6cadb3f50..000000000
--- a/openslides/motions/static/css/motions/_personal-note.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Motion personal note */
-#personalNote.pinned {
- position: fixed;
- z-index: 1000;
- bottom: 0;
- margin: 0px 20px;
- -webkit-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5);
- -moz-box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5);
- box-shadow: 0px 0px 10px 1px rgba(0,0,0,0.5);
-
- #personal-note-inline-editor {
- overflow-y: scroll;
- min-height: 100px;
- max-height: 200px;
- }
-}
-
-#personalNoteSpacer {
- display: none;
- height: 220px;
-
- &.activeSpace {
- display: block;
- }
-}
diff --git a/openslides/motions/static/css/motions/_pollresults.scss b/openslides/motions/static/css/motions/_pollresults.scss
deleted file mode 100644
index 43d0c5164..000000000
--- a/openslides/motions/static/css/motions/_pollresults.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-.pollresults {
- table {
- margin-bottom: 0;
-
- td {
- border: none !important;
- padding: 5px 2px !important;
- vertical-align: middle !important;
- }
-
- .icon {
- color: #636363;
- }
-
- tr.total td {
- border-top: 1px solid #444 !important;
- }
- }
-
- .result-label {
- margin-top: 5px;
- }
-
- .progress {
- height: 12px;
- margin-bottom: 0;
- }
-}
diff --git a/openslides/motions/static/css/motions/_projector.scss b/openslides/motions/static/css/motions/_projector.scss
deleted file mode 100644
index 21c509e85..000000000
--- a/openslides/motions/static/css/motions/_projector.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-@import "line-numbering";
-@import "diff";
-@import "pollresults";
-@import "sidebox";
-
-/* TODO: why do the projector has these extra diff related classes?
- * -> Unify the site and projector in the _diff.scss and _line-numbers.scss*/
-ol.os-split-after, ul.os-split-after {
- margin-bottom: 0;
- padding-bottom: 0;
-}
-p.os-split-after {
- margin-bottom: 0;
-}
-.motion-text-diff p.os-split-before {
- padding-top: 0;
- margin-top: 0;
-}
-.motion-text-diff p.os-split-after {
- margin-top: 0;
- margin-bottom: 0;
-}
-.diff-box {
- padding-top: 0;
-}
-.diff-box-title {
- margin-bottom: 10px;
- .description {
- font-weight: bold;
- }
-}
-
-.motion-text.line-numbers-outside {
- padding-left: 0;
- margin-left: 35px;
- position: relative;
-}
-.motion-text.line-numbers-outside .os-line-number {
- left: -33px;
-}
-.motion-text.line-numbers-outside .os-line-number:after {
- content: attr(data-line-number);
- position: absolute;
- top: 17px;
- vertical-align: top;
- color: gray;
- font-size: 14px;
- font-weight: normal;
-}
-
-/* Motion blocks */
-.motion-block {
- display: flex;
- flex-wrap: wrap;
-
- & > div {
- width: 50%;
- font-size: 1.1em;
- margin-bottom: 15px;
- padding-right: 15px;
- line-height: 1em;
- }
-
- .label {
- text-align: left;
- padding: 5px 10px;
- margin-top: 3px;
- }
-}
diff --git a/openslides/motions/static/css/motions/_sidebox.scss b/openslides/motions/static/css/motions/_sidebox.scss
deleted file mode 100644
index 37fc2c07c..000000000
--- a/openslides/motions/static/css/motions/_sidebox.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-#sidebox {
- width: 260px;
- right: 0;
- margin-top: 75px;
- background: #d3d3d3;
- border-radius: 7px 0 0 7px;
- padding: 3px 7px 10px 10px;
- position: fixed;
- z-index: 5;
-
- h3 {
- margin-top: 10px;
- margin-bottom: 0px;
- }
-}
-#sidebox .pollresults td {
- white-space: nowrap;
- font-size: 19px;
-}
diff --git a/openslides/motions/static/css/motions/_site.scss b/openslides/motions/static/css/motions/_site.scss
deleted file mode 100644
index 0c809459c..000000000
--- a/openslides/motions/static/css/motions/_site.scss
+++ /dev/null
@@ -1,268 +0,0 @@
-@import "amendments";
-@import "diff";
-@import "change-recommendation-overview";
-@import "inline-editing";
-@import "line-numbering";
-@import "personal-note";
-@import "pollresults";
-
-/* Motion */
-.motion-toolbar, .speakers-toolbar {
- background-color: #f5f5f5;
- border-bottom: 1px solid #ddd;
- padding: 12px 0 10px 0;
- height: 54px;
- margin: -20px -5px 50px -5px;
-}
-
-.motion-toolbar:first-child {
- margin-bottom: 20px;
-}
-
-/* Styles for annotating the original motion text with change recommendations */
-#content .motion-text-holder {
- position: relative;
-
- .change-recommendation-list {
- position: absolute;
- top: 0;
- left: -10px;
- width: 4px;
- list-style-type: none;
- margin: 0;
-
- & > li {
- position: absolute;
- width: 4px;
- cursor: pointer;
-
- &.insert {
- background-color: #00aa00;
- }
-
- &.delete {
- background-color: #aa0000;
- }
-
- &.replace {
- background-color: #0333ff;
- }
-
- &.other {
- background-color: #777777;
- }
- }
-
- .tooltip {
- display: none;
- }
- }
-}
-
-.import-preview p {
- margin: 0;
- padding: 0;
-}
-
-.motion-toolbar .toolbar-left {
- margin-top: 0;
- margin-bottom: 55px;
- margin-left: 15px;
-
- > * {
- margin-right: 5px;
- }
-
- ng-include {
- display: inline-block;
- }
-
- .btn.disabled {
- cursor: default;
- opacity: 1;
- background-color: #eee;
- }
-}
-
-.inline-editing-activator {
- margin-right: 13px;
-}
-
-/* Linenumbering specific site things */
-.os-line-number {
- position: relative;
- user-select: none;
- -moz-user-select: none;
- -khtml-user-select: none;
- -webkit-user-select: none;
- -o-user-select: none;
-}
-.os-line-number:after {
- position: relative;
- user-select: none;
- -moz-user-select: none;
- -khtml-user-select: none;
- -webkit-user-select: none;
- -o-user-select: none;
-}
-
-/* TODO: This rule should only apply to the site. Isn't this inconsistent?? */
-.motion-text.line-numbers-outside .os-line-number:after {
- left: 20px;
-}
-
-.motion-text.line-numbers-none li > br {
- margin-top: 6px;
- content: " ";
- display: block;
- &.os-line-break {
- margin-top: 0;
- content: "";
- display: inline;
- }
-}
-
-@mixin addChangeRecommendationBtn {
- cursor: pointer;
- content: "\f067";
- width: 14px;
- height: 14px;
- border-radius: 0.25em;
- font-family: FontAwesome;
- font-size: 12px;
- color: white;
- line-height: 16px;
- text-align: center;
- background-color: #337ab7;
-}
-
-.line-numbers-outside .os-line-number.selectable:hover:before, .line-numbers-outside .os-line-number.selected:before {
- position: absolute;
- top: 4px;
- left: 43px;
- display: inline-block;
- @include addChangeRecommendationBtn();
-}
-
-.motion-header {
- .submenu {
- position: relative;
- z-index: 2;
- }
- .motion-title {
- position: relative;
- z-index: 1;
-
- // Grab the left padding of the parent element to catch hover-events for the :before element
- margin-left: -20px;
- padding-left: 20px;
-
- .change-title {
- position: relative;
- width: 0;
- height: 0;
- }
- .change-title:before {
- position: absolute;
- top: 18px;
- left: -17px;
- @include addChangeRecommendationBtn();
- display: none;
- }
- &:hover .change-title.selectable:before {
- display: block;
- }
- .title-change-indicator {
- background-color: #0333ff;
- position: absolute;
- width: 4px;
- height: 32px;
- left: 10px;
- top: 5px;
- cursor: pointer;
- }
- }
-}
-
-
-.tt_change_recommendation_create_help {
- display: none;
- max-width: 150px;
- left: -45px;
- margin-top: -15px !important;
- z-index: 10000;
-}
-
-/* special hack for firefox only (see issue#2967) */
-@-moz-document url-prefix() {
- .tt_change_recommendation_create_help {
- margin-top: -20px !important;
- }
-}
-
-.tt_change_recommendation_create_help.opened {
- display: inherit;
- opacity: 0.8;
-}
-
-/* Diffbox */
-.diff-box {
- background-color: #f9f9f9;
- border: solid 1px #eee;
- border-radius: 3px;
- margin-bottom: 0;
- padding-top: 0;
- padding-right: 155px;
-
- &:hover {
- background-color: #f0f0f0;
-
- .action-row {
- opacity: 1;
- }
- }
-
- .action-row {
- font-size: 0.8em;
- padding-top: 5px;
- padding-bottom: 5px;
- float: right;
- width: 150px;
- text-align: right;
- margin-right: -150px;
- opacity: 0.5;
-
- .btn-delete {
- margin-left: 5px;
- color: red;
- }
-
- .btn-edit {
- margin-left: 5px;
- }
-
- .btn-amend-info {
- margin-left: 5px;
- min-width: 68px;
- }
- }
- .status-row {
- font-style: italic;
- color: gray;
-
- & > *:after {
- content: ':';
- }
- }
-}
-
-.diff-box-title {
- margin-bottom: 10px;
- .description {
- font-weight: bold;
- }
-}
-
-.motion-text-with-diffs.line-numbers-inline .diff-box, .motion-text-with-diffs.line-numbers-none .diff-box {
- margin-right: -220px;
-}
diff --git a/openslides/motions/static/js/motions/base.js b/openslides/motions/static/js/motions/base.js
deleted file mode 100644
index 8b9d4e8d9..000000000
--- a/openslides/motions/static/js/motions/base.js
+++ /dev/null
@@ -1,1646 +0,0 @@
-(function () {
-
-"use strict";
-
-angular.module('OpenSlidesApp.motions', [
- 'OpenSlidesApp.motions.motionBlock',
- 'OpenSlidesApp.motions.lineNumbering',
- 'OpenSlidesApp.motions.diff',
- 'OpenSlidesApp.poll.majority',
- 'OpenSlidesApp.users',
-])
-
-.factory('MotionState', [
- 'DS',
- function (DS) {
- return DS.defineResource({
- name: 'motions/state',
- methods: {
- getNextStates: function () {
- return _.map(this.next_states_id, function (stateId) {
- return DS.get('motions/state', stateId);
- });
- },
- getRecommendations: function () {
- var params = {
- where: {
- 'workflow_id': {
- '==': this.workflow_id
- },
- 'recommendation_label': {
- '!=': null
- }
- }
- };
- return DS.filter('motions/state', params);
- }
- },
- relations: {
- hasOne: {
- 'motions/workflow': {
- localField: 'workflow',
- localKey: 'workflow_id',
- }
- }
- },
- });
- }
-])
-
-.factory('Workflow', [
- 'DS',
- function (DS) {
- return DS.defineResource({
- name: 'motions/workflow',
- methods: {
- getFirstState: function () {
- return DS.get('motions/state', this.first_state_id);
- },
- },
- relations: {
- hasMany: {
- 'motions/state': {
- localField: 'states',
- foreignKey: 'workflow_id',
- }
- }
- }
- });
- }
-])
-
-.factory('MotionPoll', [
- 'DS',
- 'gettextCatalog',
- 'Config',
- 'MajorityMethods',
- function (DS, gettextCatalog, Config, MajorityMethods) {
- return DS.defineResource({
- name: 'motions/motion-poll',
- relations: {
- belongsTo: {
- 'motions/motion': {
- localField: 'motion',
- localKey: 'motion_id',
- }
- }
- },
- beforeInject: function (resource, instance) {
- var attrs = ['yes', 'no', 'abstain', 'votescast', 'votesinvalid', 'votesvalid'];
- _.forEach(attrs, function (attr) {
- if (instance[attr] !== null) {
- instance[attr] = parseFloat(instance[attr]);
- }
- });
- },
- methods: {
- // Returns percent base. Returns undefined if calculation is not possible in general.
- getPercentBase: function (config, type) {
- var base;
- switch (config) {
- case 'CAST':
- if (this.votescast <= 0 || this.votesinvalid < 0) {
- // It would be OK to check only this.votescast < 0 because 0
- // is checked again later but this is a little bit faster.
- break;
- }
- base = this.votescast;
- /* falls through */
- case 'VALID':
- if (this.votesvalid < 0) {
- base = void 0;
- break;
- }
- if (typeof base === 'undefined' && type !== 'votescast' && type !== 'votesinvalid') {
- base = this.votesvalid;
- }
- /* falls through */
- case 'YES_NO_ABSTAIN':
- if (this.abstain < 0) {
- base = void 0;
- break;
- }
- if (typeof base === 'undefined' && type !== 'votescast' && type !== 'votesinvalid' && type !== 'votesvalid') {
- base = this.yes + this.no + this.abstain;
- }
- /* falls through */
- case 'YES_NO':
- if (this.yes < 0 || this.no < 0 || this.abstain === -1 ) {
- // It is not allowed to set 'Abstain' to 'majority' but exclude it from calculation.
- // Setting 'Abstain' to 'undocumented' is possible, of course.
- base = void 0;
- break;
- }
- if (typeof base === 'undefined' && (type === 'yes' || type === 'no')) {
- base = this.yes + this.no;
- }
- }
- return base;
- },
-
- // Returns object with value and percent for this poll.
- getVote: function (vote, type) {
- if (!this.has_votes) {
- // Return undefined if this poll has no votes.
- return;
- }
-
- // Initial values
- var value = '',
- percentStr = '',
- percentNumber,
- config = Config.get('motions_poll_100_percent_base').value;
-
- // Check special values
- switch (vote) {
- case -1:
- value = gettextCatalog.getString('majority');
- break;
- case -2:
- value = gettextCatalog.getString('undocumented');
- break;
- default:
- if (vote >= 0) {
- value = vote;
- } else {
- value = 0; // Vote was not defined. Set value to 0.
- }
- }
-
- // Calculate percent value
- var base = this.getPercentBase(config, type);
- if (base) {
- percentNumber = Math.round(vote * 100 / (base) * 100) / 100;
- percentStr = '(' + percentNumber + ' %)';
- }
- return {
- 'value': value,
- 'percentStr': percentStr,
- 'percentNumber': percentNumber,
- 'display': value + ' ' + percentStr
- };
- },
-
- // Returns 0 or positive integer if quorum is reached or surpassed.
- // Returns negativ integer if quorum is not reached.
- // Returns undefined if we can not calculate the quorum.
- isReached: function (method) {
- if (!this.has_votes) {
- // Return undefined if this poll has no votes.
- return;
- }
-
- var isReached;
- var config = Config.get('motions_poll_100_percent_base').value;
- var base = this.getPercentBase(config, 'yes');
- if (base) {
- // Provide result only if base is not undefined and not 0.
- isReached = MajorityMethods[method](this.yes, base);
- }
- return isReached;
- }
- }
- });
- }
-])
-
-.provider('MotionPollDecimalPlaces', [
- function () {
- this.$get = ['$q', function ($q) {
- return {
- getPlaces: function (poll, find) {
- if (find) {
- return $q(function (resolve) {
- resolve(0);
- });
- } else {
- return 0;
- }
- },
- };
- }];
- }
-])
-
-.factory('MotionStateAndRecommendationParser', [
- 'DS',
- 'gettextCatalog',
- function (DS, gettextCatalog) {
- return {
- formatMotion: function (motion) {
- return '[motion:' + motion.id + ']';
- },
- parse: function (recommendation) {
- return recommendation.replace(/\[motion:(\d+)\]/g, function (match, id) {
- var motion = DS.get('motions/motion', id);
- if (motion) {
- return motion.identifier ? motion.identifier : motion.getTitle();
- } else {
- return gettextCatalog.getString('
');
- }
- });
- },
- };
- }
-])
-
-.factory('Submitter', [
- 'DS',
- function (DS) {
- return DS.defineResource({
- name: 'motions/submitter',
- relations: {
- belongsTo: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
- }
- }
- }
- });
- }
-])
-
-.factory('Motion', [
- 'DS',
- '$http',
- '$cacheFactory',
- 'MotionPoll',
- 'MotionStateAndRecommendationParser',
- 'MotionChangeRecommendation',
- 'MotionComment',
- 'jsDataModel',
- 'gettext',
- 'gettextCatalog',
- 'Config',
- 'lineNumberingService',
- 'diffService',
- 'OpenSlidesSettings',
- 'Projector',
- 'ProjectHelper',
- 'operator',
- 'UnifiedChangeObjectCollission',
- function(DS, $http, $cacheFactory, MotionPoll, MotionStateAndRecommendationParser, MotionChangeRecommendation,
- MotionComment, jsDataModel, gettext, gettextCatalog, Config, lineNumberingService,
- diffService, OpenSlidesSettings, Projector, ProjectHelper, operator, UnifiedChangeObjectCollission) {
-
- var diffCache = $cacheFactory('motion.service');
-
- var name = 'motions/motion';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Motion'),
- verboseNamePlural: gettext('Motions'),
- validate: function (resource, data, callback) {
- MotionComment.populateFieldsReverse(data);
- callback(null, data);
- },
- computed: {
- isAmendment: function () {
- return this.parent_id !== null;
- },
- },
- methods: {
- getResourceName: function () {
- return name;
- },
- getVersion: function (versionId) {
- versionId = versionId || this.active_version;
- var index;
- if (versionId == -1) {
- index = this.versions.length - 1;
- } else {
- index = _.findIndex(this.versions, function (element) {
- return element.id == versionId;
- });
- }
- return this.versions[index] || {};
- },
- isParagraphBasedAmendment: function () {
- var version = this.getVersion();
- return this.isAmendment && version.amendment_paragraphs;
- },
- getTitle: function (versionId) {
- return this.getVersion(versionId).title;
- },
- getAgendaTitle: function () {
- var title = gettextCatalog.getString('Motion');
- if (this.identifier) {
- title += ' ' + this.identifier;
- } else {
- title += ' (' + this.getTitle() + ')';
- }
- return title;
- },
- getListOfSpeakersTitle: function () {
- var title = gettextCatalog.getString('Motion');
- if (this.identifier) {
- title += ' ' + this.identifier;
- } else {
- title += ' (' + this.getTitle() + ')';
- }
- return title;
- },
- getTitleWithChanges: function (changeRecommendationMode, versionId) {
- var titleChange = this.getTitleChangeRecommendation(versionId);
- var title;
- if (titleChange) {
- if (changeRecommendationMode === "changed") {
- title = titleChange.text;
- } else if ((changeRecommendationMode === 'agreed' ||
- changeRecommendationMode === 'modified_agreed') && !titleChange.rejected) {
- title = titleChange.text;
- } else {
- title = this.getTitle();
- }
- } else {
- title = this.getTitle();
- }
- return title;
- },
- getSequentialNumber: function () {
- var id = this.id + '';
- var zeros = Math.max(0, OpenSlidesSettings.MOTION_IDENTIFIER_MIN_DIGITS - id.length);
- for (var i = 0; i < zeros; i++) {
- id = '0' + id;
- }
- return id;
- },
- getText: function (versionId) {
- return this.getVersion(versionId).text;
- },
- getTextWithLineBreaks: function (versionId, highlight, callback) {
- var lineLength = Config.get('motions_line_length').value,
- html = this.getVersion(versionId).text;
-
- return lineNumberingService.insertLineNumbers(html, lineLength, highlight, callback);
- },
- getModifiedFinalVersionWithLineBreaks: function (versionId) {
- var lineLength = Config.get('motions_line_length').value,
- html = this.getVersion(versionId).modified_final_version;
-
- return lineNumberingService.insertLineNumbers(html, lineLength);
- },
- getTextBetweenChanges: function (versionId, change1, change2, highlight) {
- var line_from = (change1 ? change1.line_to : 1),
- line_to = (change2 ? change2.line_from : null);
-
- if (line_from > line_to) {
- throw 'Invalid call of getTextBetweenChanges: change1 needs to be before change2';
- }
- if (line_from === line_to) {
- return '';
- }
-
- return this.getTextInLineRange(versionId, line_from, line_to, highlight);
- },
- getTextInLineRange: function (versionId, line_from, line_to, highlight) {
- var lineLength = Config.get('motions_line_length').value,
- htmlRaw = this.getVersion(versionId).text;
-
- var cacheKey = 'getTextInLineRange ' + line_from + ' ' + line_to + ' ' + highlight + ' ' +
- lineNumberingService.djb2hash(htmlRaw),
- cached = diffCache.get(cacheKey);
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- var html = lineNumberingService.insertLineNumbers(htmlRaw, lineLength),
- data;
-
- try {
- data = diffService.extractRangeByLineNumbers(html, line_from, line_to);
- } catch (e) {
- // This only happens (as far as we know) when the motion text has been altered (shortened)
- // without modifying the change recommendations accordingly.
- // That's a pretty serious inconsistency that should not happen at all,
- // we're just doing some basic damage control here.
- var msg = 'Inconsistent data. A change recommendation is probably referring to a non-existant line number.';
- return '' + msg + ' ';
- }
-
- // Add "merge-before"-css-class if the first line begins in the middle of a paragraph. Used for PDF.
- html = diffService.addCSSClassToFirstTag(data.outerContextStart + data.innerContextStart, "merge-before") +
- data.html + data.innerContextEnd + data.outerContextEnd;
- html = lineNumberingService.insertLineNumbers(html, lineLength, highlight, null, line_from);
-
- diffCache.put(cacheKey, html);
-
- return html;
- },
- getTextRemainderAfterLastChange: function(versionId, changes, highlight) {
- var maxLine = 0;
- for (var i = 0; i < changes.length; i++) {
- if (changes[i].line_to > maxLine) {
- maxLine = changes[i].line_to;
- }
- }
-
- var lineLength = Config.get('motions_line_length').value,
- html = lineNumberingService.insertLineNumbers(this.getVersion(versionId).text, lineLength),
- data;
-
- try {
- data = diffService.extractRangeByLineNumbers(html, maxLine, null);
- } catch (e) {
- // This only happens (as far as we know) when the motion text has been altered (shortened)
- // without modifying the change recommendations accordingly.
- // That's a pretty serious inconsistency that should not happen at all,
- // we're just doing some basic damage control here.
- var msg = 'Inconsistent data. A change recommendation is probably referring to a non-existant line number.';
- return '' + msg + ' ';
- }
-
- if (data.html !== '') {
- // Add "merge-before"-css-class if the first line begins in the middle of a paragraph. Used for PDF.
- html = diffService.addCSSClassToFirstTag(data.outerContextStart + data.innerContextStart, "merge-before") +
- data.html + data.innerContextEnd + data.outerContextEnd;
- html = lineNumberingService.insertLineNumbers(html, lineLength, highlight, null, maxLine);
- } else {
- // Prevents empty lines at the end of the motion
- html = '';
- }
- return html;
- },
- _getTextWithChanges: function (versionId, highlight, lineBreaks, recommendation_filter, amendment_filter) {
- var lineLength = Config.get('motions_line_length').value,
- html = this.getVersion(versionId).text,
- change_recommendations = this.getTextChangeRecommendations(versionId, 'DESC'),
- amendments = this.getParagraphBasedAmendments();
-
- var allChanges = [];
- change_recommendations.filter(recommendation_filter).forEach(function(change) {
- allChanges.push({"text": change.text, "line_from": change.line_from, "line_to": change.line_to});
- });
- amendments.filter(amendment_filter).forEach(function(amend) {
- var change = amend.getAmendmentsAffectedLinesChanged();
- allChanges.push({"text": change.text, "line_from": change.line_from, "line_to": change.line_to});
- });
-
- // Changes need to be applied from the bottom up, to prevent conflicts with changing line numbers.
- allChanges.sort(function(change1, change2) {
- if (change1.line_from < change2.line_from) {
- return 1;
- } else if (change1.line_from > change2.line_from) {
- return -1;
- } else {
- return 0;
- }
- });
-
-
- allChanges.forEach(function(change) {
- html = lineNumberingService.insertLineNumbers(html, lineLength, null, null, 1);
- html = diffService.replaceLines(html, change.text, change.line_from, change.line_to);
- });
-
- if (lineBreaks) {
- html = lineNumberingService.insertLineNumbers(html, lineLength, highlight, null, 1);
- }
-
- return html;
- },
- getTextWithAllChangeRecommendations: function (versionId, highlight, lineBreaks) {
- return this._getTextWithChanges(versionId, highlight, lineBreaks, function() {
- return true; // All change recommendations
- }, function() {
- return false; // No amendments
- });
- },
- getTextWithAgreedChanges: function (versionId, highlight, lineBreaks) {
- return this._getTextWithChanges(versionId, highlight, lineBreaks, function(recommendation) {
- return !recommendation.rejected;
- }, function(amendment) {
- if (amendment.state && amendment.state.name === 'rejected') {
- return false;
- }
- if (amendment.state && amendment.state.name === 'accepted') {
- return true;
- }
- return (amendment.recommendation && amendment.recommendation.name === 'accepted');
- });
- },
- getTextByMode: function(mode, versionId, highlight, lineBreaks) {
- /*
- * @param mode ['original', 'diff', 'changed', 'agreed', 'modified_agreed']
- * @param versionId [if undefined, active_version will be used]
- * @param highlight [the line number to highlight]
- * @param lineBreaks [if line numbers / breaks should be included in the result]
- */
-
- lineBreaks = (lineBreaks === undefined ? true : lineBreaks);
-
- var text;
- switch (mode) {
- case 'original':
- if (lineBreaks) {
- text = this.getTextWithLineBreaks(versionId, highlight);
- } else {
- text = this.getVersion(versionId).text;
- }
- break;
- case 'diff':
- var amendments_crs = this.getTextChangeRecommendations(versionId, 'ASC').map(function (cr) {
- return cr.getUnifiedChangeObject();
- }).concat(
- this.getParagraphBasedAmendmentsForDiffView().map(function (amendment) {
- return amendment.getUnifiedChangeObject();
- })
- );
- amendments_crs.sort(function (change1, change2) {
- if (change1.line_from > change2.line_from) {
- return 1;
- } else if (change1.line_from < change2.line_from) {
- return -1;
- } else {
- return 0;
- }
- });
-
- text = '';
- for (var i = 0; i < amendments_crs.length; i++) {
- if (i===0) {
- text += this.getTextBetweenChanges(versionId, null, amendments_crs[0], highlight);
- } else if (amendments_crs[i - 1].line_to < amendments_crs[i].line_from) {
- text += this.getTextBetweenChanges(versionId, amendments_crs[i - 1], amendments_crs[i], highlight);
-
- }
- text += amendments_crs[i].getDiff(this, versionId, highlight);
- }
- text += this.getTextRemainderAfterLastChange(versionId, amendments_crs);
-
- if (!lineBreaks) {
- text = lineNumberingService.stripLineNumbers(text);
- }
- break;
- case 'changed':
- text = this.getTextWithAllChangeRecommendations(versionId, highlight, lineBreaks);
- break;
- case 'agreed':
- text = this.getTextWithAgreedChanges(versionId, highlight, lineBreaks);
- break;
- case 'modified_agreed':
- text = this.getModifiedFinalVersion(versionId);
- if (text) {
- // Insert line numbers
- var lineLength = Config.get('motions_line_length').value;
- text = lineNumberingService.insertLineNumbers(text, lineLength);
- } else {
- // Use the agreed version as fallback
- text = this.getTextByMode('agreed', versionId, highlight, lineBreaks);
- }
- break;
- }
- return text;
- },
- getTextParagraphs: function(versionId, lineBreaks) {
- /*
- * @param versionId [if undefined, active_version will be used]
- * @param lineBreaks [if line numbers / breaks should be included in the result]
- */
- var text;
- if (lineBreaks) {
- text = this.getTextWithLineBreaks(versionId);
- } else {
- text = this.getVersion(versionId).text;
- }
-
- return lineNumberingService.splitToParagraphs(text);
- },
- getTextHeadings: function(versionId) {
- var html = this.getTextWithLineBreaks(versionId);
- return lineNumberingService.getHeadingsWithLineNumbers(html);
- },
- getAmendmentParagraphsByMode: function (mode, versionId, lineBreaks) {
- /*
- * @param mode ['original', 'diff', 'changed']
- * @param versionId [if undefined, active_version will be used]
- * @param lineBreaks [if line numbers / breaks should be included in the result]
- *
- * Structure of the return array elements:
- * {
- * "paragraphNo": paragraph number, starting with 0
- * "lineFrom": First line number of the affected paragraph
- * "lineTo": Last line number of the affected paragraph;
- * refers to the line breaking element at the end, i.e. the start of the following line
- * "text": the actual text
- * }
- */
-
- lineBreaks = (lineBreaks === undefined ? true : lineBreaks);
-
- var cacheKey = 'getAmendmentParagraphsByMode ' + mode + ' ' + versionId + ' ' + lineBreaks +
- lineNumberingService.djb2hash(JSON.stringify(this.getVersion(versionId).amendment_paragraphs)),
- cached = diffCache.get(cacheKey);
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- var original_text = this.getParentMotion().getTextByMode('original', null, null, true);
- var original_paragraphs = lineNumberingService.splitToParagraphs(original_text);
-
- var output = [];
-
- this.getVersion(versionId).amendment_paragraphs.forEach(function(paragraph_amend, paragraphNo) {
- if (paragraph_amend === null) {
- return;
- }
- if (original_paragraphs[paragraphNo] === undefined) {
- throw "The amendment appears to have more paragraphs than the motion. This means, the data might be corrupt";
- }
- var paragraph_orig = original_paragraphs[paragraphNo];
- var line_range = lineNumberingService.getLineNumberRange(paragraph_orig);
- var line_length = Config.get('motions_line_length').value;
- paragraph_orig = lineNumberingService.stripLineNumbers(paragraph_orig);
-
- var text = null;
-
- switch (mode) {
- case "diff":
- if (lineBreaks) {
- text = diffService.diff(paragraph_orig, paragraph_amend, line_length, line_range.from);
- } else {
- text = diffService.diff(paragraph_orig, paragraph_amend);
- }
- break;
- case "original":
- text = paragraph_orig;
- if (lineBreaks) {
- text = lineNumberingService.insertLineNumbers(text, line_length, null, null, line_range.from);
- }
- break;
- case "changed":
- text = paragraph_amend;
- if (lineBreaks) {
- text = lineNumberingService.insertLineNumbers(text, line_length, null, null, line_range.from);
- }
- break;
- default:
- throw "Invalid text mode: " + mode;
- }
- output.push({
- "paragraphNo": paragraphNo,
- "lineFrom": line_range.from,
- "lineTo": line_range.to,
- "text": text
- });
- });
-
- diffCache.put(cacheKey, output);
-
- return output;
- },
- getAmendmentParagraphsLinesByMode: function (mode, versionId, lineBreaks) {
- /*
- * @param mode ['original', 'diff', 'changed']
- * @param versionId [if undefined, active_version will be used]
- * @param lineBreaks [if line numbers / breaks should be included in the result]
- *
- * Structure of the return array elements:
- * {
- * "paragraphNo": paragraph number, starting with 0
- * "paragraphLineFrom": First line number of the affected paragraph
- * "paragraphLineTo": End of the affected paragraph (line number + 1)
- * "diffLineFrom": First line number of the affected lines
- * "diffLineTo": End of the affected lines (line number + 1)
- * "textPre": The beginning of the paragraph, before the diff
- * "text": the diff
- * "textPost": The end of the paragraph, after the diff
- * }
- */
-
- if (!this.isParagraphBasedAmendment() || !this.getParentMotion()) {
- return [];
- }
-
- var cacheKey = 'getAmendmentParagraphsLinesByMode ' + mode + ' ' + versionId + ' ' + lineBreaks +
- lineNumberingService.djb2hash(JSON.stringify(this.getVersion(versionId).amendment_paragraphs)),
- cached = diffCache.get(cacheKey);
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- var original_text = this.getParentMotion().getTextByMode('original', null, null, true);
- var original_paragraphs = lineNumberingService.splitToParagraphs(original_text);
-
- var output = [];
-
- this.getVersion(versionId).amendment_paragraphs.forEach(function(paragraph_amend, paragraphNo) {
- if (paragraph_amend === null) {
- return;
- }
- if (original_paragraphs[paragraphNo] === undefined) {
- throw "The amendment appears to have more paragraphs than the motion. This means, the data might be corrupt";
- }
- var line_length = Config.get('motions_line_length').value,
- paragraph_orig = original_paragraphs[paragraphNo],
- paragraph_line_range = lineNumberingService.getLineNumberRange(paragraph_orig),
- diff = diffService.diff(paragraph_orig, paragraph_amend),
- affected_lines = diffService.detectAffectedLineRange(diff);
-
- if (!affected_lines) {
- return;
- }
-
- // TODO: Make this work..
- var base_paragraph;
- switch (mode) {
- case 'original':
- //base_paragraph = paragraph_orig;
- //base_paragraph = diffService.diff(paragraph_orig, paragraph_orig, line_length, paragraph_line_range.from);
- base_paragraph = diff;
- break;
- case 'diff':
- base_paragraph = diff;
- break;
- case 'changed':
- //base_paragraph = paragraph_amend;
- //base_paragraph = diffService.diff(paragraph_amend, paragraph_amend, line_length, paragraph_line_range.from);
- base_paragraph = diff;
- break;
- }
-
- var textPre = '';
- var textPost = '';
- if (affected_lines.from > paragraph_line_range.from) {
- textPre = diffService.extractRangeByLineNumbers(base_paragraph, paragraph_line_range.from, affected_lines.from);
- if (lineBreaks) {
- textPre = diffService.formatDiffWithLineNumbers(textPre, line_length, paragraph_line_range.from);
- }
- }
- if (paragraph_line_range.to > affected_lines.to) {
- textPost = diffService.extractRangeByLineNumbers(base_paragraph, affected_lines.to, paragraph_line_range.to);
- if (lineBreaks) {
- textPost = diffService.formatDiffWithLineNumbers(textPost, line_length, affected_lines.to);
- }
- }
-
- var text = diffService.extractRangeByLineNumbers(base_paragraph, affected_lines.from, affected_lines.to);
- if (lineBreaks) {
- text = diffService.formatDiffWithLineNumbers(text, line_length, affected_lines.from);
- }
-
- output.push({
- "paragraphNo": paragraphNo,
- "paragraphLineFrom": paragraph_line_range.from,
- "paragraphLineTo": paragraph_line_range.to,
- "diffLineFrom": affected_lines.from,
- "diffLineTo": affected_lines.to,
- "textPre": textPre,
- "text": text,
- "textPost": textPost
- });
- });
-
- diffCache.put(cacheKey, output);
-
- return output;
- },
- getAmendmentParagraphsLinesDiff: function (versionId) {
- /*
- * @param versionId [if undefined, active_version will be used]
- *
- */
- return this.getAmendmentParagraphsLinesByMode('diff', versionId, true);
- },
- getAmendmentsAffectedLinesChanged: function () {
- var paragraph_diff = this.getAmendmentParagraphsByMode("diff")[0],
- affected_lines = diffService.detectAffectedLineRange(paragraph_diff.text);
-
- var extracted_lines = diffService.extractRangeByLineNumbers(paragraph_diff.text, affected_lines.from, affected_lines.to);
-
- var diff_html = extracted_lines.outerContextStart + extracted_lines.innerContextStart +
- extracted_lines.html + extracted_lines.innerContextEnd + extracted_lines.outerContextEnd;
- diff_html = diffService.diffHtmlToFinalText(diff_html);
-
- return {
- "line_from": affected_lines.from,
- "line_to": affected_lines.to,
- "text": diff_html
- };
- },
- getUnifiedChangeObject: function () {
- var paragraph = this.getAmendmentParagraphsByMode("diff")[0];
- var affected_lines = diffService.detectAffectedLineRange(paragraph.text);
-
- if (!affected_lines) {
- // no changes, no object to use
- return null;
- }
-
- var extracted_lines = diffService.extractRangeByLineNumbers(paragraph.text, affected_lines.from, affected_lines.to);
- var lineLength = Config.get('motions_line_length').value;
-
- var diff_html = diffService.formatDiffWithLineNumbers(extracted_lines, lineLength, affected_lines.from);
-
- var acceptance_state = null;
- var rejection_state = null;
- this.state.getRecommendations().forEach(function(state) {
- if (state.name === "accepted") {
- acceptance_state = state.id;
- }
- if (state.name === "rejected") {
- rejection_state = state.id;
- }
- });
-
- // The interface of this object needs to be synchronized with the same method in MotionChangeRecommendation
- //
- // The change object needs to be cached to prevent confusing Angular's change detection
- // Otherwise, a new object would be created with every call, leading to flickering
- var amendment = this;
-
- if (this._change_object === undefined) {
- // Properties that are guaranteed to be constant
- this._change_object = {
- "type": "amendment",
- "id": "amendment-" + amendment.id,
- "original": amendment,
- "saveStatus": function () {
- // The status needs to be reset first, as the workflow does not allow changing from
- // acceptance to rejection directly or vice-versa.
- amendment.setState(null).then(function () {
- if (amendment._change_object.accepted) {
- amendment.setState(acceptance_state);
- }
- if (amendment._change_object.rejected) {
- amendment.setState(rejection_state);
- }
- });
- },
- "getDiff": function (motion, version, highlight) {
- if (highlight > 0) {
- diff_html = lineNumberingService.highlightLine(diff_html, highlight);
- }
- return diff_html;
- }
- };
- }
-
- // Properties that might change when the Amendment is edited
- this._change_object.line_from = affected_lines.from;
- this._change_object.line_to = affected_lines.to;
-
- this._change_object.accepted = false;
- this._change_object.rejected = false;
- if (this.state && this.state.name === 'rejected') {
- this._change_object.rejected = true;
- } else if (this.state && this.state.name === 'accepted') {
- this._change_object.accepted = true;
- } else if (this.recommendation && this.recommendation.name === 'rejected') {
- this._change_object.rejected = true;
- }
-
- UnifiedChangeObjectCollission.populate(this._change_object);
-
- return this._change_object;
- },
- setTextStrippingLineBreaks: function (text) {
- this.text = lineNumberingService.stripLineNumbers(text);
- },
- setModifiedFinalVersionStrippingLineBreaks: function (html) {
- this.modified_final_version = lineNumberingService.stripLineNumbers(html);
- },
- // Copies to final version to the modified_final_version field
- copyModifiedFinalVersionStrippingLineBreaks: function () {
- var finalVersion = this.getTextByMode('agreed');
- this.setModifiedFinalVersionStrippingLineBreaks(finalVersion);
- },
- getModifiedFinalVersion: function (versionId) {
- return this.getVersion(versionId).modified_final_version;
- },
- getReason: function (versionId) {
- return this.getVersion(versionId).reason;
- },
- // full state name - optional with custom state name extension
- // depended by state and provided by a custom comment field
- getStateName: function () {
- var name = '';
- if (this.state) {
- name = gettextCatalog.getString(this.state.name);
- if (this.state.show_state_extension_field) {
- // check motion comment fields for flag 'forState'
- var commentFieldForStateId = MotionComment.getFieldIdForFlag('forState');
- if (commentFieldForStateId > -1) {
- name += ' ' + this.comments[commentFieldForStateId];
- }
- }
- }
- return MotionStateAndRecommendationParser.parse(name);
- },
- // ID of the state - or null, if to be reset
- setState: function(state_id) {
- if (state_id === null) {
- return $http.put('/rest/motions/motion/' + this.id + '/set_state/', {});
- } else {
- return $http.put('/rest/motions/motion/' + this.id + '/set_state/', {'state': state_id});
- }
- },
- // full recommendation string - optional with custom recommendationextension
- // depended by state and provided by a custom comment field
- getRecommendationName: function () {
- var recommendation = '';
- if (Config.get('motions_recommendations_by').value !== '' && this.recommendation) {
- recommendation = gettextCatalog.getString(this.recommendation.recommendation_label);
- if (this.recommendation.show_recommendation_extension_field) {
- // check motion comment fields for flag 'forRecommendation'
- var commentFieldForRecommendationId = MotionComment.getFieldIdForFlag('forRecommendation');
- if (commentFieldForRecommendationId > -1) {
- recommendation += ' ' + this.comments[commentFieldForRecommendationId];
- }
- }
- }
- return MotionStateAndRecommendationParser.parse(recommendation);
- },
- // ID of the state - or null, if to be reset
- setRecommendation: function(recommendation_id) {
- if (recommendation_id === null) {
- return $http.put('/rest/motions/motion/' + this.id + '/set_recommendation/', {});
- } else {
- return $http.put('/rest/motions/motion/' + this.id + '/set_recommendation/', {'recommendation': recommendation_id});
- }
- },
- // link name which is shown in search result
- getSearchResultName: function () {
- return this.getTitle();
- },
- // return true if a specific relation matches for given searchquery
- // e.g. submitter, supporters or category
- hasSearchResult: function (results, searchquery) {
- var motion = this;
- // search for submitters and supporters (check if any user.id from already found users matches)
- var foundSomething = _.some(results, function(result) {
- if (result.getResourceName() === "users/user") {
- if (_.some(motion.submitters, {'id': result.id})) {
- return true;
- } else if (_.some(motion.supporters, { 'id': result.id })) {
- return true;
- }
- }
- });
- // search for category
- if (!foundSomething && motion.category && motion.category.name.match(new RegExp(searchquery, 'i'))) {
- foundSomething = true;
- }
-
- // search for change recommendation
- if (!foundSomething) {
- var recommendations = MotionChangeRecommendation.filter({
- where: {motion_version_id: this.active_version}
- });
- foundSomething = _.some(recommendations, function(recommendation) {
- if (recommendation.text.match(new RegExp(searchquery, 'i'))) {
- return true;
- }
- });
- }
- return foundSomething;
- },
- getTextChangeRecommendations: function (versionId, order) {
- /*
- * Returns all change recommendations for this given version, sorted by line
- * @param versionId
- * @param order ['DESC' or 'ASC' (default)]
- * @returns {*}
- */
- versionId = versionId || this.active_version;
- order = order || 'ASC';
- return MotionChangeRecommendation.filter({
- where: {
- motion_version_id: versionId
- },
- orderBy: [
- ['line_from', order]
- ]
- }).filter(function(change) {
- return change.isTextRecommendation();
- });
- },
- getTitleChangeRecommendation: function (versionId) {
- /**
- * Returns the change recommendation affecting the title, or null
- * @param versionId
- * @returns MotionChangeRecommendation|null
- */
- versionId = versionId || this.active_version;
- var changes = MotionChangeRecommendation.filter({
- where: {
- motion_version_id: versionId,
- line_from: 0,
- line_to: 0
- }
- });
- return (changes.length > 0 ? changes[0] : null);
- },
- getAmendments: function () {
- return DS.filter('motions/motion', {parent_id: this.id});
- },
- hasAmendments: function () {
- return DS.filter('motions/motion', {parent_id: this.id}).length > 0;
- },
- getParagraphBasedAmendments: function () {
- return DS.filter('motions/motion', {parent_id: this.id}).filter(function(amendment) {
- return (amendment.isParagraphBasedAmendment());
- });
- },
- getParagraphBasedAmendmentsForDiffView: function () {
- return _.filter(this.getParagraphBasedAmendments(), function(amendment) {
- // If no accepted/rejected status is given, only amendments that have a recommendation
- // of "accepted" and have not been officially rejected are to be shown in the diff-view
- if (amendment.state && amendment.state.name === 'rejected') {
- return false;
- }
- if (amendment.state && amendment.state.name === 'accepted') {
- return true;
- }
- return (amendment.recommendation && amendment.recommendation.name === 'accepted');
- });
- },
- getParentMotion: function () {
- if (this.parent_id > 0) {
- var parents = DS.filter('motions/motion', {id: this.parent_id});
- if (parents.length > 0) {
- return parents[0];
- } else {
- return null;
- }
- } else {
- return null;
- }
- },
- isAllowed: function (action) {
- /*
- * Return true if the requested user is allowed to do the specific action.
- * There are the following possible actions.
- * - see
- * - update
- * - update_submitters
- * - delete
- * - create_poll
- * - support
- * - unsupport
- * - change_state
- * - reset_state
- * - change_comments
- * - change_recommendation
- * - can_manage
- * - can_see_amendments
- * - can_create_amendments
- *
- * NOTE: If you update this function please think about
- * server permissions, see motions/views.py.
- */
- switch (action) {
- case 'see':
- return (
- operator.hasPerms('motions.can_see') &&
- (
- !this.state.required_permission_to_see ||
- operator.hasPerms(this.state.required_permission_to_see) ||
- (operator.user in this.submitters)
- )
- );
- case 'update':
- return (
- operator.hasPerms('motions.can_manage') ||
- (
- (_.indexOf(this.submitters, operator.user) !== -1) &&
- this.state.allow_submitter_edit
- )
- );
- case 'update_submitters':
- return operator.hasPerms('motions.can_manage');
- case 'delete':
- return (
- operator.hasPerms('motions.can_manage') ||
- (
- (_.indexOf(this.submitters, operator.user) !== -1) &&
- this.state.allow_submitter_edit
- )
- );
- case 'create_poll':
- return (
- operator.hasPerms('motions.can_manage') &&
- this.state &&
- this.state.allow_create_poll
- );
- case 'support':
- return (
- operator.hasPerms('motions.can_support') &&
- this.state.allow_support &&
- Config.get('motions_min_supporters').value > 0 &&
- (_.indexOf(this.submitters, operator.user) === -1) &&
- (_.indexOf(this.supporters, operator.user) === -1)
- );
- case 'unsupport':
- return this.state.allow_support && _.indexOf(this.supporters, operator.user) !== -1;
- case 'change_state':
- return operator.hasPerms('motions.can_manage');
- case 'reset_state':
- return operator.hasPerms('motions.can_manage');
- case 'change_comments':
- return operator.hasPerms('motions.can_manage_comments');
- case 'change_recommendation':
- return operator.hasPerms('motions.can_manage');
- case 'can_manage':
- return operator.hasPerms('motions.can_manage');
- case 'can_see_amendments':
- var result;
- if (operator.hasPerms('motions.can_create')) {
- result = Config.get('motions_amendments_enabled').value &&
- (this.hasAmendments() || this.isAllowed('can_create_amendment'));
- } else if (operator.hasPerms('motions.can_see')) {
- result = Config.get('motions_amendments_enabled').value && this.hasAmendments();
- }
- return result;
- case 'can_create_amendment':
- return (
- operator.hasPerms('motions.can_create') &&
- Config.get('motions_amendments_enabled').value &&
- ( !this.isAmendment ||
- (this.isAmendment && OpenSlidesSettings.MOTIONS_ALLOW_AMENDMENTS_OF_AMENDMENTS))
- );
- default:
- return false;
- }
- },
- /* Overrides from jsDataModel factory.
- * Also sets the projection mode if given; If not it projects in 'original' mode. */
- project: function (projectorId, mode) {
- // if this object is already projected on projectorId, delete this element from this projector
- var requestData = {
- clear_ids: this.isProjected(),
- };
- // Was there a projector with the same id and mode as the given id and mode?
- // If not, project the motion.
- var wasProjectedBefore = _.some(this.isProjectedWithMode(), function (mapping) {
- var value = (mapping.projectorId === projectorId);
- if (mode) {
- value = value && (mapping.mode === mode);
- }
- return value;
- });
- mode = mode || Config.get('motions_recommendation_text_mode').value;
- if (!wasProjectedBefore) {
- requestData.prune = {
- id: projectorId,
- element: {
- name: name,
- id: this.id,
- mode: mode,
- },
- };
- }
- return ProjectHelper.project(requestData);
- },
- isProjected: function (mode) {
- var self = this;
- var predicate = function (element) {
- var value = element.name === name &&
- element.id === self.id;
- if (mode) {
- value = value && (element.mode === mode);
- }
- return value;
- };
- var projectorIds = [];
- _.forEach(Projector.getAll(), function (projector) {
- if (typeof _.findKey(projector.elements, predicate) === 'string') {
- projectorIds.push(projector.id);
- }
- });
- return projectorIds;
- },
- /* returns a list of mappings between projector id and mode:
- * [ {projectorId: 2, mode: 'original'}, ... ] */
- isProjectedWithMode: function () {
- var self = this;
- var mapping = [];
- _.forEach(Projector.getAll(), function (projector) {
- _.forEach(projector.elements, function (element) {
- if (element.name === name && element.id === self.id) {
- mapping.push({
- projectorId: projector.id,
- mode: element.mode || 'original',
- });
- }
- });
- });
- return mapping;
- },
- isRelatedProjected: function () {
- // A motion related object is the list of speakers (through the agenda item)
- if (this.agenda_item) {
- return this.agenda_item.isListOfSpeakersProjected();
- } else {
- return [];
- }
- },
- },
- relations: {
- belongsTo: {
- 'motions/category': {
- localField: 'category',
- localKey: 'category_id',
- },
- 'motions/motion-block': {
- localField: 'motionBlock',
- localKey: 'motion_block_id',
- },
- 'agenda/item': {
- localKey: 'agenda_item_id',
- localField: 'agenda_item',
- }
- },
- hasMany: {
- 'core/tag': {
- localField: 'tags',
- localKeys: 'tags_id',
- },
- 'mediafiles/mediafile': {
- localField: 'attachments',
- localKeys: 'attachments_id',
- },
- 'users/user': {
- localField: 'supporters',
- localKeys: 'supporters_id',
- },
- 'motions/motion-poll': {
- localField: 'polls',
- foreignKey: 'motion_id',
- },
- 'motions/submitter': {
- localField: 'submitters',
- foreignKey: 'motion_id',
- },
- },
- hasOne: {
- 'motions/state': [
- {
- localField: 'state',
- localKey: 'state_id',
- },
- {
- localField: 'recommendation',
- localKey: 'recommendation_id',
- }
- ]
- }
- }
- });
- }
-])
-
-// Service for generic comment fields
-.factory('MotionComment', [
- '$filter',
- 'Config',
- 'operator',
- 'Editor',
- function ($filter, Config, operator, Editor) {
- return {
- isSpecialCommentField: function (field) {
- if (field) {
- return field.forState || field.forRecommendation;
- } else {
- return false;
- }
- },
- getCommentsFields: function () {
- var fields = Config.get('motions_comments').value;
- return $filter('excludeDeletedAndForbiddenCommentsFields')(fields);
- },
- getNoSpecialCommentsFields: function () {
- var fields = this.getCommentsFields();
- return $filter('excludeSpecialCommentsFields')(fields);
- },
- getFormFields: function () {
- var fields = this.getNoSpecialCommentsFields();
- return _.map(fields, function (field, id) {
- return {
- key: 'comment_' + id,
- type: 'editor',
- templateOptions: {
- label: field.name,
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- },
- hide: !operator.hasPerms("motions.can_manage_comments")
- };
- }
- );
- },
- getFormField : function (id) {
- var fields = this.getNoSpecialCommentsFields();
- var field = fields[id];
- if (field) {
- return {
- key: 'comment_' + id,
- type: 'editor',
- templateOptions: {
- label: field.name,
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- },
- hide: !operator.hasPerms("motions.can_manage_comments")
- };
- }
- },
- populateFields: function (motion) {
- // Populate content of motion.comments to the single comment
- var fields = this.getCommentsFields();
- if (motion.comments) {
- _.forEach(fields, function (field, id) {
- motion['comment_' + id] = motion.comments[id];
- });
- }
- },
- populateFieldsReverse: function (motion) {
- // Reverse equivalent to populateFields.
- var fields = this.getCommentsFields();
- motion.comments = {};
- _.forEach(fields, function (field, id) {
- motion.comments[id] = motion['comment_' + id] || '';
- });
- },
- getFieldIdForFlag: function (flag) {
- var fields = this.getCommentsFields();
- return _.findKey(fields, [flag, true]);
- },
- };
- }
-])
-
-.filter('excludeSpecialCommentsFields', [
- 'MotionComment',
- function (MotionComment) {
- return function (commentsFields) {
- var withoutSpecialCommentsFields = {};
- _.forEach(commentsFields, function (field, id) {
- if (!MotionComment.isSpecialCommentField(field)) {
- withoutSpecialCommentsFields[id] = field;
- }
- });
- return withoutSpecialCommentsFields;
- };
- }
-])
-
-.filter('excludeDeletedAndForbiddenCommentsFields', [
- 'MotionComment',
- 'operator',
- function (MotionComment, operator) {
- return function (commentsFields) {
- var withoutDeletedAndForbiddenCommentsFields = {};
- _.forEach(commentsFields, function (field, id) {
- if (field && (field.public || operator.hasPerms('motions.can_see_comments'))) {
- withoutDeletedAndForbiddenCommentsFields[id] = field;
- }
- });
- return withoutDeletedAndForbiddenCommentsFields;
- };
- }
-])
-
-.factory('Category', [
- 'DS',
- function(DS) {
- return DS.defineResource({
- name: 'motions/category',
- });
- }
-])
-
-.factory('MotionChangeRecommendation', [
- 'DS',
- 'Config',
- 'jsDataModel',
- 'diffService',
- 'lineNumberingService',
- 'UnifiedChangeObjectCollission',
- 'gettextCatalog',
- function (DS, Config, jsDataModel, diffService, lineNumberingService,
- UnifiedChangeObjectCollission, gettextCatalog) {
- return DS.defineResource({
- name: 'motions/motion-change-recommendation',
- useClass: jsDataModel,
- methods: {
- saveStatus: function() {
- this.DSSave();
- },
- isTitleRecommendation: function() {
- return (this.line_from === 0 && this.line_to === 0);
- },
- isTextRecommendation: function() {
- return (this.line_from !== 0 || this.line_to !== 0);
- },
- getDiff: function(motion, version, highlight) {
- var lineLength = Config.get('motions_line_length').value,
- html = lineNumberingService.insertLineNumbers(motion.getVersion(version).text, lineLength),
- data, oldText;
-
- try {
- data = diffService.extractRangeByLineNumbers(html, this.line_from, this.line_to);
- oldText = data.outerContextStart + data.innerContextStart +
- data.html + data.innerContextEnd + data.outerContextEnd;
- } catch (e) {
- // This only happens (as far as we know) when the motion text has been altered (shortened)
- // without modifying the change recommendations accordingly.
- // That's a pretty serious inconsistency that should not happen at all,
- // we're just doing some basic damage control here.
- var msg = 'Inconsistent data. A change recommendation is probably referring to a non-existant line number.';
- return '' + msg + ' ';
- }
- oldText = lineNumberingService.insertLineNumbers(oldText, lineLength, null, null, this.line_from);
- var diff = diffService.diff(oldText, this.text);
-
- // If an insertion makes the line longer than the line length limit, we need two line breaking runs:
- // - First, for the official line numbers, ignoring insertions (that's been done some lines before)
- // - Second, another one to prevent the displayed including insertions to exceed the page width
- diff = lineNumberingService.insertLineBreaksWithoutNumbers(diff, lineLength, true);
-
- if (highlight > 0) {
- diff = lineNumberingService.highlightLine(diff, highlight);
- }
-
- var origBeginning = data.outerContextStart + data.innerContextStart;
- if (diff.toLowerCase().indexOf(origBeginning.toLowerCase()) === 0) {
- // Add "merge-before"-css-class if the first line begins in the middle of a paragraph. Used for PDF.
- diff = diffService.addCSSClassToFirstTag(origBeginning, "merge-before") + diff.substring(origBeginning.length);
- }
-
- return diff;
- },
- getType: function(original_full_html) {
- return this.type;
- },
- getTitle: function(original_full_html) {
- var title;
- if (this.line_to > (this.line_from + 1)) {
- title = gettextCatalog.getString('%TYPE% from line %FROM% to %TO%');
- } else {
- title = gettextCatalog.getString('%TYPE% in line %FROM%');
- }
- switch (this.getType(original_full_html)) {
- case diffService.TYPE_INSERTION:
- title = title.replace('%TYPE%', gettextCatalog.getString('Insertion'));
- break;
- case diffService.TYPE_DELETION:
- title = title.replace('%TYPE%', gettextCatalog.getString('Deletion'));
- break;
- case diffService.TYPE_REPLACEMENT:
- title = title.replace('%TYPE%', gettextCatalog.getString('Replacement'));
- break;
- case diffService.TYPE_OTHER:
- title = title.replace('%TYPE%', this.other_description);
- break;
- }
- title = title.replace('%FROM%', this.line_from).replace('%TO%', (this.line_to - 1));
- return title;
- },
- getUnifiedChangeObject: function () {
- // The interface of this object needs to be synchronized with the same method in Motion
- //
- // The change object needs to be cached to prevent confusing Angular's change detection
- // Otherwise, a new object would be created with every call, leading to flickering
- var recommendation = this;
-
- if (this._change_object === undefined) {
- // Properties that are guaranteed to be constant
- this._change_object = {
- "type": "recommendation",
- "other_description": recommendation.other_description,
- "id": "recommendation-" + recommendation.id,
- "original": recommendation,
- "saveStatus": function () {
- recommendation.rejected = recommendation._change_object.rejected;
- recommendation.saveStatus();
- },
- "getDiff": function (motion, version, highlight) {
- return recommendation.getDiff(motion, version, highlight);
- }
- };
- }
- // Properties that might change when the Change Recommendation is edited
- this._change_object.line_from = recommendation.line_from;
- this._change_object.line_to = recommendation.line_to;
- this._change_object.rejected = recommendation.rejected;
- this._change_object.accepted = !recommendation.rejected;
-
- UnifiedChangeObjectCollission.populate(this._change_object);
-
- return this._change_object;
- }
- }
- });
- }
-])
-
-.factory('UnifiedChangeObjectCollission', [
- function () {
- return {
- populate: function (obj) {
- obj.otherChanges = [];
- obj.setOtherChangesForCollission = function (changes) {
- obj.otherChanges = changes;
- };
- obj.getCollissions = function(onlyAccepted) {
- return obj.otherChanges.filter(function(otherChange) {
- if (onlyAccepted && !otherChange.accepted) {
- return false;
- }
- return (otherChange.id !== obj.id && (
- (otherChange.line_from >= obj.line_from && otherChange.line_from < obj.line_to) ||
- (otherChange.line_to > obj.line_from && otherChange.line_to <= obj.line_to) ||
- (otherChange.line_from < obj.line_from && otherChange.line_to > obj.line_to)
- ));
- });
- };
- obj.getAcceptedCollissions = function() {
- return obj.getCollissions().filter(function(colliding) {
- return colliding.accepted;
- });
- };
- obj.setAccepted = function($event) {
- if (obj.getAcceptedCollissions().length > 0) {
- $event.preventDefault();
- $event.stopPropagation();
- return;
- }
- obj.accepted = true;
- obj.rejected = false;
- obj.saveStatus();
- };
- obj.setRejected = function($event) {
- obj.rejected = true;
- obj.accepted = false;
- obj.saveStatus();
- };
- },
- };
- }
-])
-
-.run([
- 'Motion',
- 'Category',
- 'Workflow',
- 'MotionState',
- 'MotionChangeRecommendation',
- 'Submitter',
- function(Motion, Category, Workflow, MotionState, MotionChangeRecommendation, Submitter) {}
-])
-
-
-// Mark all motion workflow state strings for translation in JavaScript.
-// (see motions/signals.py)
-.config([
- 'gettext',
- function (gettext) {
- // workflow 1
- gettext('Simple Workflow');
- gettext('submitted');
- gettext('accepted');
- gettext('Accept');
- gettext('Acceptance');
- gettext('rejected');
- gettext('Reject');
- gettext('Rejection');
- gettext('not decided');
- gettext('Do not decide');
- gettext('No decision');
- // workflow 2
- gettext('Complex Workflow');
- gettext('published');
- gettext('permitted');
- gettext('Permit');
- gettext('Permission');
- gettext('accepted');
- gettext('Accept');
- gettext('Acceptance');
- gettext('rejected');
- gettext('Reject');
- gettext('Rejection');
- gettext('withdrawed');
- gettext('Withdraw');
- gettext('adjourned');
- gettext('Adjourn');
- gettext('Adjournment');
- gettext('not concerned');
- gettext('Do not concern');
- gettext('No concernment');
- gettext('refered to committee');
- gettext('Refer to committee');
- gettext('Referral to committee');
- gettext('needs review');
- gettext('Needs review');
- gettext('rejected (not authorized)');
- gettext('Reject (not authorized)');
- gettext('Rejection (not authorized)');
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/csv.js b/openslides/motions/static/js/motions/csv.js
deleted file mode 100644
index b236569bd..000000000
--- a/openslides/motions/static/js/motions/csv.js
+++ /dev/null
@@ -1,210 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.csv', [])
-
-.factory('MotionCsvExport', [
- '$filter',
- 'gettextCatalog',
- 'Config',
- 'CsvDownload',
- 'lineNumberingService',
- function ($filter, gettextCatalog, Config, CsvDownload, lineNumberingService) {
- var makeHeaderline = function (params) {
- var headerline = ['Identifier', 'Title'];
- if (params.include.text) {
- headerline.push('Text');
- }
- if (params.include.reason) {
- headerline.push('Reason');
- }
- if (params.include.submitters) {
- headerline.push('Submitter');
- }
- headerline.push('Category');
- if (params.include.origin) {
- headerline.push('Origin');
- }
- if (params.include.motionBlock) {
- headerline.push('Motion block');
- }
- return _.map(headerline, function (entry) {
- return gettextCatalog.getString(entry);
- });
- };
- return {
- export: function (motions, params) {
- if (!params) {
- params = {};
- }
- _.defaults(params, {
- changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
- include: {
- text: true,
- reason: true,
- submitters: true,
- origin: true,
- motionBlock: true,
- state: true,
- recommendation: true,
- },
- });
- params.filename = gettextCatalog.getString('motions') + '.csv';
- if (!_.includes(['original', 'changed', 'agreed'], params.changeRecommendationMode)) {
- params.changeRecommendationMode = 'original';
- }
-
- var csvRows = [
- makeHeaderline(params)
- ];
- _.forEach(motions, function (motion) {
- var text = motion.getTextByMode(params.changeRecommendationMode, null, null, false);
- var row = [];
- // Identifier and title
- row.push('"' + motion.identifier !== null ? motion.identifier : '' + '"');
- row.push('"' + motion.getTitle() + '"');
-
- // Text
- if (params.include.text) {
- row.push('"' + text + '"');
- }
-
- // Reason
- if (params.include.reason) {
- row.push('"' + motion.getReason() + '"');
- }
-
- // Submitters
- if (params.include.submitters) {
- var submitters = [];
- _.forEach($filter('orderBy')(motion.submitters, 'weight'), function (user) {
- var user_short_name = [
- user.user.title,
- user.user.first_name,
- user.user.last_name
- ].join(' ').trim();
- submitters.push(user_short_name);
- });
- row.push('"' + submitters.join('; ') + '"');
- }
-
- // Category
- var category = motion.category ? motion.category.name : '';
- row.push('"' + category + '"');
-
- // Origin
- if (params.include.origin) {
- row.push('"' + motion.origin + '"');
- }
-
- // Motion block
- if (params.include.motionBlock) {
- var blockTitle = motion.motionBlock ? motion.motionBlock.title : '';
- row.push('"' + blockTitle + '"');
- }
-
- csvRows.push(row);
- });
- CsvDownload(csvRows, params.filename);
- },
- downloadExample: function () {
- var csvRows = [makeHeaderline({ include: {
- text: true,
- reason: true,
- submitters: true,
- origin: true,
- motionBlock: true,
- state: true,
- recommendation: true,
- }}),
- // example entries
- ['A1', 'Title 1', 'Text 1', 'Reason 1', 'Submitter A', 'Category A', 'Last Year Conference A', 'Block A'],
- ['B1', 'Title 2', 'Text 2', 'Reason 2', 'Submitter B', 'Category B', '', 'Block A'],
- ['' , 'Title 3', 'Text 3', '', '', '', '', ''],
- ];
- CsvDownload(csvRows, gettextCatalog.getString('motions-example') + '.csv');
- },
- };
- }
-])
-
-.factory('AmendmentCsvExport', [
- 'gettextCatalog',
- 'CsvDownload',
- 'lineNumberingService',
- function (gettextCatalog, CsvDownload, lineNumberingService) {
- var makeHeaderline = function () {
- var headerline = ['Identifier', 'Submitters', 'Category', 'Motion block',
- 'Leadmotion', 'Line', 'Old text', 'New text'];
- return _.map(headerline, function (entry) {
- return gettextCatalog.getString(entry);
- });
- };
- return {
- export: function (amendments) {
- var csvRows = [
- makeHeaderline()
- ];
- _.forEach(amendments, function (amendment) {
- var row = [];
- // Identifier and title
- row.push('"' + amendment.identifier !== null ? amendment.identifier : '' + '"');
- // Submitters
- var submitters = [];
- angular.forEach(amendment.submitters, function(user) {
- var user_short_name = [user.title, user.first_name, user.last_name].join(' ').trim();
- submitters.push(user_short_name);
- });
- row.push('"' + submitters.join('; ') + '"');
-
- // Category
- var category = amendment.category ? amendment.category.name : '';
- row.push('"' + category + '"');
-
- // Motion block
- var blockTitle = amendment.motionBlock ? amendment.motionBlock.title : '';
- row.push('"' + blockTitle + '"');
-
- // Lead motion
- var leadmotion = amendment.getParentMotion();
- if (leadmotion) {
- var leadmotionTitle = leadmotion.identifier ? leadmotion.identifier + ': ' : '';
- leadmotionTitle += leadmotion.getTitle();
- row.push('"' + leadmotionTitle + '"');
- } else {
- row.push('""');
- }
-
- // changed paragraph
- if (amendment.isParagraphBasedAmendment()) {
- // TODO: get old and new paragraphLine. Resolve todo
- // in motion.getAmendmentParagraphsLinesByMode
- var p_old = amendment.getAmendmentParagraphsLinesByMode('original', null, false)[0];
- //var p_new = amendment.getAmendmentParagraphsLinesByMode('changed', null, false)[0];
- var lineStr = p_old.diffLineFrom;
- if (p_old.diffLineTo != p_old.diffLineFrom + 1) {
- lineStr += '-' + p_old.diffLineTo;
- }
- row.push('"' + lineStr + '"');
- //row.push('"' + p_old.text.html + '"');
- //row.push('"' + p_new.text.html + '"');
-
- // Work around: Export the full paragraphs instead of changed lines
- row.push('"' + amendment.getAmendmentParagraphsByMode('original', null, false)[0].text + '"');
- row.push('"' + amendment.getAmendmentParagraphsByMode('changed', null, false)[0].text + '"');
- } else {
- row.push('""');
- row.push('""');
- row.push('"' + amendment.getText() + '"');
- }
-
- csvRows.push(row);
- });
- CsvDownload(csvRows, 'amendments-export.csv');
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/diff.js b/openslides/motions/static/js/motions/diff.js
deleted file mode 100644
index d6abfbf65..000000000
--- a/openslides/motions/static/js/motions/diff.js
+++ /dev/null
@@ -1,1589 +0,0 @@
-(function () {
-
-"use strict";
-
-angular.module('OpenSlidesApp.motions.diff', ['OpenSlidesApp.motions.lineNumbering'])
-
-.service('diffService', [
- 'lineNumberingService',
- '$cacheFactory',
- function (lineNumberingService, $cacheFactory) {
- var ELEMENT_NODE = 1,
- TEXT_NODE = 3,
- DOCUMENT_FRAGMENT_NODE = 11;
-
- var diffCache = $cacheFactory('diff.service');
-
- this.TYPE_REPLACEMENT = 0;
- this.TYPE_INSERTION = 1;
- this.TYPE_DELETION = 2;
- this.TYPE_OTHER = 3;
-
- this.getLineNumberNode = function(fragment, lineNumber) {
- return fragment.querySelector('os-linebreak.os-line-number.line-number-' + lineNumber);
- };
-
- /**
- * @param {Element} element
- */
- this._getFirstLineNumberNode = function(element) {
- if (element.nodeType === TEXT_NODE) {
- return null;
- }
- if (element.nodeName === 'OS-LINEBREAK') {
- return element;
- }
- var found = element.querySelectorAll('OS-LINEBREAK');
- if (found.length > 0) {
- return found.item(0);
- } else {
- return null;
- }
- };
-
- /**
- * @param {Element} element
- */
- this._getLastLineNumberNode = function(element) {
- if (element.nodeType === TEXT_NODE) {
- return null;
- }
- if (element.nodeName === 'OS-LINEBREAK') {
- return element;
- }
- var found = element.querySelectorAll('OS-LINEBREAK');
- if (found.length > 0) {
- return found.item(found.length - 1);
- } else {
- return null;
- }
- };
-
- this._getNodeContextTrace = function(node) {
- var context = [],
- currNode = node;
- while (currNode) {
- context.unshift(currNode);
- currNode = currNode.parentNode;
- }
- return context;
- };
-
- this._isFirstNonemptyChild = function(node, child) {
- for (var i = 0; i < node.childNodes.length; i++) {
- if (node.childNodes[i] === child) {
- return true;
- }
- if (node.childNodes[i].nodeType !== TEXT_NODE || node.childNodes[i].nodeValue.match(/\S/)) {
- return false;
- }
- }
- return false;
- };
-
- // Adds elements like
- this._insertInternalLineMarkers = function(fragment) {
- if (fragment.querySelectorAll('OS-LINEBREAK').length > 0) {
- // Prevent duplicate calls
- return;
- }
- var lineNumbers = fragment.querySelectorAll('span.os-line-number'),
- lineMarker, maxLineNumber;
-
- for (var i = 0; i < lineNumbers.length; i++) {
- var insertBefore = lineNumbers[i];
- while (insertBefore.parentNode.nodeType !== DOCUMENT_FRAGMENT_NODE &&
- this._isFirstNonemptyChild(insertBefore.parentNode, insertBefore)) {
- insertBefore = insertBefore.parentNode;
- }
- lineMarker = document.createElement('OS-LINEBREAK');
- lineMarker.setAttribute('data-line-number', lineNumbers[i].getAttribute('data-line-number'));
- lineMarker.setAttribute('class', lineNumbers[i].getAttribute('class'));
- insertBefore.parentNode.insertBefore(lineMarker, insertBefore);
- maxLineNumber = lineNumbers[i].getAttribute('data-line-number');
- }
-
- // Add one more "fake" line number at the end and beginning, so we can select the last line as well
- lineMarker = document.createElement('OS-LINEBREAK');
- lineMarker.setAttribute('data-line-number', (parseInt(maxLineNumber) + 1));
- lineMarker.setAttribute('class', 'os-line-number line-number-' + (parseInt(maxLineNumber) + 1));
- fragment.appendChild(lineMarker);
-
- lineMarker = document.createElement('OS-LINEBREAK');
- lineMarker.setAttribute('data-line-number', '0');
- lineMarker.setAttribute('class', 'os-line-number line-number-0');
- fragment.insertBefore(lineMarker, fragment.firstChild);
- };
-
- // @TODO Check if this is actually necessary
- this._insertInternalLiNumbers = function(fragment) {
- if (fragment.querySelectorAll('LI[os-li-number]').length > 0) {
- // Prevent duplicate calls
- return;
- }
- var ols = fragment.querySelectorAll('OL');
- for (var i = 0; i < ols.length; i++) {
- var ol = ols[i],
- liNo = 0;
- for (var j = 0; j < ol.childNodes.length; j++) {
- if (ol.childNodes[j].nodeName == 'LI') {
- liNo++;
- ol.childNodes[j].setAttribute('os-li-number', liNo);
- }
- }
- }
- };
-
- this._addStartToOlIfNecessary = function(node) {
- var firstLiNo = null;
- for (var i = 0; i < node.childNodes.length && firstLiNo === null; i++) {
- if (node.childNode[i].nodeName == 'LI') {
- var lineNo = node.childNode[i].getAttribute('ol-li-number');
- if (lineNo) {
- firstLiNo = parseInt(lineNo);
- }
- }
- }
- if (firstLiNo > 1) {
- node.setAttribute('start', firstLiNo);
- }
- };
-
- this._isWithinNthLIOfOL = function(olNode, descendantNode) {
- var nthLIOfOL = null;
- while (descendantNode.parentNode) {
- if (descendantNode.parentNode === olNode) {
- var lisBeforeOl = 0,
- foundMe = false;
- for (var i = 0; i < olNode.childNodes.length && !foundMe; i++) {
- if (olNode.childNodes[i] === descendantNode) {
- foundMe = true;
- } else if (olNode.childNodes[i].nodeName === 'LI') {
- lisBeforeOl++;
- }
- }
- nthLIOfOL = lisBeforeOl + 1;
- }
- descendantNode = descendantNode.parentNode;
- }
- return nthLIOfOL;
- };
-
- /*
- * Returns an array with the following values:
- * 0: the most specific DOM-node that contains both line numbers
- * 1: the context of node1 (an array of dom-elements; 0 is the document fragment)
- * 2: the context of node2 (an array of dom-elements; 0 is the document fragment)
- * 3: the index of [0] in the two arrays
- */
- this._getCommonAncestor = function(node1, node2) {
- var trace1 = this._getNodeContextTrace(node1),
- trace2 = this._getNodeContextTrace(node2),
- commonAncestor = null,
- commonIndex = null,
- childTrace1 = [],
- childTrace2 = [];
-
- for (var i = 0; i < trace1.length && i < trace2.length; i++) {
- if (trace1[i] == trace2[i]) {
- commonAncestor = trace1[i];
- commonIndex = i;
- }
- }
- for (i = commonIndex + 1; i < trace1.length; i++) {
- childTrace1.push(trace1[i]);
- }
- for (i = commonIndex + 1; i < trace2.length; i++) {
- childTrace2.push(trace2[i]);
- }
- return {
- 'commonAncestor': commonAncestor,
- 'trace1' : childTrace1,
- 'trace2' : childTrace2,
- 'index': commonIndex
- };
- };
-
- this._serializeTag = function(node) {
- if (node.nodeType === DOCUMENT_FRAGMENT_NODE) {
- // Fragments are only placeholders and do not have an HTML representation
- return '';
- }
- var html = '<' + node.nodeName;
- for (var i = 0; i < node.attributes.length; i++) {
- var attr = node.attributes[i];
- if (attr.name !== 'os-li-number') {
- html += ' ' + attr.name + '="' + attr.value + '"';
- }
- }
- html += '>';
- return html;
- };
-
- this._serializeDom = function(node, stripLineNumbers) {
- if (node.nodeType === TEXT_NODE) {
- return node.nodeValue.replace(//g, ">");
- }
- if (stripLineNumbers && (
- lineNumberingService._isOsLineNumberNode(node) || lineNumberingService._isOsLineBreakNode(node))) {
- return '';
- }
- if (node.nodeName === 'OS-LINEBREAK') {
- return '';
- }
- if (node.nodeName === 'BR') {
- var br = ' ';
- }
-
- var html = this._serializeTag(node);
- for (var i = 0; i < node.childNodes.length; i++) {
- if (node.childNodes[i].nodeType === TEXT_NODE) {
- html += node.childNodes[i].nodeValue.replace(/&/g, "&").replace(//g, ">");
- } else if (!stripLineNumbers || (!lineNumberingService._isOsLineNumberNode(node.childNodes[i]) && !lineNumberingService._isOsLineBreakNode(node.childNodes[i]))) {
- html += this._serializeDom(node.childNodes[i], stripLineNumbers);
- }
- }
- if (node.nodeType !== DOCUMENT_FRAGMENT_NODE) {
- html += '' + node.nodeName + '>';
- }
-
- return html;
- };
-
- /**
- * Implementation hint: the first element of "toChildTrace" array needs to be a child element of "node"
- */
- this._serializePartialDomToChild = function(node, toChildTrace, stripLineNumbers) {
- if (lineNumberingService._isOsLineNumberNode(node) || lineNumberingService._isOsLineBreakNode(node)) {
- return '';
- }
- if (node.nodeName === 'OS-LINEBREAK') {
- return '';
- }
-
- var html = this._serializeTag(node);
-
- for (var i = 0, found = false; i < node.childNodes.length && !found; i++) {
- if (node.childNodes[i] === toChildTrace[0]) {
- found = true;
- var remainingTrace = toChildTrace;
- remainingTrace.shift();
- if (!lineNumberingService._isOsLineNumberNode(node.childNodes[i])) {
- html += this._serializePartialDomToChild(node.childNodes[i], remainingTrace, stripLineNumbers);
- }
- } else if (node.childNodes[i].nodeType === TEXT_NODE) {
- html += node.childNodes[i].nodeValue;
- } else {
- if (!stripLineNumbers || (!lineNumberingService._isOsLineNumberNode(node.childNodes[i]) &&
- !lineNumberingService._isOsLineBreakNode(node.childNodes[i]))) {
- html += this._serializeDom(node.childNodes[i], stripLineNumbers);
- }
- }
- }
- if (!found) {
- console.trace();
- throw "Inconsistency or invalid call of this function detected (to)";
- }
- return html;
- };
-
- /**
- * Implementation hint: the first element of "toChildTrace" array needs to be a child element of "node"
- */
- this._serializePartialDomFromChild = function(node, fromChildTrace, stripLineNumbers) {
- if (lineNumberingService._isOsLineNumberNode(node) || lineNumberingService._isOsLineBreakNode(node)) {
- return '';
- }
- if (node.nodeName === 'OS-LINEBREAK') {
- return '';
- }
-
- var html = '';
- for (var i = 0, found = false; i < node.childNodes.length; i++) {
- if (node.childNodes[i] === fromChildTrace[0]) {
- found = true;
- var remainingTrace = fromChildTrace;
- remainingTrace.shift();
- if (!lineNumberingService._isOsLineNumberNode(node.childNodes[i])) {
- html += this._serializePartialDomFromChild(node.childNodes[i], remainingTrace, stripLineNumbers);
- }
- } else if (found) {
- if (node.childNodes[i].nodeType === TEXT_NODE) {
- html += node.childNodes[i].nodeValue;
- } else {
- if (!stripLineNumbers || (!lineNumberingService._isOsLineNumberNode(node.childNodes[i]) &&
- !lineNumberingService._isOsLineBreakNode(node.childNodes[i]))) {
- html += this._serializeDom(node.childNodes[i], stripLineNumbers);
- }
- }
- }
- }
- if (!found) {
- console.trace();
- throw "Inconsistency or invalid call of this function detected (from)";
- }
- if (node.nodeType !== DOCUMENT_FRAGMENT_NODE) {
- html += '' + node.nodeName + '>';
- }
- return html;
- };
-
- /**
- * @param {string} html
- * @return {DocumentFragment}
- */
- this.htmlToFragment = function(html) {
- var fragment = document.createDocumentFragment(),
- div = document.createElement('DIV');
- div.innerHTML = html;
- while (div.childElementCount) {
- var child = div.childNodes[0];
- div.removeChild(child);
- fragment.appendChild(child);
- }
- return fragment;
- };
-
- /**
- * When a with a os-split-before-class (set by extractRangeByLineNumbers) is edited when creating a
- * change recommendation and is split again in CKEditor, the second list items also gets that class.
- * This is not correct however, as the second one actually is a new list item. So we need to remove it again.
- *
- * @param {string} html
- * @returns {string}
- */
- this.removeDuplicateClassesInsertedByCkeditor = function(html) {
- var fragment = this.htmlToFragment(html);
- var items = fragment.querySelectorAll('li.os-split-before');
- for (var i = 0; i < items.length; i++) {
- if (!this._isFirstNonemptyChild(items[i].parentNode, items[i])) {
- this.removeCSSClass(items[i], 'os-split-before');
- }
- }
- return this._serializeDom(fragment, false);
- };
-
- /**
- * Returns the HTML snippet between two given line numbers.
- *
- * Hint:
- * - The last line (toLine) is not included anymore, as the number refers to the line breaking element at the end of the line
- * - if toLine === null, then everything from fromLine to the end of the fragment is returned
- *
- * In addition to the HTML snippet, additional information is provided regarding the most specific DOM element
- * that contains the whole section specified by the line numbers (like a P-element if only one paragraph is selected
- * or the most outer DIV, if multiple sections selected).
- *
- * This additional information is meant to render the snippet correctly without producing broken HTML
- *
- * The return object has the following fields:
- * - html: The HTML between the two line numbers.
- * Line numbers and automatically set line breaks are stripped.
- * All HTML tags are converted to uppercase
- * (e.g. Line 2 Line3 Line 4 )
- * - ancestor: the most specific DOM element that contains the HTML snippet (e.g. a UL, if several LIs are selected)
- * - outerContextStart: An HTML string that opens all necessary tags to get the browser into the rendering mode
- * of the ancestor element (e.g. in the case of the multiple LIs)
- * - outerContectEnd: An HTML string that closes all necessary tags from the ancestor element (e.g.
- * - innerContextStart: A string that opens all necessary tags between the ancestor
- * and the beginning of the selection (e.g. )
- * - innerContextEnd: A string that closes all tags after the end of the selection to the ancestor (e.g. )
- * - previousHtml: The HTML before the selected area begins (including line numbers)
- * - previousHtmlEndSnippet: A HTML snippet that closes all open tags from previousHtml
- * - followingHtml: The HTML after the selected area
- * - followingHtmlStartSnippet: A HTML snippet that opens all HTML tags necessary to render "followingHtml"
- *
- *
- * In some cases, the returned HTML tags receive additional CSS classes, providing information both for
- * rendering it and for merging it again correctly.
- * - os-split-*: These classes are set for all HTML Tags that have been split into two by this process,
- * e.g. if the fromLine- or toLine-line-break was somewhere in the middle of this tag.
- * If a tag is split, the first one receives "os-split-after", and the second one "os-split-before".
- * For example, for the following string Line 1 Line 2 Line 3
:
- * - extracting line 1 to 2 results in Line 1
- * - extracting line 2 to 3 results in Line 2
- * - extracting line 3 to null/4 results in Line 3
- */
- this.extractRangeByLineNumbers = function(htmlIn, fromLine, toLine) {
- if (typeof(htmlIn) !== 'string') {
- throw 'Invalid call - extractRangeByLineNumbers expects a string as first argument';
- }
-
- var cacheKey = fromLine + "-" + toLine + "-" + lineNumberingService.djb2hash(htmlIn),
- cached = diffCache.get(cacheKey);
-
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- var fragment = this.htmlToFragment(htmlIn);
-
- this._insertInternalLineMarkers(fragment);
- this._insertInternalLiNumbers(fragment);
- if (toLine === null) {
- var internalLineMarkers = fragment.querySelectorAll('OS-LINEBREAK');
- toLine = parseInt(internalLineMarkers[internalLineMarkers.length - 1].getAttribute("data-line-number"));
- }
-
- var fromLineNode = this.getLineNumberNode(fragment, fromLine),
- toLineNode = (toLine ? this.getLineNumberNode(fragment, toLine) : null),
- ancestorData = this._getCommonAncestor(fromLineNode, toLineNode);
-
- var fromChildTraceRel = ancestorData.trace1,
- fromChildTraceAbs = this._getNodeContextTrace(fromLineNode),
- toChildTraceRel = ancestorData.trace2,
- toChildTraceAbs = this._getNodeContextTrace(toLineNode),
- ancestor = ancestorData.commonAncestor,
- htmlOut = '',
- outerContextStart = '',
- outerContextEnd = '',
- innerContextStart = '',
- innerContextEnd = '',
- previousHtmlEndSnippet = '',
- followingHtmlStartSnippet = '',
- fakeOl, offset;
-
- fromChildTraceAbs.shift();
- var previousHtml = this._serializePartialDomToChild(fragment, fromChildTraceAbs, false);
- toChildTraceAbs.shift();
- var followingHtml = this._serializePartialDomFromChild(fragment, toChildTraceAbs, false);
-
- var currNode = fromLineNode,
- isSplit = false;
- while (currNode.parentNode) {
- if (!this._isFirstNonemptyChild(currNode.parentNode, currNode)) {
- isSplit = true;
- }
- if (isSplit) {
- this.addCSSClass(currNode.parentNode, 'os-split-before');
- }
- if (currNode.nodeName !== 'OS-LINEBREAK') {
- previousHtmlEndSnippet += '' + currNode.nodeName + '>';
- }
- currNode = currNode.parentNode;
- }
-
- currNode = toLineNode;
- isSplit = false;
- while (currNode.parentNode) {
- if (!this._isFirstNonemptyChild(currNode.parentNode, currNode)) {
- isSplit = true;
- }
- if (isSplit) {
- this.addCSSClass(currNode.parentNode, 'os-split-after');
- }
- if (currNode.parentNode.nodeName === 'OL') {
- fakeOl = currNode.parentNode.cloneNode(false);
- offset = (currNode.parentNode.getAttribute("start") ? parseInt(currNode.parentNode.getAttribute("start")) - 1 : 0);
- fakeOl.setAttribute('start', (this._isWithinNthLIOfOL(currNode.parentNode, toLineNode) + offset).toString());
- followingHtmlStartSnippet = this._serializeTag(fakeOl) + followingHtmlStartSnippet;
- } else {
- followingHtmlStartSnippet = this._serializeTag(currNode.parentNode) + followingHtmlStartSnippet;
- }
- currNode = currNode.parentNode;
- }
-
- var found = false;
- isSplit = false;
- for (var i = 0; i < fromChildTraceRel.length && !found; i++) {
- if (fromChildTraceRel[i].nodeName === 'OS-LINEBREAK') {
- found = true;
- } else {
- if (!this._isFirstNonemptyChild(fromChildTraceRel[i], fromChildTraceRel[i + 1])) {
- isSplit = true;
- }
- if (fromChildTraceRel[i].nodeName === 'OL') {
- fakeOl = fromChildTraceRel[i].cloneNode(false);
- offset = (fromChildTraceRel[i].getAttribute("start") ? parseInt(fromChildTraceRel[i].getAttribute("start")) - 1 : 0);
- fakeOl.setAttribute('start', (offset + this._isWithinNthLIOfOL(fromChildTraceRel[i], fromLineNode)).toString());
- innerContextStart += this._serializeTag(fakeOl);
- } else {
- if (i < (fromChildTraceRel.length - 1) && isSplit) {
- this.addCSSClass(fromChildTraceRel[i], 'os-split-before');
- }
- innerContextStart += this._serializeTag(fromChildTraceRel[i]);
- }
- }
- }
- found = false;
- for (i = 0; i < toChildTraceRel.length && !found; i++) {
- if (toChildTraceRel[i].nodeName === 'OS-LINEBREAK') {
- found = true;
- } else {
- innerContextEnd = '' + toChildTraceRel[i].nodeName + '>' + innerContextEnd;
- }
- }
-
- found = false;
- for (i = 0; i < ancestor.childNodes.length; i++) {
- if (ancestor.childNodes[i] === fromChildTraceRel[0]) {
- found = true;
- fromChildTraceRel.shift();
- htmlOut += this._serializePartialDomFromChild(ancestor.childNodes[i], fromChildTraceRel, true);
- } else if (ancestor.childNodes[i] === toChildTraceRel[0]) {
- found = false;
- toChildTraceRel.shift();
- htmlOut += this._serializePartialDomToChild(ancestor.childNodes[i], toChildTraceRel, true);
- } else if (found === true) {
- htmlOut += this._serializeDom(ancestor.childNodes[i], true);
- }
- }
-
- currNode = ancestor;
- while (currNode.parentNode) {
- if (currNode.nodeName === 'OL') {
- fakeOl = currNode.cloneNode(false);
- offset = (currNode.getAttribute("start") ? parseInt(currNode.getAttribute("start")) - 1 : 0);
- fakeOl.setAttribute('start', (this._isWithinNthLIOfOL(currNode, fromLineNode) + offset).toString());
- outerContextStart = this._serializeTag(fakeOl) + outerContextStart;
- } else {
- outerContextStart = this._serializeTag(currNode) + outerContextStart;
- }
- outerContextEnd += '' + currNode.nodeName + '>';
- currNode = currNode.parentNode;
- }
-
- var ret = {
- 'html': htmlOut,
- 'ancestor': ancestor,
- 'outerContextStart': outerContextStart,
- 'outerContextEnd': outerContextEnd,
- 'innerContextStart': innerContextStart,
- 'innerContextEnd': innerContextEnd,
- 'previousHtml': previousHtml,
- 'previousHtmlEndSnippet': previousHtmlEndSnippet,
- 'followingHtml': followingHtml,
- 'followingHtmlStartSnippet': followingHtmlStartSnippet
- };
-
- diffCache.put(cacheKey, ret);
- return ret;
- };
-
- /*
- * Convenience method that takes the html-attribute from an extractRangeByLineNumbers()-method,
- * wraps it with the context and adds line numbers.
- */
- this.formatDiffWithLineNumbers = function(diff, lineLength, firstLine) {
- var text = diff.outerContextStart + diff.innerContextStart + diff.html + diff.innerContextEnd + diff.outerContextEnd;
- text = lineNumberingService.insertLineNumbers(text, lineLength, null, null, firstLine);
- return text;
- };
-
- /*
- * This is a workardoun to prevent the last word of the inserted text from accidently being merged with the
- * first word of the following line.
- *
- * This happens as trailing spaces in the change recommendation's text are frequently stripped,
- * which is pretty nasty if the original text goes on after the affected line. So we insert a space
- * if the original line ends with one.
- */
- this._insertDanglingSpace = function(element) {
- if (element.childNodes.length > 0) {
- var lastChild = element.childNodes[element.childNodes.length - 1];
- if (lastChild.nodeType === TEXT_NODE && !lastChild.nodeValue.match(/[\S]/) && element.childNodes.length > 1) {
- // If the text node only contains whitespaces, chances are high it's just space between block elmeents,
- // like a line break between and
- lastChild = element.childNodes[element.childNodes.length - 2];
- }
- if (lastChild.nodeType === TEXT_NODE) {
- if (lastChild.nodeValue === '' || lastChild.nodeValue.substr(-1) !== ' ') {
- lastChild.nodeValue += ' ';
- }
- } else {
- this._insertDanglingSpace(lastChild);
- }
- }
- };
-
- /*
- * This functions merges to arrays of nodes. The last element of nodes1 and the first element of nodes2
- * are merged, if they are of the same type.
- *
- * This is done recursively until a TEMPLATE-Tag is is found, which was inserted in this.replaceLines.
- * Using a TEMPLATE-Tag is a rather dirty hack, as it is allowed inside of any other element, including .
- *
- */
- this._replaceLinesMergeNodeArrays = function(nodes1, nodes2) {
- if (nodes1.length === 0) {
- return nodes2;
- }
- if (nodes2.length === 0) {
- return nodes1;
- }
-
- var out = [];
- for (var i = 0; i < nodes1.length - 1; i++) {
- out.push(nodes1[i]);
- }
-
- var lastNode = nodes1[nodes1.length - 1],
- firstNode = nodes2[0];
- if (lastNode.nodeType === TEXT_NODE && firstNode.nodeType === TEXT_NODE) {
- var newTextNode = lastNode.ownerDocument.createTextNode(lastNode.nodeValue + firstNode.nodeValue);
- out.push(newTextNode);
- } else if (lastNode.nodeName === firstNode.nodeName) {
- var newNode = lastNode.ownerDocument.createElement(lastNode.nodeName);
- for (i = 0; i < lastNode.attributes.length; i++) {
- var attr = lastNode.attributes[i];
- newNode.setAttribute(attr.name, attr.value);
- }
-
- // Remove #text nodes inside of List elements (OL/UL), as they are confusing
- var lastChildren, firstChildren;
- if (lastNode.nodeName === 'OL' || lastNode.nodeName === 'UL') {
- lastChildren = [];
- firstChildren = [];
- for (i = 0; i < firstNode.childNodes.length; i++) {
- if (firstNode.childNodes[i].nodeType === ELEMENT_NODE) {
- firstChildren.push(firstNode.childNodes[i]);
- }
- }
- for (i = 0; i < lastNode.childNodes.length; i++) {
- if (lastNode.childNodes[i].nodeType === ELEMENT_NODE) {
- lastChildren.push(lastNode.childNodes[i]);
- }
- }
- } else {
- lastChildren = lastNode.childNodes;
- firstChildren = firstNode.childNodes;
- }
-
- var children = this._replaceLinesMergeNodeArrays(lastChildren, firstChildren);
- for (i = 0; i < children.length; i++) {
- newNode.appendChild(children[i]);
- }
-
- out.push(newNode);
- } else {
- if (lastNode.nodeName !== 'TEMPLATE') {
- out.push(lastNode);
- }
- if (firstNode.nodeName !== 'TEMPLATE') {
- out.push(firstNode);
- }
- }
-
- for (i = 1; i < nodes2.length; i++) {
- out.push(nodes2[i]);
- }
-
- return out;
- };
-
- /**
- *
- * @param {string} html
- * @returns {string}
- * @private
- */
- this._normalizeHtmlForDiff = function (html) {
- // Convert all HTML tags to uppercase, but leave the values of attributes unchanged
- // All attributes and CSS class names are sorted alphabetically
- // If an attribute is empty, it is removed
- html = html.replace(/<(\/?[a-z]*)( [^>]*)?>/ig, function (html, tag, attributes) {
- var tagNormalized = tag.toUpperCase();
- if (attributes === undefined) {
- attributes = "";
- }
- var attributesList = [],
- attributesMatcher = /( [^"'=]*)(= *((["'])(.*?)\4))?/gi,
- match;
- do {
- match = attributesMatcher.exec(attributes);
- if (match) {
- var attrNormalized = match[1].toUpperCase(),
- attrValue = match[5];
- if (match[2] !== undefined) {
- if (attrNormalized === ' CLASS') {
- attrValue = attrValue.split(' ').sort().join(' ').replace(/^\s+/, '').replace(/\s+$/, '');
- }
- attrNormalized += "=" + match[4] + attrValue + match[4];
- }
- if (attrValue !== '') {
- attributesList.push(attrNormalized);
- }
- }
- } while (match);
- attributes = attributesList.sort().join('');
- return "<" + tagNormalized + attributes + ">";
- });
-
- var entities = {
- ' ': ' ',
- '–': '-',
- 'ä': 'ä',
- 'ö': 'ö',
- 'ü': 'ü',
- 'Ä': 'Ä',
- 'Ö': 'Ö',
- 'Ü': 'Ü',
- 'ß': 'ß',
- '„': '„',
- '“': '“',
- '•': '•',
- '§': '§',
- 'é': 'é',
- '€': '€'
- };
-
- html = html.replace(/\s+<\/P>/gi, '').replace(/\s+<\/DIV>/gi, ' ').replace(/\s+<\/LI>/gi, '');
- html = html.replace(/\s+/gi, ' ').replace(/<\/LI>\s+/gi, ' ');
- html = html.replace(/\u00A0/g, ' ');
- html = html.replace(/\u2013/g, '-');
- for (var ent in entities) {
- html = html.replace(new RegExp(ent, 'g'), entities[ent]);
- }
-
- // Newline characters: after closing block-level-elements, but not after BR (which is inline)
- html = html.replace(/( )\n/gi, "$1");
- html = html.replace(/[ \n\t]+/gi, ' ');
- html = html.replace(/(<\/(div|p|ul|li|blockquote>)>) /gi, "$1\n");
-
- return html;
- };
-
- this._getAllNextSiblings = function(element) {
- var elements = [];
- while (element.nextSibling) {
- elements.push(element.nextSibling);
- element = element.nextSibling;
- }
- return elements;
- };
-
- this._getAllPrevSiblingsReversed = function(element) {
- var elements = [];
- while (element.previousSibling) {
- elements.push(element.previousSibling);
- element = element.previousSibling;
- }
- return elements;
- };
-
- /**
- * This returns the line number range in which changes (insertions, deletions) are encountered.
- * As in extractRangeByLineNumbers(), "to" refers to the line breaking element at the end, i.e. the start of the following line.
- *
- * @param {string} diffHtml
- */
- this.detectAffectedLineRange = function (diffHtml) {
- var cacheKey = lineNumberingService.djb2hash(diffHtml),
- cached = diffCache.get(cacheKey);
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- var fragment = this.htmlToFragment(diffHtml);
-
- this._insertInternalLineMarkers(fragment);
- this._insertInternalLiNumbers(fragment);
-
- var changes = fragment.querySelectorAll('ins, del, .insert, .delete'),
- firstChange = changes.item(0),
- lastChange = changes.item(changes.length - 1),
- i, j;
-
- if (!firstChange || !lastChange) {
- // There are no changes
- return null;
- }
-
- var firstTrace = this._getNodeContextTrace(firstChange),
- lastLineNumberBefore = null;
- for (j = firstTrace.length - 1; j >= 0 && lastLineNumberBefore === null; j--) {
- var prevSiblings = this._getAllPrevSiblingsReversed(firstTrace[j]);
- for (i = 0; i < prevSiblings.length && lastLineNumberBefore === null; i++) {
- lastLineNumberBefore = this._getLastLineNumberNode(prevSiblings[i]);
- }
- }
-
- var lastTrace = this._getNodeContextTrace(lastChange),
- firstLineNumberAfter = null;
- for (j = lastTrace.length - 1; j >= 0 && firstLineNumberAfter === null; j--) {
- var nextSiblings = this._getAllNextSiblings(lastTrace[j]);
- for (i = 0; i < nextSiblings.length && firstLineNumberAfter === null; i++) {
- firstLineNumberAfter = this._getFirstLineNumberNode(nextSiblings[i]);
- }
- }
-
- var range = {
- "from": parseInt(lastLineNumberBefore.getAttribute("data-line-number")),
- "to": parseInt(firstLineNumberAfter.getAttribute("data-line-number"))
- };
-
- diffCache.put(cacheKey, range);
- return range;
- };
-
- /**
- * Removes .delete-nodes and -Tags (including content)
- * Removes the .insert-classes and the wrapping -Tags (while maintaining content)
- * @param html
- */
- this.diffHtmlToFinalText = function(html) {
- var fragment = this.htmlToFragment(html);
-
- var delNodes = fragment.querySelectorAll('.delete, del');
- for (var i = 0; i < delNodes.length; i++) {
- delNodes[i].parentNode.removeChild(delNodes[i]);
- }
-
- var insNodes = fragment.querySelectorAll('ins');
- for (i = 0; i < insNodes.length; i++) {
- var ins = insNodes[i];
- while (ins.childNodes.length > 0) {
- var child = ins.childNodes.item(0);
- ins.removeChild(child);
- ins.parentNode.insertBefore(child, ins);
- }
- ins.parentNode.removeChild(ins);
- }
-
- var insertNodes = fragment.querySelectorAll('.insert');
- for (i = 0;i < insertNodes.length; i++) {
- this.removeCSSClass(insertNodes[i], 'insert');
- }
-
- return this._serializeDom(fragment, false);
- };
-
- /**
- * @param {string} htmlOld
- * @param {string} htmlNew
- * @returns {number}
- */
- this.detectReplacementType = function (htmlOld, htmlNew) {
- htmlOld = this._normalizeHtmlForDiff(htmlOld);
- htmlNew = this._normalizeHtmlForDiff(htmlNew);
-
- if (htmlOld === htmlNew) {
- return this.TYPE_REPLACEMENT;
- }
-
- var i, foundDiff;
- for (i = 0, foundDiff = false; i < htmlOld.length && i < htmlNew.length && foundDiff === false; i++) {
- if (htmlOld[i] !== htmlNew[i]) {
- foundDiff = true;
- }
- }
-
- var remainderOld = htmlOld.substr(i - 1),
- remainderNew = htmlNew.substr(i - 1),
- type = this.TYPE_REPLACEMENT;
-
- if (remainderOld.length > remainderNew.length) {
- if (remainderOld.substr(remainderOld.length - remainderNew.length) === remainderNew) {
- type = this.TYPE_DELETION;
- }
- } else if (remainderOld.length < remainderNew.length) {
- if (remainderNew.substr(remainderNew.length - remainderOld.length) === remainderOld) {
- type = this.TYPE_INSERTION;
- }
- }
-
- return type;
- };
-
- /**
- * @param {string} oldHtml
- * @param {string} newHTML
- * @param {number} fromLine
- * @param {number} toLine
- */
- this.replaceLines = function (oldHtml, newHTML, fromLine, toLine) {
- var data = this.extractRangeByLineNumbers(oldHtml, fromLine, toLine),
- previousHtml = data.previousHtml + ' ' + data.previousHtmlEndSnippet,
- previousFragment = this.htmlToFragment(previousHtml),
- followingHtml = data.followingHtmlStartSnippet + ' ' + data.followingHtml,
- followingFragment = this.htmlToFragment(followingHtml),
- newFragment = this.htmlToFragment(newHTML);
-
- if (data.html.length > 0 && data.html.substr(-1) === ' ') {
- this._insertDanglingSpace(newFragment);
- }
-
- var merged = this._replaceLinesMergeNodeArrays(previousFragment.childNodes, newFragment.childNodes);
- merged = this._replaceLinesMergeNodeArrays(merged, followingFragment.childNodes);
-
- var mergedFragment = document.createDocumentFragment();
- for (var i = 0; i < merged.length; i++) {
- mergedFragment.appendChild(merged[i]);
- }
-
- var forgottenTemplates = mergedFragment.querySelectorAll("TEMPLATE");
- for (i = 0; i < forgottenTemplates.length; i++) {
- var el = forgottenTemplates[i];
- el.parentNode.removeChild(el);
- }
-
- var forgottenSplitClasses = mergedFragment.querySelectorAll(".os-split-before, .os-split-after");
- for (i = 0; i < forgottenSplitClasses.length; i++) {
- this.removeCSSClass(forgottenSplitClasses[i], 'os-split-before');
- this.removeCSSClass(forgottenSplitClasses[i], 'os-split-after');
- }
-
- return this._serializeDom(mergedFragment, true);
- };
-
- this.addCSSClass = function (node, className) {
- if (node.nodeType !== ELEMENT_NODE) {
- return;
- }
- var classes = node.getAttribute('class');
- classes = (classes ? classes.split(' ') : []);
- if (classes.indexOf(className) === -1) {
- classes.push(className);
- }
- node.setAttribute('class', classes.join(' '));
- };
-
- this.removeCSSClass = function (node, className) {
- if (node.nodeType !== ELEMENT_NODE) {
- return;
- }
- var classes = node.getAttribute('class'),
- newClasses = [];
- classes = (classes ? classes.split(' ') : []);
- for (var i = 0; i < classes.length; i++) {
- if (classes[i] !== className) {
- newClasses.push(classes[i]);
- }
- }
- if (newClasses.length === 0) {
- node.removeAttribute('class');
- } else {
- node.setAttribute('class', newClasses.join(' '));
- }
- };
-
- this.addDiffMarkup = function (originalHTML, newHTML, fromLine, toLine, diffFormatterCb) {
- var data = this.extractRangeByLineNumbers(originalHTML, fromLine, toLine),
- previousHtml = data.previousHtml + ' ' + data.previousHtmlEndSnippet,
- previousFragment = this.htmlToFragment(previousHtml),
- followingHtml = data.followingHtmlStartSnippet + ' ' + data.followingHtml,
- followingFragment = this.htmlToFragment(followingHtml),
- newFragment = this.htmlToFragment(newHTML),
- oldHTML = data.outerContextStart + data.innerContextStart + data.html +
- data.innerContextEnd + data.outerContextEnd,
- oldFragment = this.htmlToFragment(oldHTML),
- el;
-
- var diffFragment = diffFormatterCb(oldFragment, newFragment);
-
- var mergedFragment = document.createDocumentFragment();
- while (previousFragment.firstChild) {
- el = previousFragment.firstChild;
- previousFragment.removeChild(el);
- mergedFragment.appendChild(el);
- }
- while (diffFragment.firstChild) {
- el = diffFragment.firstChild;
- diffFragment.removeChild(el);
- mergedFragment.appendChild(el);
- }
- while (followingFragment.firstChild) {
- el = followingFragment.firstChild;
- followingFragment.removeChild(el);
- mergedFragment.appendChild(el);
- }
-
- var forgottenTemplates = mergedFragment.querySelectorAll("TEMPLATE");
- for (var i = 0; i < forgottenTemplates.length; i++) {
- el = forgottenTemplates[i];
- el.parentNode.removeChild(el);
- }
-
- return this._serializeDom(mergedFragment, true);
- };
-
- /**
- * Adapted from http://ejohn.org/projects/javascript-diff-algorithm/
- * by John Resig, MIT License
- * @param {array} oldArr
- * @param {array} newArr
- * @returns {object}
- */
- this._diff = function (oldArr, newArr) {
- var ns = {},
- os = {},
- i;
-
- for (i = 0; i < newArr.length; i++) {
- if (ns[newArr[i]] === undefined)
- ns[newArr[i]] = {rows: [], o: null};
- ns[newArr[i]].rows.push(i);
- }
-
- for (i = 0; i < oldArr.length; i++) {
- if (os[oldArr[i]] === undefined)
- os[oldArr[i]] = {rows: [], n: null};
- os[oldArr[i]].rows.push(i);
- }
-
- for (i in ns) {
- if (ns[i].rows.length === 1 && typeof(os[i]) !== "undefined" && os[i].rows.length === 1) {
- newArr[ns[i].rows[0]] = {text: newArr[ns[i].rows[0]], row: os[i].rows[0]};
- oldArr[os[i].rows[0]] = {text: oldArr[os[i].rows[0]], row: ns[i].rows[0]};
- }
- }
-
- for (i = 0; i < newArr.length - 1; i++) {
- if (newArr[i].text !== null && newArr[i + 1].text === undefined && newArr[i].row + 1 < oldArr.length &&
- oldArr[newArr[i].row + 1].text === undefined && newArr[i + 1] == oldArr[newArr[i].row + 1]) {
- newArr[i + 1] = {text: newArr[i + 1], row: newArr[i].row + 1};
- oldArr[newArr[i].row + 1] = {text: oldArr[newArr[i].row + 1], row: i + 1};
- }
- }
-
- for (i = newArr.length - 1; i > 0; i--) {
- if (newArr[i].text !== null && newArr[i - 1].text === undefined && newArr[i].row > 0 &&
- oldArr[newArr[i].row - 1].text === undefined && newArr[i - 1] == oldArr[newArr[i].row - 1]) {
- newArr[i - 1] = {text: newArr[i - 1], row: newArr[i].row - 1};
- oldArr[newArr[i].row - 1] = {text: oldArr[newArr[i].row - 1], row: i - 1};
- }
- }
-
- return {o: oldArr, n: newArr};
- };
-
- this._tokenizeHtml = function (str) {
- var splitArrayEntriesEmbedSeparator = function (arr, by, prepend) {
- var newArr = [];
- for (var i = 0; i < arr.length; i++) {
- if (arr[i][0] === '<' && (by === " " || by === "\n")) {
- // Don't split HTML tags
- newArr.push(arr[i]);
- continue;
- }
-
- var parts = arr[i].split(by);
- if (parts.length === 1) {
- newArr.push(arr[i]);
- } else {
- var j;
- if (prepend) {
- if (parts[0] !== '') {
- newArr.push(parts[0]);
- }
- for (j = 1; j < parts.length; j++) {
- newArr.push(by + parts[j]);
- }
- } else {
- for (j = 0; j < parts.length - 1; j++) {
- newArr.push(parts[j] + by);
- }
- if (parts[parts.length - 1] !== '') {
- newArr.push(parts[parts.length - 1]);
- }
- }
- }
- }
- return newArr;
- };
- var splitArrayEntriesSplitSeparator = function (arr, by) {
- var newArr = [];
- for (var i = 0; i < arr.length; i++) {
- if (arr[i][0] === '<') {
- newArr.push(arr[i]);
- continue;
- }
- var parts = arr[i].split(by);
- for (var j = 0; j < parts.length; j++) {
- if (j > 0) {
- newArr.push(by);
- }
- newArr.push(parts[j]);
- }
- }
- return newArr;
- };
- var arr = splitArrayEntriesEmbedSeparator([str], '<', true);
- arr = splitArrayEntriesEmbedSeparator(arr, '>', false);
- arr = splitArrayEntriesSplitSeparator(arr, " ");
- arr = splitArrayEntriesSplitSeparator(arr, ".");
- arr = splitArrayEntriesSplitSeparator(arr, ",");
- arr = splitArrayEntriesSplitSeparator(arr, "!");
- arr = splitArrayEntriesSplitSeparator(arr, "-");
- arr = splitArrayEntriesEmbedSeparator(arr, "\n", false);
-
- var arrWithoutEmptes = [];
- for (var i = 0; i < arr.length; i++) {
- if (arr[i] !== '') {
- arrWithoutEmptes.push(arr[i]);
- }
- }
-
- return arrWithoutEmptes;
- };
-
- /**
- * @param {string} oldStr
- * @param {string} newStr
- * @returns {string}
- */
- this._diffString = function (oldStr, newStr) {
- oldStr = this._normalizeHtmlForDiff(oldStr.replace(/\s+$/, '').replace(/^\s+/, ''));
- newStr = this._normalizeHtmlForDiff(newStr.replace(/\s+$/, '').replace(/^\s+/, ''));
-
- var out = this._diff(this._tokenizeHtml(oldStr), this._tokenizeHtml(newStr));
-
- // This fixes the problem tested by "does not lose words when changes are moved X-wise"
- var lastRow = 0;
- for (var z = 0; z < out.n.length; z++) {
- if (out.n[z].row && out.n[z].row > lastRow) {
- lastRow = out.n[z].row;
- }
- if (out.n[z].row && out.n[z].row < lastRow) {
- out.o[out.n[z].row] = out.o[out.n[z].row].text;
- out.n[z] = out.n[z].text;
- }
- }
-
- var str = "";
- var i;
-
- if (out.n.length === 0) {
- for (i = 0; i < out.o.length; i++) {
- str += '' + out.o[i] + "";
- }
- } else {
- if (out.n[0].text === undefined) {
- for (var k = 0; k < out.o.length && out.o[k].text === undefined; k++) {
- str += '' + out.o[k] + "";
- }
- }
-
- var currOldRow = 0;
- for (i = 0; i < out.n.length; i++) {
- if (out.n[i].text === undefined) {
- if (out.n[i] !== "") {
- str += '' + out.n[i] + " ";
- }
- } else if (out.n[i].row < currOldRow) {
- str += '' + out.n[i].text + " ";
- } else {
- var pre = "";
-
- if ((i + 1) < out.n.length && out.n[i + 1].row !== undefined && out.n[i + 1].row > out.n[i].row + 1) {
- for (var n = out.n[i].row + 1; n < out.n[i + 1].row; n++) {
- if (out.o[n].text === undefined) {
- pre += '' + out.o[n] + "";
- } else {
- pre += '' + out.o[n].text + "";
- }
- }
- } else {
- for (var j = out.n[i].row + 1; j < out.o.length && out.o[j].text === undefined; j++) {
- pre += '' + out.o[j] + "";
- }
- }
- str += out.n[i].text + pre;
-
- currOldRow = out.n[i].row;
- }
- }
- }
-
- return str.replace(/^\s+/g, '').replace(/\s+$/g, '').replace(/ {2,}/g, ' ');
- };
-
- /**
- * @param {string} html
- * @return {boolean}
- * @private
- */
- this._isValidInlineHtml = function(html) {
- // If there are no HTML tags, we assume it's valid and skip further checks
- if (!html.match(/<[^>]*>/)) {
- return true;
- }
-
- // We check if this is a valid HTML that closes all its tags again using the innerHTML-Hack to correct
- // the string and check if the number of HTML tags changes by this
- var doc = document.createElement('div');
- doc.innerHTML = html;
- var tagsBefore = (html.match(/ it was not valid
- return false;
- }
-
- // If there is any block element inside, we consider it as broken, as this string will be displayed
- // inside of / tags
- if (html.match(/<(div|p|ul|li|blockquote)\W/i)) {
- return false;
- }
-
- return true;
- };
-
- /**
- * @param {string} html
- * @returns {boolean}
- * @private
- */
- this._diffDetectBrokenDiffHtml = function(html) {
- // If other HTML tags are contained within INS/DEL (e.g. "Test
"), let's better be cautious
- // The "!!(found=...)"-construction is only used to make jshint happy :)
- var findDel = /(.*?)<\/del>/gi,
- findIns = /(.*?)<\/ins>/gi,
- found, inner;
- while (!!(found = findDel.exec(html))) {
- inner = found[1].replace(/ ]*>/gi, '');
- if (inner.match(/<[^>]*>/)) {
- return true;
- }
- }
- while (!!(found = findIns.exec(html))) {
- inner = found[1].replace(/ ]*>/gi, '');
- if (!this._isValidInlineHtml(inner)) {
- return true;
- }
- }
-
- // If non of the conditions up to now is met, we consider the diff as being sane
- return false;
- };
-
- this._diffParagraphs = function(oldText, newText, lineLength, firstLineNumber) {
- var oldTextWithBreaks, newTextWithBreaks, currChild;
-
- if (lineLength !== undefined) {
- oldTextWithBreaks = lineNumberingService.insertLineNumbersNode(oldText, lineLength, null, firstLineNumber);
- newTextWithBreaks = lineNumberingService.insertLineNumbersNode(newText, lineLength, null, firstLineNumber);
- } else {
- oldTextWithBreaks = document.createElement('div');
- oldTextWithBreaks.innerHTML = oldText;
- newTextWithBreaks = document.createElement('div');
- newTextWithBreaks.innerHTML = newText;
- }
-
- for (var i = 0; i < oldTextWithBreaks.childNodes.length; i++) {
- currChild = oldTextWithBreaks.childNodes[i];
- if (currChild.nodeType === TEXT_NODE) {
- var wrapDel = document.createElement('del');
- oldTextWithBreaks.insertBefore(wrapDel, currChild);
- oldTextWithBreaks.removeChild(currChild);
- wrapDel.appendChild(currChild);
- } else {
- this.addCSSClass(currChild, 'delete');
- this._removeColorStyles(currChild);
- }
- }
- for (i = 0; i < newTextWithBreaks.childNodes.length; i++) {
- currChild = newTextWithBreaks.childNodes[i];
- if (currChild.nodeType === TEXT_NODE) {
- var wrapIns = document.createElement('ins');
- newTextWithBreaks.insertBefore(wrapIns, currChild);
- newTextWithBreaks.removeChild(currChild);
- wrapIns.appendChild(currChild);
- } else {
- this.addCSSClass(currChild, 'insert');
- this._removeColorStyles(currChild);
- }
- }
-
- var mergedFragment = document.createDocumentFragment(),
- el;
- while (oldTextWithBreaks.firstChild) {
- el = oldTextWithBreaks.firstChild;
- oldTextWithBreaks.removeChild(el);
- mergedFragment.appendChild(el);
- }
- while (newTextWithBreaks.firstChild) {
- el = newTextWithBreaks.firstChild;
- newTextWithBreaks.removeChild(el);
- mergedFragment.appendChild(el);
- }
-
- return this._serializeDom(mergedFragment);
- };
-
- this.addCSSClassToFirstTag = function (html, className) {
- return html.replace(/<[a-z][^>]*>/i, function (match) {
- if (match.match(/class=["'][a-z0-9 _-]*["']/i)) {
- return match.replace(/class=["']([a-z0-9 _-]*)["']/i, function (match2, previousClasses) {
- return "class=\"" + previousClasses + " " + className + "\"";
- });
- } else {
- return match.substring(0, match.length - 1) + " class=\"" + className + "\">";
- }
- });
- };
-
- this._addClassToLastNode = function (html, className) {
- var node = document.createElement('div');
- node.innerHTML = html;
- var foundLast = false;
- for (var i = node.childNodes.length - 1; i >= 0 && !foundLast; i--) {
- if (node.childNodes[i].nodeType === ELEMENT_NODE) {
- var classes = [];
- if (node.childNodes[i].getAttribute("class")) {
- classes = node.childNodes[i].getAttribute("class").split(" ");
- }
- classes.push(className);
- node.childNodes[i].setAttribute("class", classes.sort().join(' ').replace(/^\s+/, '').replace(/\s+$/, ''));
- foundLast = true;
- }
- }
- return node.innerHTML;
- };
-
- /**
- * This function removes color-Attributes from the styles of this node or a descendant,
- * as they interfer with the green/red color in HTML and PDF
- *
- * For the moment, it is sufficient to do this only in paragraph diff mode, as we fall back to this mode anyway
- * once we encounter SPANs or other tags inside of INS/DEL-tags
- *
- * @param {Element} node
- * @private
- */
- this._removeColorStyles = function (node) {
- var styles = node.getAttribute('style');
- if (styles && styles.indexOf('color') > -1) {
- var stylesNew = [];
- styles.split(';').forEach(function(style) {
- if (!style.match(/^\s*color\s*:/i)) {
- stylesNew.push(style);
- }
- });
- if (stylesNew.join(";") === '') {
- node.removeAttribute('style');
- } else {
- node.setAttribute('style', stylesNew.join(";"));
- }
- }
- for (var i = 0; i < node.childNodes.length; i++) {
- if (node.childNodes[i].nodeType === ELEMENT_NODE) {
- this._removeColorStyles(node.childNodes[i]);
- }
- }
- };
-
- /**
- * This fixes a very specific, really weird bug that is tested in the test case "does not a change in a very specific case".
- *
- * @param {string}diffStr
- * @return {string}
- * @private
- */
- this._fixWrongChangeDetection = function (diffStr) {
- if (diffStr.indexOf('') === -1 || diffStr.indexOf('') === -1) {
- return diffStr;
- }
-
- var findDelGroupFinder = /(?:.*?<\/del>)+/gi,
- found,
- returnStr = diffStr;
-
- while (!!(found = findDelGroupFinder.exec(diffStr))) {
- var del = found[0],
- split = returnStr.split(del);
-
- var findInsGroupFinder = /^(?:.*?<\/ins>)+/gi,
- foundIns = findInsGroupFinder.exec(split[1]);
- if (foundIns) {
- var ins = foundIns[0];
-
- var delShortened = del.replace(
- /(( <\/del>)?(]+os-line-number[^>]+?>)(\s|<\/?del>)*<\/span>)<\/del>/gi,
- ''
- ).replace(/<\/del>/g, '');
- var insConv = ins.replace(//g, '').replace(/<\/ins>/g, '').replace(/<\/del>/g, '');
- if (delShortened.indexOf(insConv) !== -1) {
- delShortened = delShortened.replace(insConv, '');
- if (delShortened === '') {
- returnStr = returnStr.replace(del + ins, del.replace(//g, '').replace(/<\/del>/g, ''));
- }
- }
- }
- }
- return returnStr;
- };
-
- /**
- * This function calculates the diff between two strings and tries to fix problems with the resulting HTML.
- * If lineLength and firstLineNumber is given, line numbers will be returned es well
- *
- * @param {string} htmlOld
- * @param {string} htmlNew
- * @param {number} lineLength - optional
- * @param {number} firstLineNumber - optional
- * @returns {string}
- */
- this.diff = function (htmlOld, htmlNew, lineLength, firstLineNumber) {
- var cacheKey = lineLength + ' ' + firstLineNumber + ' ' +
- lineNumberingService.djb2hash(htmlOld) + lineNumberingService.djb2hash(htmlNew),
- cached = diffCache.get(cacheKey);
- if (!angular.isUndefined(cached)) {
- return cached;
- }
-
- // This fixes a really strange artefact with the diff that occures under the following conditions:
- // - The first tag of the two texts is identical, e.g.
- // - A change happens in the next tag, e.g. inserted text
- // - The first tag occures a second time in the text, e.g. another
- // In this condition, the first tag is deleted first and inserted afterwards again
- // Test case: "does not break when an insertion followes a beginning tag occuring twice"
- // The work around inserts to tags at the beginning and removes them afterwards again,
- // to make sure this situation does not happen (and uses invisible pseudo-tags in case something goes wrong)
- var workaroundPrepend = "";
-
- // os-split-after should not be considered for detecting changes in paragraphs, so we strip it here
- // and add it afterwards.
- // We only do this for P for now, as for more complex types like UL/LI that tend to be nestend,
- // information would get lost by this that we will need to recursively merge it again later on.
- var oldIsSplitAfter = false,
- newIsSplitAfter = false;
- htmlOld = htmlOld.replace(/(\s*]+class\s*=\s*["'][^"']*)os-split-after/gi, function(match, beginning) {
- oldIsSplitAfter = true;
- return beginning;
- });
- htmlNew = htmlNew.replace(/(\s*
]+class\s*=\s*["'][^"']*)os-split-after/gi, function(match, beginning) {
- newIsSplitAfter = true;
- return beginning;
- });
-
- // Performing the actual diff
- var str = this._diffString(workaroundPrepend + htmlOld, workaroundPrepend + htmlNew),
- diffUnnormalized = str.replace(/^\s+/g, '').replace(/\s+$/g, '').replace(/ {2,}/g, ' ');
-
-
- diffUnnormalized = this._fixWrongChangeDetection(diffUnnormalized);
-
- // Remove tags that only delete line numbers
- // We need to do this before removing as done in one of the next statements
- diffUnnormalized = diffUnnormalized.replace(
- /(( <\/del>)?(]+os-line-number[^>]+?>)(\s|<\/?del>)*<\/span>)<\/del>/gi,
- function(found,tag,br,span) {
- return (br !== undefined ? br : '') + span + ' ';
- }
- );
-
- diffUnnormalized = diffUnnormalized.replace(/<\/ins>/gi, '').replace(/<\/del>/gi, '');
-
- // Move whitespaces around inserted P's out of the INS-tag
- diffUnnormalized = diffUnnormalized.replace(
- /(\s*)(]*)?>[\s\S]*?<\/p>)(\s*)<\/ins>/gim,
- function(match, whiteBefore, inner, tagInner, whiteAfter) {
- return whiteBefore +
- inner
- .replace(/
]*)?>/gi, function(match) {
- return match + "";
- })
- .replace(/<\/p>/gi, "
") +
- whiteAfter;
- }
- );
-
- // Fixes HTML produced by the diff like this:
- // from:
Inserted Text
\nMore inserted text
- // into: Inserted Text \nMore inserted text
- diffUnnormalized = diffUnnormalized.replace(
- /<\/p><\/del>([\s\S]*?)<\/p><\/ins>/gim,
- "$1 "
- );
- diffUnnormalized = diffUnnormalized.replace(
- /[\s\S]*?<\/ins>/gim,
- function(match) {
- return match.replace(/(<\/p>\s*)/gi, "
$1");
- }
- );
-
- // If only a few characters of a word have changed, don't display this as a replacement of the whole word,
- // but only of these specific characters
- diffUnnormalized = diffUnnormalized.replace(/([a-z0-9,_-]* ?)<\/del>([a-z0-9,_-]* ?)<\/ins>/gi, function (found, oldText, newText) {
- var foundDiff = false, commonStart = '', commonEnd = '',
- remainderOld = oldText, remainderNew = newText;
-
- while (remainderOld.length > 0 && remainderNew.length > 0 && !foundDiff) {
- if (remainderOld[0] === remainderNew[0]) {
- commonStart += remainderOld[0];
- remainderOld = remainderOld.substr(1);
- remainderNew = remainderNew.substr(1);
- } else {
- foundDiff = true;
- }
- }
-
- foundDiff = false;
- while (remainderOld.length > 0 && remainderNew.length > 0 && !foundDiff) {
- if (remainderOld[remainderOld.length - 1] === remainderNew[remainderNew.length - 1]) {
- commonEnd = remainderOld[remainderOld.length - 1] + commonEnd;
- remainderNew = remainderNew.substr(0, remainderNew.length - 1);
- remainderOld = remainderOld.substr(0, remainderOld.length - 1);
- } else {
- foundDiff = true;
- }
- }
-
- var out = commonStart;
- if (remainderOld !== '') {
- out += '' + remainderOld + '';
- }
- if (remainderNew !== '') {
- out += '' + remainderNew + ' ';
- }
- out += commonEnd;
-
- return out;
- });
-
- // Replace spaces in line numbers by
- diffUnnormalized = diffUnnormalized.replace(
- /]+os-line-number[^>]+?>\s*<\/span>/gi,
- function(found) {
- return found.toLowerCase().replace(/> <\/span/gi, "> .*?(\n.*?)*<\/ins>/gi, function (found) {
- found = found.replace(/<(div|p|li)[^>]*>/gi, function(match) { return match + ''; });
- found = found.replace(/<\/(div|p|li)[^>]*>/gi, function(match) { return ' ' + match; });
- return found;
- });
- diffUnnormalized = diffUnnormalized.replace(/.*?(\n.*?)*<\/del>/gi, function (found) {
- found = found.replace(/<(div|p|li)[^>]*>/gi, function(match) { return match + ''; });
- found = found.replace(/<\/(div|p|li)[^>]*>/gi, function(match) { return '' + match; });
- return found;
- });
- diffUnnormalized = diffUnnormalized.replace(/^(.*)<\/p><\/del>$/gi, function(match, inner) { return "
" + inner + "
"; });
-
- var node = document.createElement('div');
- node.innerHTML = diffUnnormalized;
- diff = node.innerHTML;
-
- if (lineLength !== undefined && firstLineNumber !== undefined) {
- node = lineNumberingService.insertLineNumbersNode(diff, lineLength, null, firstLineNumber);
- diff = node.innerHTML;
- }
- }
-
- if (oldIsSplitAfter || newIsSplitAfter) {
- diff = this._addClassToLastNode(diff, "os-split-after");
- }
-
- diffCache.put(cacheKey, diff);
- return diff;
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/docx.js b/openslides/motions/static/js/motions/docx.js
deleted file mode 100644
index dce23e97d..000000000
--- a/openslides/motions/static/js/motions/docx.js
+++ /dev/null
@@ -1,221 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.docx', ['OpenSlidesApp.core.docx'])
-
-.factory('MotionDocxExport', [
- '$http',
- '$q',
- '$filter',
- 'operator',
- 'Config',
- 'Category',
- 'gettextCatalog',
- 'FileSaver',
- 'lineNumberingService',
- 'Html2DocxConverter',
- 'MotionComment',
- function ($http, $q, $filter, operator, Config, Category, gettextCatalog,
- FileSaver, lineNumberingService, Html2DocxConverter, MotionComment) {
-
- var PAGEBREAK = ' ';
-
- var converter;
-
- var getData = function (motions, params) {
- var data = {};
- // header
- var headerline1 = [
- Config.translate(Config.get('general_event_name').value),
- Config.translate(Config.get('general_event_description').value)
- ].filter(Boolean).join(' – ');
- var headerline2 = [
- Config.get('general_event_location').value,
- Config.get('general_event_date').value
- ].filter(Boolean).join(', ');
- data.header = [headerline1, headerline2].join('\n');
-
- // motion catalog title/preamble
- data.title = Config.translate(Config.get('motions_export_title').value);
- data.preamble = Config.get('motions_export_preamble').value;
-
- // categories
- var categories = getCategoriesData(motions);
- data.has_categories = categories.length === 0 ? false : true;
- data.categories_translation = gettextCatalog.getString('Categories');
- data.categories = categories;
- data.no_categories = gettextCatalog.getString('No categories available.');
- data.pagebreak_main = categories.length === 0 ? '' : PAGEBREAK;
-
- // motions
- data.tableofcontents_translation = gettextCatalog.getString('Table of contents');
- data.motions_list = getMotionShortData(motions, params);
- data.no_motions = gettextCatalog.getString('No motions available.');
-
- return $q(function (resolve) {
- getMotionFullData(motions, params).then(function (motionData) {
- data.motions = motionData;
- resolve(data);
- });
- });
- };
-
- var getCategoriesData = function (motions) {
- var categories = _.map(motions, function (motion) {
- if (motion.category) {
- return {
- prefix: motion.category.prefix,
- name: motion.category.name,
- };
- }
- });
- // clear out 'undefined' and make the categories unique.
- categories = _.uniqBy(_.filter(categories, function(category) {
- return category;
- }), 'prefix');
- var sortKey = Config.get('motions_export_category_sorting').value;
- return _.orderBy(categories, [sortKey]);
- };
-
- var getMotionShortData = function (motions, params) {
- return _.map(motions, function (motion) {
- return {
- identifier: motion.identifier || '',
- title: motion.getTitleWithChanges(params.changeRecommendationMode),
- };
- });
- };
-
- var getMotionFullData = function (motions, params) {
- // All translations
- var translation = gettextCatalog.getString('Motion'),
- sequential_translation = gettextCatalog.getString('Sequential number'),
- submitters_translation = gettextCatalog.getString('Submitters'),
- status_translation = gettextCatalog.getString('Status'),
- reason_translation = gettextCatalog.getString('Reason'),
- comment_translation = gettextCatalog.getString('Comments');
- var sequential_enabled = Config.get('motions_export_sequential_number').value;
- // promises for create the actual motion data
- var promises = _.map(motions, function (motion) {
- var title = motion.getTitleWithChanges(params.changeRecommendationMode);
- var text = params.include.text ? motion.getTextByMode(params.changeRecommendationMode, null, null, false) : '';
- var reason = params.include.reason ? motion.getReason() : '';
- var comments = getMotionComments(motion, params.includeComments);
-
- // Data for one motions. Must include translations, ...
- var motionData = {
- // Translations
- motion_translation: translation,
- sequential_translation: sequential_translation,
- submitters_translation: submitters_translation,
- reason_translation: reason.length === 0 ? '' : reason_translation,
- status_translation: status_translation,
- comment_translation: comments.length === 0 ? '' : comment_translation,
- sequential_enabled: sequential_enabled,
- // Actual data
- id: motion.id,
- identifier: motion.identifier || '',
- title: title,
- submitters: params.include.submitters ? _.map(
- $filter('orderBy')(motion.submitters, 'weight'), function (submitter) {
- return submitter.user.get_full_name();
- }
- ).join(', ') : '',
- status: motion.getStateName(),
- // Miscellaneous stuff
- preamble: gettextCatalog.getString(Config.get('motions_preamble').value),
- pagebreak: PAGEBREAK,
- };
- // converting html to docx is async, so text, reason and comments are inserted here.
- return $q(function (resolve) {
- var convertPromises = _.map(comments, function (comment) {
- return converter.html2docx(comment.comment).then(function (commentAsDocx) {
- comment.comment = commentAsDocx;
- });
- });
- convertPromises.push(converter.html2docx(text).then(function (textAsDocx) {
- motionData.text = textAsDocx;
- }));
- convertPromises.push(converter.html2docx(reason).then(function (reasonAsDocx) {
- motionData.reason = reasonAsDocx;
- }));
- $q.all(convertPromises).then(function () {
- motionData.comments = comments;
- resolve(motionData);
- });
- });
- });
- // resolve, if all motion data is fetched.
- return $q(function (resolve) {
- $q.all(promises).then(function (data) {
- if (data.length) {
- // clear pagebreak on last element
- data[data.length - 1].pagebreak = '';
- }
- resolve(data);
- });
- });
- };
-
- var getMotionComments = function (motion, fieldsIncluded) {
- var fields = MotionComment.getNoSpecialCommentsFields();
- var comments = [];
- _.forEach(fieldsIncluded, function (ok, id) {
- if (ok && motion.comments[id]) {
- var title = fields[id].name;
- if (!fields[id].public) {
- title += ' (' + gettextCatalog.getString('internal') + ')';
- }
- var comment = motion.comments[id];
- if (comment.indexOf('') !== 0) {
- comment = '
' + comment + '
';
- }
- comments.push({
- title: title,
- comment: comment,
- });
- }
- });
- return comments;
- };
-
- return {
- export: function (motions, params) {
- converter = Html2DocxConverter.createInstance();
- params = _.clone(params || {}); // Clone this to avoid sideeffects.
- _.defaults(params, {
- changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
- include: {
- text: true,
- reason: true,
- submitters: true,
- },
- includeComments: {},
- });
- params.filename = gettextCatalog.getString('motions') + '.docx';
- if (!_.includes(['original', 'changed', 'agreed'], params.changeRecommendationMode)) {
- params.changeRecommendationMode = 'original';
- }
-
- $http.get('/motions/docxtemplate/').then(function (success) {
- var content = window.atob(success.data);
- var doc = new Docxgen(content);
-
- getData(motions, params).then(function (data) {
- doc.setData(data);
- doc.render();
-
- var zip = doc.getZip();
- zip = converter.updateZipFile(zip);
-
- var out = zip.generate({type: 'blob'});
- FileSaver.saveAs(out, params.filename);
- });
- });
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/linenumbering.js b/openslides/motions/static/js/motions/linenumbering.js
deleted file mode 100644
index d978e2d01..000000000
--- a/openslides/motions/static/js/motions/linenumbering.js
+++ /dev/null
@@ -1,772 +0,0 @@
-(function () {
-
-"use strict";
-
-angular.module('OpenSlidesApp.motions.lineNumbering', [])
-
-/**
- * Current limitations of this implementation:
- *
- * Only the following inline elements are supported:
- * - 'SPAN', 'A', 'EM', 'S', 'B', 'I', 'STRONG', 'U', 'BIG', 'SMALL', 'SUB', 'SUP', 'TT'
- * - 'INS' and 'DEL' are supported, but line numbering does not affect the content of 'INS'-elements
- *
- * Only other inline elements are allowed within inline elements.
- * No constructs like
are allowed. CSS-attributes like 'display: block' are ignored.
- */
-
-.service('lineNumberingService', [
- '$cacheFactory',
- function ($cacheFactory) {
- var ELEMENT_NODE = 1,
- TEXT_NODE = 3;
-
- // Counts the number of characters in the current line, beyond singe nodes.
- // Needs to be resetted after each line break and after entering a new block node.
- this._currentInlineOffset = null;
-
- // The last position of a point suitable for breaking the line. null or an object with the following values:
- // - node: the node that contains the position. Guaranteed to be a TextNode
- // - offset: the offset of the breaking characters (like the space)
- // Needs to be resetted after each line break and after entering a new block node.
- this._lastInlineBreakablePoint = null;
-
- // The line number counter
- this._currentLineNumber = null;
-
- // Indicates that we just entered a block element and we want to add a line number without line break at the beginning.
- this._prependLineNumberToFirstText = false;
-
- // A workaround to prevent double line numbers
- this._ignoreNextRegularLineNumber = false;
-
- // Decides if the content of inserted nodes should count as well. This is used so we can use the algorithm on a
- // text with inline diff annotations and get the same line numbering as with the original text (when set to false)
- this._ignoreInsertedText = false;
-
- var lineNumberCache = $cacheFactory('linenumbering.service');
-
- this.djb2hash = function(str) {
- var hash = 5381, char;
- for (var i = 0; i < str.length; i++) {
- char = str.charCodeAt(i);
- hash = ((hash << 5) + hash) + char;
- }
- return hash.toString();
- };
-
- this._isInlineElement = function (node) {
- var inlineElements = [
- 'SPAN', 'A', 'EM', 'S', 'B', 'I', 'STRONG', 'U', 'BIG', 'SMALL', 'SUB', 'SUP', 'TT', 'INS', 'DEL',
- 'STRIKE'
- ];
- return (inlineElements.indexOf(node.nodeName) > -1);
- };
-
- this._isIgnoredByLineNumbering = function (node) {
- if (node.nodeName === 'INS') {
- return this._ignoreInsertedText;
- } else if (this._isOsLineNumberNode(node)) {
- return true;
- } else {
- return false;
- }
- };
-
- this._isOsLineBreakNode = function (node) {
- var isLineBreak = false;
- if (node && node.nodeType === ELEMENT_NODE && node.nodeName === 'BR' && node.hasAttribute('class')) {
- var classes = node.getAttribute('class').split(' ');
- if (classes.indexOf('os-line-break') > -1) {
- isLineBreak = true;
- }
- }
- return isLineBreak;
- };
-
- this._isOsLineNumberNode = function (node) {
- var isLineNumber = false;
- if (node && node.nodeType === ELEMENT_NODE && node.nodeName === 'SPAN' && node.hasAttribute('class')) {
- var classes = node.getAttribute('class').split(' ');
- if (classes.indexOf('os-line-number') > -1) {
- isLineNumber = true;
- }
- }
- return isLineNumber;
- };
-
- this._getLineNumberNode = function(fragment, lineNumber) {
- return fragment.querySelector('.os-line-number.line-number-' + lineNumber);
- };
-
- this._htmlToFragment = function(html) {
- var fragment = document.createDocumentFragment(),
- div = document.createElement('DIV');
- div.innerHTML = html;
- while (div.childElementCount) {
- var child = div.childNodes[0];
- div.removeChild(child);
- fragment.appendChild(child);
- }
- return fragment;
- };
-
- this._fragmentToHtml = function(fragment) {
- var div = document.createElement('DIV');
- while (fragment.firstChild) {
- var child = fragment.firstChild;
- fragment.removeChild(child);
- div.appendChild(child);
- }
- return div.innerHTML;
- };
-
- this._createLineBreak = function () {
- var br = document.createElement('br');
- br.setAttribute('class', 'os-line-break');
- return br;
- };
-
- this._createLineNumber = function () {
- if (this._ignoreNextRegularLineNumber) {
- this._ignoreNextRegularLineNumber = false;
- return;
- }
- var node = document.createElement('span');
- var lineNumber = this._currentLineNumber;
- this._currentLineNumber++;
- node.setAttribute('class', 'os-line-number line-number-' + lineNumber);
- node.setAttribute('data-line-number', lineNumber + '');
- node.setAttribute('contenteditable', 'false');
- node.innerHTML = ' '; // Prevent ckeditor from stripping out empty span's
- return node;
- };
-
- /**
- * Splits a TEXT_NODE into an array of TEXT_NODEs and BR-Elements separating them into lines.
- * Each line has a maximum length of 'length', with one exception: spaces are accepted to exceed the length.
- * Otherwise the string is split by the last space or dash in the line.
- *
- * @param node
- * @param length
- * @param highlight
- * @returns Array
- * @private
- */
- this._textNodeToLines = function (node, length, highlight) {
- var out = [],
- currLineStart = 0,
- i = 0,
- firstTextNode = true,
- service = this;
- var addLine = function (text, highlight) {
- var node;
- if (typeof highlight === 'undefined') {
- highlight = -1;
- }
- if (firstTextNode) {
- if (highlight === service._currentLineNumber - 1) {
- node = document.createElement('span');
- node.setAttribute('class', 'highlight');
- node.innerHTML = text;
- } else {
- node = document.createTextNode(text);
- }
- firstTextNode = false;
- } else {
- if (service._currentLineNumber === highlight && highlight !== null) {
- node = document.createElement('span');
- node.setAttribute('class', 'highlight');
- node.innerHTML = text;
- } else {
- node = document.createTextNode(text);
- }
- out.push(service._createLineBreak());
- if (service._currentLineNumber !== null) {
- out.push(service._createLineNumber());
- }
- }
- out.push(node);
- return node;
- };
- var addLinebreakToPreviousNode = function (node, offset) {
- var firstText = node.nodeValue.substr(0, offset + 1),
- secondText = node.nodeValue.substr(offset + 1);
- var lineBreak = service._createLineBreak();
- var firstNode = document.createTextNode(firstText);
- node.parentNode.insertBefore(firstNode, node);
- node.parentNode.insertBefore(lineBreak, node);
- if (service._currentLineNumber !== null) {
- node.parentNode.insertBefore(service._createLineNumber(), node);
- }
- node.nodeValue = secondText;
- };
-
- if (node.nodeValue === "\n") {
- out.push(node);
- } else {
-
- // This happens if a previous inline element exactly stretches to the end of the line
- if (this._currentInlineOffset >= length) {
- out.push(service._createLineBreak());
- if (this._currentLineNumber !== null) {
- out.push(service._createLineNumber());
- }
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- } else if (this._prependLineNumberToFirstText) {
- if (this._ignoreNextRegularLineNumber) {
- this._ignoreNextRegularLineNumber = false;
- } else if (service._currentLineNumber !== null) {
- out.push(service._createLineNumber());
- }
- }
- this._prependLineNumberToFirstText = false;
-
- while (i < node.nodeValue.length) {
- var lineBreakAt = null;
- if (this._currentInlineOffset >= length) {
- if (this._lastInlineBreakablePoint !== null) {
- lineBreakAt = this._lastInlineBreakablePoint;
- } else {
- lineBreakAt = {
- 'node': node,
- 'offset': i - 1
- };
- }
- }
- if (lineBreakAt !== null && (node.nodeValue[i] !== ' ' && node.nodeValue[i] !== "\n")) {
- if (lineBreakAt.node === node) {
- // The last possible breaking point is in this text node
- var currLine = node.nodeValue.substring(currLineStart, lineBreakAt.offset + 1);
- addLine(currLine, highlight);
-
- currLineStart = lineBreakAt.offset + 1;
- this._currentInlineOffset = i - lineBreakAt.offset - 1;
- this._lastInlineBreakablePoint = null;
- } else {
- // The last possible breaking point was not in this text not, but one we have already passed
- var remainderOfPrev = lineBreakAt.node.nodeValue.length - lineBreakAt.offset - 1;
- addLinebreakToPreviousNode(lineBreakAt.node, lineBreakAt.offset);
-
- this._currentInlineOffset = i + remainderOfPrev;
- this._lastInlineBreakablePoint = null;
- }
-
- }
-
- if (node.nodeValue[i] === ' ' || node.nodeValue[i] === '-' || node.nodeValue[i] === "\n") {
- this._lastInlineBreakablePoint = {
- 'node': node,
- 'offset': i
- };
- }
-
- this._currentInlineOffset++;
- i++;
-
- }
- var lastLine = addLine(node.nodeValue.substring(currLineStart), highlight);
- if (this._lastInlineBreakablePoint !== null) {
- this._lastInlineBreakablePoint.node = lastLine;
- }
- }
- return out;
- };
-
-
- /**
- * Moves line breaking and line numbering markup before inline elements
- *
- * @param innerNode
- * @param outerNode
- * @private
- */
- this._moveLeadingLineBreaksToOuterNode = function (innerNode, outerNode) {
- if (this._isInlineElement(innerNode)) {
- if (this._isOsLineBreakNode(innerNode.firstChild)) {
- var br = innerNode.firstChild;
- innerNode.removeChild(br);
- outerNode.appendChild(br);
- }
- if (this._isOsLineNumberNode(innerNode.firstChild)) {
- var span = innerNode.firstChild;
- innerNode.removeChild(span);
- outerNode.appendChild(span);
- }
- }
- };
-
- this._lengthOfFirstInlineWord = function (node) {
- if (!node.firstChild) {
- return 0;
- }
- if (node.firstChild.nodeType === TEXT_NODE) {
- var parts = node.firstChild.nodeValue.split(' ');
- return parts[0].length;
- } else {
- return this._lengthOfFirstInlineWord(node.firstChild);
- }
- };
-
- this._insertLineNumbersToInlineNode = function (node, length, highlight) {
- var oldChildren = [], i;
- for (i = 0; i < node.childNodes.length; i++) {
- oldChildren.push(node.childNodes[i]);
- }
-
- while (node.firstChild) {
- node.removeChild(node.firstChild);
- }
-
- for (i = 0; i < oldChildren.length; i++) {
- if (oldChildren[i].nodeType === TEXT_NODE) {
- var ret = this._textNodeToLines(oldChildren[i], length, highlight);
- for (var j = 0; j < ret.length; j++) {
- node.appendChild(ret[j]);
- }
- } else if (oldChildren[i].nodeType === ELEMENT_NODE) {
- var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
- overlength = ((this._currentInlineOffset + firstword) > length && this._currentInlineOffset > 0);
- if (overlength && this._isInlineElement(oldChildren[i])) {
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- node.appendChild(this._createLineBreak());
- if (this._currentLineNumber !== null) {
- node.appendChild(this._createLineNumber());
- }
- }
- var changedNode = this._insertLineNumbersToNode(oldChildren[i], length, highlight);
- this._moveLeadingLineBreaksToOuterNode(changedNode, node);
- node.appendChild(changedNode);
- } else {
- throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
- }
- }
-
- return node;
- };
-
- this._calcBlockNodeLength = function (node, oldLength) {
- var newLength = oldLength;
- switch (node.nodeName) {
- case 'LI':
- newLength -= 5;
- break;
- case 'BLOCKQUOTE':
- newLength -= 20;
- break;
- case 'DIV':
- case 'P':
- var styles = node.getAttribute("style"),
- padding = 0;
- if (styles) {
- var leftpad = styles.split("padding-left:");
- if (leftpad.length > 1) {
- leftpad = parseInt(leftpad[1]);
- padding += leftpad;
- }
- var rightpad = styles.split("padding-right:");
- if (rightpad.length > 1) {
- rightpad = parseInt(rightpad[1]);
- padding += rightpad;
- }
- newLength -= (padding / 5);
- }
- break;
- case 'H1':
- newLength *= 0.66;
- break;
- case 'H2':
- newLength *= 0.75;
- break;
- case 'H3':
- newLength *= 0.85;
- break;
- }
- return Math.ceil(newLength);
- };
-
- this._insertLineNumbersToBlockNode = function (node, length, highlight) {
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- this._prependLineNumberToFirstText = true;
-
- var oldChildren = [], i;
- for (i = 0; i < node.childNodes.length; i++) {
- oldChildren.push(node.childNodes[i]);
- }
-
- while (node.firstChild) {
- node.removeChild(node.firstChild);
- }
-
- for (i = 0; i < oldChildren.length; i++) {
- if (oldChildren[i].nodeType === TEXT_NODE) {
- if (!oldChildren[i].nodeValue.match(/\S/)) {
- // White space nodes between block elements should be ignored
- var prevIsBlock = (i > 0 && !this._isInlineElement(oldChildren[i - 1]));
- var nextIsBlock = (i < oldChildren.length - 1 && !this._isInlineElement(oldChildren[i + 1]));
- if ((prevIsBlock && nextIsBlock) || (i === 0 && nextIsBlock) || (i === oldChildren.length - 1 && prevIsBlock)) {
- node.appendChild(oldChildren[i]);
- continue;
- }
- }
- var ret = this._textNodeToLines(oldChildren[i], length, highlight);
- for (var j = 0; j < ret.length; j++) {
- node.appendChild(ret[j]);
- }
- } else if (oldChildren[i].nodeType === ELEMENT_NODE) {
- var firstword = this._lengthOfFirstInlineWord(oldChildren[i]),
- overlength = ((this._currentInlineOffset + firstword) > length && this._currentInlineOffset > 0);
- if (overlength && this._isInlineElement(oldChildren[i]) && !this._isIgnoredByLineNumbering(oldChildren[i])) {
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- node.appendChild(this._createLineBreak());
- if (this._currentLineNumber !== null) {
- node.appendChild(this._createLineNumber());
- }
- }
- var changedNode = this._insertLineNumbersToNode(oldChildren[i], length, highlight);
- this._moveLeadingLineBreaksToOuterNode(changedNode, node);
- node.appendChild(changedNode);
- } else {
- throw 'Unknown nodeType: ' + i + ': ' + oldChildren[i];
- }
- }
-
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- this._prependLineNumberToFirstText = true;
- this._ignoreNextRegularLineNumber = false;
-
- return node;
- };
-
- this._insertLineNumbersToNode = function (node, length, highlight) {
- if (node.nodeType !== ELEMENT_NODE) {
- throw 'This method may only be called for ELEMENT-nodes: ' + node.nodeValue;
- }
- if (this._isIgnoredByLineNumbering(node)) {
- if (this._currentInlineOffset === 0 && this._currentLineNumber !== null) {
- var lineNumberNode = this._createLineNumber();
- if (lineNumberNode) {
- node.insertBefore(lineNumberNode, node.firstChild);
- this._ignoreNextRegularLineNumber = true;
- }
- }
- return node;
- } else if (this._isInlineElement(node)) {
- return this._insertLineNumbersToInlineNode(node, length, highlight);
- } else {
- var newLength = this._calcBlockNodeLength(node, length);
- return this._insertLineNumbersToBlockNode(node, newLength, highlight);
- }
- };
-
- this._stripLineNumbers = function (node) {
- for (var i = 0; i < node.childNodes.length; i++) {
- if (this._isOsLineBreakNode(node.childNodes[i]) || this._isOsLineNumberNode(node.childNodes[i])) {
- // If a newline character follows a line break, it's been very likely inserted by the WYSIWYG-editor
- if (node.childNodes.length > (i + 1) && node.childNodes[i + 1].nodeType === TEXT_NODE) {
- if (node.childNodes[i + 1].nodeValue[0] === "\n") {
- node.childNodes[i + 1].nodeValue = " " + node.childNodes[i + 1].nodeValue.substring(1);
- }
- }
- node.removeChild(node.childNodes[i]);
- i--;
- } else {
- this._stripLineNumbers(node.childNodes[i]);
- }
- }
- };
-
- this._nodesToHtml = function (nodes) {
- var root = document.createElement('div');
- for (var i in nodes) {
- if (nodes.hasOwnProperty(i)) {
- root.appendChild(nodes[i]);
- }
- }
- return root.innerHTML;
- };
-
- /**
- *
- * @param {string} html
- * @param {number|string} lineLength
- * @param {number|null} highlight - optional
- * @param {number|null} firstLine
- */
- this.insertLineNumbersNode = function (html, lineLength, highlight, firstLine) {
- // Removing newlines after BRs, as they lead to problems like #3410
- if (html) {
- html = html.replace(/( ]*>)[\n\r]+/gi, '$1');
- }
-
- var root = document.createElement('div');
- root.innerHTML = html;
-
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- if (firstLine) {
- this._currentLineNumber = parseInt(firstLine);
- } else {
- this._currentLineNumber = 1;
- }
- if (highlight !== null) {
- highlight = parseInt(highlight);
- }
- this._prependLineNumberToFirstText = true;
- this._ignoreNextRegularLineNumber = false;
- this._ignoreInsertedText = true;
-
- return this._insertLineNumbersToNode(root, lineLength, highlight);
- };
-
- /**
- *
- * @param {string} html
- * @param {number} lineLength
- * @param {number|null} highlight - optional
- * @param {function} callback
- * @param {number} firstLine
- * @returns {string}
- */
- this.insertLineNumbers = function (html, lineLength, highlight, callback, firstLine) {
- var newHtml, newRoot;
-
- if (highlight > 0) {
- // Caching versions with highlighted line numbers is probably not worth it
- newRoot = this.insertLineNumbersNode(html, lineLength, highlight, firstLine);
- newHtml = newRoot.innerHTML;
- } else {
- var firstLineStr = (firstLine === undefined || firstLine === null ? '' : firstLine.toString());
- var cacheKey = this.djb2hash(firstLineStr + "-" + lineLength.toString() + html);
- newHtml = lineNumberCache.get(cacheKey);
-
- if (angular.isUndefined(newHtml)) {
- newRoot = this.insertLineNumbersNode(html, lineLength, null, firstLine);
- newHtml = newRoot.innerHTML;
- lineNumberCache.put(cacheKey, newHtml);
- }
- }
-
- if (callback) {
- callback();
- }
-
- return newHtml;
- };
-
- /**
- * @param {string} html
- * @param {number} lineLength
- * @param {boolean} countInserted
- */
- this.insertLineBreaksWithoutNumbers = function (html, lineLength, countInserted) {
- var root = document.createElement('div');
- root.innerHTML = html;
-
- this._currentInlineOffset = 0;
- this._lastInlineBreakablePoint = null;
- this._currentLineNumber = null;
- this._prependLineNumberToFirstText = true;
- this._ignoreNextRegularLineNumber = false;
- this._ignoreInsertedText = !countInserted;
-
- var newRoot = this._insertLineNumbersToNode(root, lineLength, null);
-
- return newRoot.innerHTML;
- };
-
- /**
- * @param {string} html
- * @returns {string}
- */
- this.stripLineNumbers = function (html) {
- var root = document.createElement('div');
- root.innerHTML = html;
- this._stripLineNumbers(root);
- return root.innerHTML;
- };
-
- /**
- * @param {string} html
- * @returns {object}
- * {"from": 23, "to": 42} ; "to" refers to the line breaking element at the end of the last line,
- * i.e. the line number of the following line
- */
- this.getLineNumberRange = function (html) {
- var fragment = this._htmlToFragment(html),
- range = {
- "from": null,
- "to": null
- };
- var lineNumbers = fragment.querySelectorAll('.os-line-number');
- for (var i = 0; i < lineNumbers.length; i++) {
- var node = lineNumbers.item(i);
- var number = parseInt(node.getAttribute("data-line-number"));
- if (range.from === null || number < range.from) {
- range.from = number;
- }
- if (range.to === null || (number + 1) > range.to) {
- range.to = number + 1;
- }
- }
- return range;
- };
-
- /**
- * @param {string} html
- */
- this.getHeadingsWithLineNumbers = function (html) {
- var fragment = this._htmlToFragment(html),
- headings = [];
- var headingNodes = fragment.querySelectorAll('h1, h2, h3, h4, h5, h6');
- for (var i = 0; i < headingNodes.length; i++) {
- var heading = headingNodes.item(i);
- var linenumbers = heading.querySelectorAll('.os-line-number');
- if (linenumbers.length > 0) {
- var number = parseInt(linenumbers.item(0).getAttribute("data-line-number"));
- headings.push({
- "lineNumber": number,
- "level": parseInt(heading.nodeName.substr(1)),
- "text": heading.innerText.replace(/^\s/, "").replace(/\s$/, "")
- });
- }
- }
- return headings.sort(function(heading1, heading2) {
- if (heading1.lineNumber < heading2.lineNumber) {
- return 0;
- } else if (heading1.lineNumber > heading2.lineNumber) {
- return 1;
- } else {
- return 0;
- }
- });
- };
-
- /**
- * @param {Element} node
- * @returns {array}
- * @private
- */
- this._splitNodeToParagraphs = function (node) {
- var elements = [];
- for (var i = 0; i < node.childNodes.length; i++) {
- var childNode = node.childNodes.item(i);
-
- if (childNode.nodeType === TEXT_NODE) {
- continue;
- }
- if (childNode.nodeName === 'UL' || childNode.nodeName === 'OL') {
- var start = 1;
- if (childNode.getAttribute("start") !== null) {
- start = parseInt(childNode.getAttribute("start"));
- }
- for (var j = 0; j < childNode.childNodes.length; j++) {
- if (childNode.childNodes.item(j).nodeType === TEXT_NODE) {
- continue;
- }
- var newParent = childNode.cloneNode(false);
- if (childNode.nodeName === 'OL') {
- newParent.setAttribute('start', start);
- }
- newParent.appendChild(childNode.childNodes.item(j).cloneNode(true));
- elements.push(newParent);
- start++;
- }
- } else {
- elements.push(childNode);
- }
- }
- return elements;
- };
-
- /**
- * Splitting the text into paragraphs:
- * - Each root-level-element is considered as a paragraph.
- * Inline-elements at root-level are not expected and treated as block elements.
- * Text-nodes at root-level are not expected and ignored. Every text needs to be wrapped e.g. by or
.
- * - If a UL or OL is encountered, paragraphs are defined by the child-LI-elements.
- * List items of nested lists are not considered as a paragraph of their own.
- *
- * @param {string} html
- * @return {string[]}
- */
- this.splitToParagraphs = function (html) {
- var fragment = this._htmlToFragment(html);
- return this._splitNodeToParagraphs(fragment).map(function(node) { return node.outerHTML; });
- };
-
- /**
- * Traverses up the DOM tree until it finds a node with a nextSibling, then returns that sibling
- *
- * @param node
- * @private
- */
- this._findNextAuntNode = function(node) {
- if (node.nextSibling) {
- return node.nextSibling;
- } else if (node.parentNode) {
- return this._findNextAuntNode(node.parentNode);
- } else {
- return null;
- }
- };
-
- this._highlightUntilNextLine = function(lineNumberNode) {
- var currentNode = lineNumberNode,
- foundNextLineNumber = false;
-
- do {
- var wasHighlighted = false;
- if (currentNode.nodeType === TEXT_NODE) {
- var node = document.createElement('span');
- node.setAttribute('class', 'highlight');
- node.innerHTML = currentNode.nodeValue;
- currentNode.parentNode.insertBefore(node, currentNode);
- currentNode.parentNode.removeChild(currentNode);
- currentNode = node;
- wasHighlighted = true;
- } else {
- wasHighlighted = false;
- }
-
- if (currentNode.childNodes.length > 0 && !this._isOsLineNumberNode(currentNode) && !wasHighlighted) {
- currentNode = currentNode.childNodes[0];
- } else if (currentNode.nextSibling) {
- currentNode = currentNode.nextSibling;
- } else {
- currentNode = this._findNextAuntNode(currentNode);
- }
-
- if (this._isOsLineNumberNode(currentNode)) {
- foundNextLineNumber = true;
- }
- } while (!foundNextLineNumber && currentNode !== null);
- };
-
- /**
- * @param {string} html
- * @param {number} lineNumber
- * @return {string}
- */
- this.highlightLine = function (html, lineNumber) {
- lineNumber = parseInt(lineNumber);
- var fragment = this._htmlToFragment(html),
- lineNumberNode = this._getLineNumberNode(fragment, lineNumber);
-
- if (lineNumberNode) {
- this._highlightUntilNextLine(lineNumberNode);
- html = this._fragmentToHtml(fragment);
- }
-
- return html;
- };
- }
-]);
-
-
-}());
diff --git a/openslides/motions/static/js/motions/motion-block-projector.js b/openslides/motions/static/js/motions/motion-block-projector.js
deleted file mode 100644
index 5db18429c..000000000
--- a/openslides/motions/static/js/motions/motion-block-projector.js
+++ /dev/null
@@ -1,59 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.motionBlockProjector', [])
-
-
-// MotionBlock projector elements
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('motions/motion-block', {
- template: 'static/templates/motions/slide_motion_block.html',
- });
- }
-])
-
-.controller('SlideMotionBlockCtrl', [
- '$scope',
- 'Motion',
- 'MotionBlock',
- function($scope, Motion, MotionBlock) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- MotionBlock.bindOne(id, $scope, 'motionBlock');
-
- // Returns a shortened motion title. If the title is longer then maxLength, it is
- // split at the last whitespace that is in maxLength. Three dots are added then.
- $scope.getShortTitle = function (motion) {
- var maxLength = 40;
- var title = motion.getTitle();
-
- if (title.length <= maxLength) {
- return title;
- }
-
- // Find last whitespace that is before maxLength. Split the title
- // there and append dots.
- var whitespaceIndex = -1;
- for (var i = 0; i < maxLength+1; i++) {
- if (title[i] === ' ') {
- whitespaceIndex = i;
- }
- }
-
- if (whitespaceIndex === -1) {
- // just one long word.. split it :/
- return title.substr(0, maxLength) + '...';
- } else {
- return title.substr(0, whitespaceIndex) + '...';
- }
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/motion-block.js b/openslides/motions/static/js/motions/motion-block.js
deleted file mode 100644
index eb71e1f82..000000000
--- a/openslides/motions/static/js/motions/motion-block.js
+++ /dev/null
@@ -1,262 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.motionBlock', [])
-
-
-// MotionBlock model
-
-.factory('MotionBlock', [
- 'DS',
- 'jsDataModel',
- 'gettext',
- function(DS, jsDataModel, gettext) {
- var name = 'motions/motion-block';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Motion block'),
- methods: {
- getResourceName: function () {
- return name;
- },
- getAgendaTitle: function () {
- return this.title;
- },
- },
- relations: {
- belongsTo: {
- 'agenda/item': {
- localKey: 'agenda_item_id',
- localField: 'agenda_item',
- }
- },
- hasMany: {
- 'motions/motion': {
- localField: 'motions',
- foreignKey: 'motion_block_id',
- osProtectedRelation: true,
- }
- },
- }
- });
- }
-])
-
-.run(['MotionBlock', function(MotionBlock) {}])
-
-// MotionBlock views (list view, create dialog, update dialog)
-.factory('MotionBlockForm', [
- '$http',
- 'operator',
- 'gettextCatalog',
- 'Agenda',
- 'AgendaTree',
- 'ShowAsAgendaItemField',
- function ($http, operator, gettextCatalog, Agenda, AgendaTree, ShowAsAgendaItemField) {
- return {
- // Get ngDialog configuration.
- getDialog: function (motionBlock) {
- return {
- template: 'static/templates/motions/motion-block-form.html',
- controller: (motionBlock) ? 'MotionBlockUpdateCtrl' : 'MotionBlockCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionBlockId: function () {return motionBlock ? motionBlock.id : void 0;}
- }
- };
- },
- // Get angular-formly fields.
- getFormFields: function (isCreateForm) {
- var formFields = [
- {
- key: 'title',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Title')
- }
- },
- ];
-
- // show as agenda item + parent item
- if (isCreateForm) {
- formFields.push(ShowAsAgendaItemField('motions.can_manage'));
- formFields.push({
- key: 'agenda_parent_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Parent item'),
- options: AgendaTree.getFlatTree(Agenda.getAll()),
- ngOptions: 'item.id as item.getListViewTitle() for item in to.options | notself : model.agenda_item_id',
- placeholder: gettextCatalog.getString('Select a parent item ...')
- },
- hide: !operator.hasPerms('agenda.can_manage')
- });
- }
-
- return formFields;
- }
- };
- }
-])
-
-.controller('MotionBlockListCtrl', [
- '$scope',
- 'ngDialog',
- 'MotionBlock',
- 'MotionBlockForm',
- 'Projector',
- 'ProjectionDefault',
- function ($scope, ngDialog, MotionBlock, MotionBlockForm, Projector, ProjectionDefault) {
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'motionBlocks'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- // Two-way data binding for all MotionBlock instances.
- MotionBlock.bindAll({}, $scope, 'motionBlocks');
-
- // Dialog with a form to create or update a MotionBlock instance.
- $scope.openFormDialog = function (motionBlock) {
- ngDialog.open(MotionBlockForm.getDialog(motionBlock));
- };
-
- // Confirm dialog to delete a MotionBlock instance.
- $scope.delete = function (motionBlock) {
- MotionBlock.destroy(motionBlock.id);
- };
- }
-])
-
-.controller('MotionBlockDetailCtrl', [
- '$scope',
- '$http',
- 'ngDialog',
- 'Motion',
- 'MotionBlockForm',
- 'MotionBlock',
- 'motionBlockId',
- 'Projector',
- 'ProjectionDefault',
- 'WebpageTitle',
- 'gettextCatalog',
- 'ErrorMessage',
- function($scope, $http, ngDialog, Motion, MotionBlockForm, MotionBlock, motionBlockId, Projector,
- ProjectionDefault, WebpageTitle, gettextCatalog, ErrorMessage) {
- $scope.$watch(function () {
- return MotionBlock.lastModified(motionBlockId);
- }, function () {
- $scope.motionBlock = MotionBlock.get(motionBlockId);
- WebpageTitle.updateTitle(gettextCatalog.getString('Motion block') + ' ' +
- $scope.motionBlock.agenda_item.getTitle());
- });
- Motion.bindAll({}, $scope, 'motions');
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'motionBlocks'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.openDialog = function (motionBlock) {
- ngDialog.open(MotionBlockForm.getDialog(motionBlock));
- };
- $scope.followRecommendations = function () {
- $http.post('/rest/motions/motion-block/' + motionBlockId + '/follow_recommendations/').then(
- function (success) {
- $scope.alert = { type: 'success', msg: success.data.detail, show: true };
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- $scope.delete = function (motion) {
- motion.motion_block_id = null;
- motion.title = motion.getTitle(-1);
- motion.text = motion.getText(-1);
- motion.reason = motion.getReason(-1);
- Motion.save(motion);
- };
- }
-])
-
-.controller('MotionBlockCreateCtrl', [
- '$scope',
- 'MotionBlock',
- 'MotionBlockForm',
- 'Config',
- function($scope, MotionBlock, MotionBlockForm, Config) {
- // Prepare form.
- $scope.model = {
- agenda_type: parseInt(Config.get('agenda_new_items_default_visibility').value),
- };
-
- // Get all form fields.
- $scope.formFields = MotionBlockForm.getFormFields(true);
-
- // Save form.
- $scope.save = function (motionBlock) {
- MotionBlock.create(motionBlock).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- }
- );
- };
- }
-])
-
-.controller('MotionBlockUpdateCtrl', [
- '$scope',
- '$state',
- 'MotionBlock',
- 'MotionBlockForm',
- 'motionBlockId',
- function($scope, $state, MotionBlock, MotionBlockForm, motionBlockId) {
- $scope.alert = {};
-
- // Prepare form. Set initial values by creating a deep copy of
- // motionBlock object so list/detail view is not updated while editing.
- var motionBlock = MotionBlock.get(motionBlockId);
- $scope.model = angular.copy(motionBlock);
-
- // Get all form fields.
- $scope.formFields = MotionBlockForm.getFormFields();
-
- // Save form.
- $scope.save = function (motionBlock) {
- // inject the changed motionBlock (copy) object back into DS store
- MotionBlock.inject(motionBlock);
- // save changed motionBlock object on server
- MotionBlock.create(motionBlock).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // Save error: revert all changes by restore
- // (refresh) original motionBlock object from server
- MotionBlock.refresh(motionBlock); // TODO: Why do we need a refresh here?
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- }
- );
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/motion-services.js b/openslides/motions/static/js/motions/motion-services.js
deleted file mode 100644
index f4b6a32ef..000000000
--- a/openslides/motions/static/js/motions/motion-services.js
+++ /dev/null
@@ -1,698 +0,0 @@
-(function () {
-
-"use strict";
-
-angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.lineNumbering'])
-
-/* Generic inline editing factory.
- *
- * getOriginalData: Function that should return the editor data. The editor object is passed.
- * saveData: Function that is called whith the editor object as argument. This function
- * should prepare the save. If the function returns true, the save process won't be
- * continued. Else a patch request is send.
- */
-.factory('MotionInlineEditing', [
- 'Motion',
- '$timeout',
- 'gettextCatalog',
- function (Motion, $timeout, gettextCatalog) {
- var createInstance = function ($scope, motion, selector, versioning, ckeditorOptions, getOriginalData, saveData) {
- var obj = {
- active: false,
- changed: false,
- isEditable: false,
- trivialChange: false,
- originalHtml: null,
- };
- ckeditorOptions.readOnly = true;
-
- obj.setVersion = function (_motion, versionId) {
- motion = _motion; // If this is not updated,
- obj.originalHtml = motion.getTextWithLineBreaks(versionId);
- obj.changed = false;
- if (obj.editor) {
- obj.editor.setReadOnly(true);
- obj.editor.setData(obj.originalHtml);
- }
- };
-
- obj.enable = function () {
- obj.active = true;
- obj.isEditable = true;
- ckeditorOptions.language = localStorage.getItem('language');
- obj.editor = CKEDITOR.inline(selector, ckeditorOptions);
- obj.editor.on('change', function () {
- $timeout(function() {
- if (obj.editor.getData() !== obj.originalHtml) {
- obj.changed = true;
- } else {
- obj.changed = false;
- }
- });
- });
- obj.revert();
- };
-
- obj.disable = function () {
- if (obj.editor) {
- obj.editor.setReadOnly(true);
- obj.editor.setData(obj.originalHtml, {
- callback: function() {
- obj.editor.destroy();
- }
- });
- }
- $timeout(function() {
- obj.active = false;
- obj.changed = false;
- obj.isEditable = false;
- });
- };
-
- // sets editor content to the initial motion state
- obj.revert = function(originalData) {
- if (obj.editor) {
- obj.originalHtml = getOriginalData(obj);
- obj.editor.setData(
- getOriginalData(obj), {
- callback: function() {
- obj.originalHtml = obj.editor.getData();
- obj.editor.setReadOnly(false);
- $timeout(function() {
- obj.changed = false;
- });
- $timeout(function () {
- obj.editor.focus();
- }, 100);
- }
- });
- }
- };
-
- obj.save = function () {
- if (!saveData(obj)) {
- obj.disable();
-
- Motion.inject(motion);
- // save change motion object on server
- Motion.save(motion, {method: 'PATCH'}).then(
- function (success) {
- if (versioning) {
- $scope.showVersion(motion.getVersion(-1));
- }
- obj.revert();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(motion);
- obj.revert();
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- }
- );
- }
- };
-
- return obj;
- };
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('MotionCommentsInlineEditing', [
- 'MotionInlineEditing',
- 'Editor',
- function (MotionInlineEditing, Editor) {
- var createInstances = function ($scope, motion) {
- var commentsInlineEditing = {
- editors: {}, // Map comment id to editor instance.
- };
- var options = Editor.getOptions('inline', 'YOffset');
- _.forEachRight($scope.noSpecialCommentsFields, function (field, id) {
- var inlineEditing = MotionInlineEditing.createInstance($scope, motion,
- 'view-original-comment-inline-editor-' + id, false, options,
- function (obj) {
- return motion['comment_' + id];
- },
- function (obj) {
- if (obj.editor) {
- motion['comment_' + id] = obj.editor.getData();
- }
- }
- );
- commentsInlineEditing.editors[id] = inlineEditing;
- });
- commentsInlineEditing.saveToolbarVisible = function () {
- return _.some(commentsInlineEditing.editors, function (instance) {
- return instance.changed && instance.active;
- });
- };
- commentsInlineEditing.active = function (commentId) {
- return commentsInlineEditing.editors[commentId].active;
- };
- commentsInlineEditing.save = function () {
- _.forEach(commentsInlineEditing.editors, function (instance) {
- instance.save();
- });
- };
- commentsInlineEditing.revert = function () {
- _.forEach(commentsInlineEditing.editors, function (instance) {
- instance.revert();
- });
- };
- commentsInlineEditing.enable = function (commentId) {
- commentsInlineEditing.editors[commentId].enable();
- };
- commentsInlineEditing.disable = function (commentId) {
- commentsInlineEditing.editors[commentId].disable();
- };
-
- return commentsInlineEditing;
- };
- return {
- createInstances: createInstances,
- };
- }
-])
-
-.factory('ChangeRecommendationCreate', [
- 'ngDialog',
- 'ChangeRecommendationTitleForm',
- 'ChangeRecommendationTextForm',
- function(ngDialog, ChangeRecommendationTitleForm, ChangeRecommendationTextForm) {
- var MODE_INACTIVE = 0,
- MODE_SELECTING_FROM = 1,
- MODE_SELECTING_TO = 2,
-
- TITLE_DUMMY_LINE_NUMBER = 0;
-
- var obj = {
- mode: MODE_INACTIVE,
- lineFrom: 1,
- lineTo: 2,
- html: '',
- reviewingHtml: ''
- };
-
- var $scope, motion, version;
-
- obj._getAffectedLineNumbers = function () {
- var changeRecommendations = motion.getTextChangeRecommendations(version.id),
- affectedLines = [];
- for (var i = 0; i < changeRecommendations.length; i++) {
- var change = changeRecommendations[i];
- for (var j = change.line_from; j < change.line_to; j++) {
- affectedLines.push(j);
- }
- }
- return affectedLines;
- };
-
- // startCreating is called right at the beginning after the users interacts with the text for the first time.
- // This ensures all necessary nodes have been initialized
- obj.startCreating = function () {
- if (obj.mode > MODE_SELECTING_FROM || !motion.isAllowed('can_manage')) {
- return;
- }
-
- $(".tt_change_recommendation_create_help").removeClass("opened");
- var $lineNumbers = $(".motion-text-original .os-line-number"),
- $title = $(".motion-title .change-title");
- if ($lineNumbers.filter(".selectable").length === 0) {
- obj.mode = MODE_SELECTING_FROM;
- var alreadyAffectedLines = obj._getAffectedLineNumbers();
- $lineNumbers.each(function () {
- var $this = $(this),
- lineNumber = $this.data("line-number");
- if (alreadyAffectedLines.indexOf(lineNumber) === -1) {
- $(this).addClass("selectable");
- }
- });
- if (alreadyAffectedLines.indexOf(TITLE_DUMMY_LINE_NUMBER) === -1) {
- $title.addClass("selectable");
- }
- }
- };
-
- obj.cancelCreating = function (ev) {
- var $target = $(ev.target),
- query = ".line-numbers-outside .os-line-number.selectable";
- if (!$target.is(query) && $target.parents(query).length === 0) {
- obj.mode = MODE_INACTIVE;
- obj.lineFrom = 0;
- obj.lineTo = 0;
- $(".motion-text-original .os-line-number").removeClass("selected selectable");
- obj.startCreating();
- }
- };
-
- obj.setFromLine = function (line) {
- obj.mode = MODE_SELECTING_TO;
- obj.lineFrom = line;
-
- var alreadyAffectedLines = obj._getAffectedLineNumbers(),
- foundCollission = false;
-
- $(".motion-text-original .os-line-number").each(function () {
- var $this = $(this);
- if ($this.data("line-number") >= line && !foundCollission) {
- if (alreadyAffectedLines.indexOf($this.data("line-number")) === -1) {
- $(this).addClass("selectable");
- } else {
- $(this).removeClass("selectable");
- foundCollission = true;
- }
- } else {
- $(this).removeClass("selectable");
- }
- });
-
- var tt_pos = $(".motion-text-original .line-number-" + line).position().top - 45;
- $(".tt_change_recommendation_create_help").css("top", tt_pos).addClass("opened");
- };
-
- obj.titleClicked = function () {
- ngDialog.open(ChangeRecommendationTitleForm.getCreateDialog(motion, version));
-
- obj.mode = MODE_INACTIVE;
- obj.lineFrom = 0;
- obj.lineTo = 0;
- $(".motion-text-original .os-line-number").removeClass("selected selectable");
- obj.startCreating();
- };
-
- obj.setToLine = function (line) {
- if (line < obj.lineFrom) {
- return;
- }
- obj.mode = MODE_INACTIVE;
- ngDialog.open(ChangeRecommendationTextForm.getCreateDialog(motion, version, obj.lineFrom, line + 1));
-
- obj.lineFrom = 0;
- obj.lineTo = 0;
- $(".motion-text-original .os-line-number").removeClass("selected selectable");
- obj.startCreating();
- };
-
- obj.lineClicked = function (ev) {
- if (obj.mode === MODE_INACTIVE) {
- return;
- }
- if (obj.mode === MODE_SELECTING_FROM) {
- obj.setFromLine($(ev.target).data("line-number"));
- $(ev.target).addClass("selected");
- } else if (obj.mode === MODE_SELECTING_TO) {
- obj.setToLine($(ev.target).data("line-number"));
- }
- };
-
- obj.mouseOver = function (ev) {
- if (obj.mode !== MODE_SELECTING_TO) {
- return;
- }
- var hoverLine = $(ev.target).data("line-number");
- $(".motion-text-original .os-line-number").each(function () {
- var line = $(this).data("line-number");
- if (line >= obj.lineFrom && line <= hoverLine) {
- $(this).addClass("selected");
- } else {
- $(this).removeClass("selected");
- }
- });
- };
-
- obj.setVersion = function (_motion, _version) {
- motion = _motion;
- version = motion.getVersion(_version);
- };
-
- obj.editTextDialog = function(change_recommendation) {
- ngDialog.open(ChangeRecommendationTextForm.getEditDialog(change_recommendation));
- };
-
- obj.editTitleDialog = function(change_recommendation) {
- ngDialog.open(ChangeRecommendationTitleForm.getEditDialog(change_recommendation));
- };
-
- obj.init = function (_scope, _motion) {
- $scope = _scope;
- motion = _motion;
- version = motion.getVersion($scope.version);
-
- var $content = $("#content");
- $content.on("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
- $content.on("click", ".motion-title .change-title.selectable", obj.titleClicked);
- $content.on("click", obj.cancelCreating);
- $content.on("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
- $content.on("mouseover", ".motion-text-original, .motion-title", obj.startCreating);
-
- $scope.$watch(function () {
- return $scope.change_recommendations.length;
- }, function () {
- if (obj.mode === MODE_INACTIVE || obj.mode === MODE_SELECTING_FROM) {
- // Recalculate the affected lines so we cannot select lines affected by a recommendation
- // that has just been created
- $(".motion-text-original .os-line-number").removeClass("selected selectable");
- $(".motion-title .change-title").removeClass("selected selectable");
- obj.startCreating();
- }
- });
-
- $scope.$on("$destroy", function () {
- obj.destroy();
- });
- };
-
- obj.destroy = function () {
- var $content = $("#content");
- $content.off("click", ".line-numbers-outside .os-line-number.selectable", obj.lineClicked);
- $content.off("click", ".motion-title .change-title.selectable", obj.titleClicked);
- $content.off("click", obj.cancelCreating);
- $content.off("mouseover", ".line-numbers-outside .os-line-number.selectable", obj.mouseOver);
- $content.off("mouseover", ".motion-text-original, .motion-title", obj.startCreating);
- };
-
- return obj;
- }
-])
-
-.factory('ChangeRecommendationView', [
- 'Motion',
- 'MotionChangeRecommendation',
- 'Config',
- 'lineNumberingService',
- 'diffService',
- '$interval',
- '$timeout',
- function (Motion, MotionChangeRecommendation, Config, lineNumberingService, diffService, $interval, $timeout) {
- var $scope, motion;
-
- var obj = {
- mode: 'original',
- context: null
- };
-
- obj.diffFormatterCb = function (change, oldFragment, newFragment) {
- for (var i = 0; i < oldFragment.childNodes.length; i++) {
- diffService.addCSSClass(oldFragment.childNodes[i], 'delete');
- }
- for (i = 0; i < newFragment.childNodes.length; i++) {
- diffService.addCSSClass(newFragment.childNodes[i], 'insert');
- }
- var mergedFragment = document.createDocumentFragment(),
- diffSection = document.createElement('SECTION'),
- el;
-
- mergedFragment.appendChild(diffSection);
- diffSection.setAttribute('class', 'diff');
- diffSection.setAttribute('data-change-id', change.id);
-
- while (oldFragment.firstChild) {
- el = oldFragment.firstChild;
- oldFragment.removeChild(el);
- diffSection.appendChild(el);
- }
- while (newFragment.firstChild) {
- el = newFragment.firstChild;
- newFragment.removeChild(el);
- diffSection.appendChild(el);
- }
-
- return mergedFragment;
- };
-
- obj.delete = function (changeId) {
- MotionChangeRecommendation.destroy(changeId);
- };
-
- obj.rejectAllChangeRecommendations = function (motion) {
- var changeRecommendations = MotionChangeRecommendation.filter({
- 'where': {'motion_version_id': {'==': motion.active_version}}
- });
- _.forEach(changeRecommendations, function(change) {
- change.rejected = true;
- change.saveStatus();
- });
- };
-
- obj.repositionOriginalAnnotations = function () {
- var $changeRecommendationList = $('.change-recommendation-list'),
- $lineNumberReference = $('.motion-text-original');
-
- $changeRecommendationList.children().each(function() {
- var $this = $(this),
- lineFrom = $this.data('line-from'),
- lineTo = ($this.data('line-to') - 1),
- $lineFrom = $lineNumberReference.find('.line-number-' + lineFrom),
- $lineTo = $lineNumberReference.find('.line-number-' + lineTo),
- fromTop = $lineFrom.position().top + 3,
- toTop = $lineTo.position().top + 20,
- height = (toTop - fromTop);
-
- if (height < 10) {
- height = 10;
- }
-
- // $lineFrom.position().top seems to depend on the scrolling position when the line numbers
- // have position: absolute. Maybe a bug in the used version of jQuery?
- // This cancels the effect.
- /*
- if ($lineNumberReference.hasClass('line-numbers-outside')) {
- fromTop += window.scrollY;
- }
- */
-
- $this.css({ 'top': fromTop, 'height': height });
- });
- };
-
- obj.copyToModifiedFinalVersion = function (motion, version) {
- if (!motion.isAllowed('update')) {
- throw 'No permission to update motion';
- }
-
- motion.copyModifiedFinalVersionStrippingLineBreaks();
-
- Motion.inject(motion);
- // save change motion object on server
- Motion.save(motion, {method: 'PATCH'}).then(null, function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(motion);
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- });
- };
-
- obj.deleteModifiedFinalVersion = function (motion, version) {
- if (!motion.isAllowed('update')) {
- throw 'No permission to update motion';
- }
-
- if (!motion.getModifiedFinalVersion(version)) {
- return;
- }
-
- motion.modified_final_version = '';
-
- Motion.inject(motion);
- // save change motion object on server
- Motion.save(motion, {method: 'PATCH'}).then(function (success) {
- $scope.viewChangeRecommendations.mode = 'agreed';
- }, function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(motion);
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- });
- };
-
- obj.newVersionIncludingChanges = function (motion, version) {
- if (!motion.isAllowed('update')) {
- throw 'No permission to update motion';
- }
-
- var newHtml = motion.getTextByMode('agreed');
- motion.setTextStrippingLineBreaks(newHtml);
-
- Motion.inject(motion);
- // save change motion object on server
- Motion.save(motion, {method: 'PATCH'}).then(
- function (success) {
- $scope.showVersion(motion.getVersion(-1));
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(motion);
- var message = '';
- for (var e in error.data) {
- message += e + ': ' + error.data[e] + ' ';
- }
- $scope.alert = {type: 'danger', msg: message, show: true};
- }
- );
- };
-
- obj.scrollToDiffBox = function (changeId) {
- obj.mode = 'diff';
- $timeout(function() {
- var $diffBox = $('.diff-box-' + changeId);
- $('html, body').animate({
- scrollTop: $diffBox.offset().top - 50
- }, 300);
- }, 0, false);
- };
-
- // $scope.amendments_crs holds the change objects of all change recommendations regarding the text,
- // and all amendments with a "accepted"-recommendation, ordered by the first affected line number.
- obj.set_amendments_crs_watcher = function($scope, motion) {
- $scope.amendments_crs = [];
- $scope.change_recommendations = [];
- $scope.paragraph_amendments = [];
- $scope.has_proposed_changes = false;
- $scope.changed_version_has_collissions = false;
-
- var rebuild_amendments_crs = function () {
- $scope.amendments_crs = $scope.change_recommendations.map(function (cr) {
- return cr.getUnifiedChangeObject();
- }).concat(
- $scope.paragraph_amendments.map(function (amendment) {
- return amendment.getUnifiedChangeObject();
- })
- );
- $scope.amendments_crs.sort(function (change1, change2) {
- if (change1.line_from > change2.line_from) {
- return 1;
- } else if (change1.line_from < change2.line_from) {
- return -1;
- } else {
- return 0;
- }
- });
-
- // Set all crs and amendments for collission detection.
- _.forEach($scope.amendments_crs, function (change) {
- change.setOtherChangesForCollission($scope.amendments_crs);
- });
-
- $scope.has_proposed_changes = ($scope.amendments_crs.length > 0);
- $scope.changed_version_has_accepted_collissions = ($scope.amendments_crs.find(function(change) {
- return (change.getCollissions(true).length !== 0);
- }) !== undefined);
-
- if (obj.context === 'site') {
- if (!$scope.has_proposed_changes) {
- $scope.setProjectionMode($scope.projectionModes[0]);
- }
- if ($scope.has_proposed_changes) {
- $scope.disableMotionInlineEditing();
- }
- }
- };
-
- $scope.$watch(function () {
- return MotionChangeRecommendation.lastModified();
- }, function () {
- $scope.change_recommendations = [];
- $scope.title_change_recommendation = null;
- MotionChangeRecommendation.filter({
- 'where': {'motion_version_id': {'==': motion.active_version}}
- }).forEach(function (change) {
- if (change.isTextRecommendation()) {
- $scope.change_recommendations.push(change);
- }
- if (change.isTitleRecommendation()) {
- $scope.title_change_recommendation = change;
- }
- });
- rebuild_amendments_crs();
- });
-
- $scope.$watch(function () {
- return Motion.lastModified();
- }, function () {
- if (motion) {
- $scope.paragraph_amendments = motion.getParagraphBasedAmendmentsForDiffView();
- rebuild_amendments_crs();
- }
- });
- };
-
- obj.setVersion = function (_motion/*, _version*/) {
- motion = _motion;
- };
-
- obj.initProjector = function (_scope, _motion, viewMode) {
- obj.context = 'projector';
- $scope = _scope;
- motion = _motion;
-
- obj.set_amendments_crs_watcher($scope, motion);
- obj.mode = viewMode;
- };
-
- obj.initSite = function (_scope, _motion, viewMode) {
- obj.context = 'site';
- $scope = _scope;
- motion = _motion;
-
- obj.set_amendments_crs_watcher($scope, motion);
-
- $scope.$evalAsync(function() {
- obj.repositionOriginalAnnotations();
- });
- $scope.$watch(function() {
- return $('.change-recommendation-list').children().length;
- }, obj.repositionOriginalAnnotations);
-
- var checkGotoOriginal = function () {
- if ($scope.amendments_crs.length === 0 && $scope.title_change_recommendation === null) {
- obj.mode = 'original';
- }
- };
- $scope.$watch(function () {
- return $scope.amendments_crs.length;
- }, checkGotoOriginal);
- $scope.$watch(function () {
- return $scope.title_change_recommendation;
- }, checkGotoOriginal);
-
- var sizeCheckerLastSize = null,
- sizeCheckerLastClass = null,
- sizeChecker = $interval(function() {
- var $holder = $(".motion-text-original"),
- newHeight = $holder.height(),
- classes = $holder.attr("class");
- if (newHeight !== sizeCheckerLastSize || sizeCheckerLastClass !== classes) {
- sizeCheckerLastSize = newHeight;
- sizeCheckerLastClass = classes;
- obj.repositionOriginalAnnotations();
- }
- }, 100, 0, false);
-
- $scope.$on('$destroy', function() {
- $interval.cancel(sizeChecker);
- });
-
- obj.mode = viewMode;
- };
-
- return obj;
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/pdf.js b/openslides/motions/static/js/motions/pdf.js
deleted file mode 100644
index 2becb86f4..000000000
--- a/openslides/motions/static/js/motions/pdf.js
+++ /dev/null
@@ -1,1447 +0,0 @@
-(function () {
-
-"use strict";
-
-angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
-
-.factory('MotionContentProvider', [
- '$q',
- '$filter',
- 'operator',
- 'gettextCatalog',
- 'PDFLayout',
- 'PdfMakeConverter',
- 'ImageConverter',
- 'HTMLValidizer',
- 'Category',
- 'Config',
- 'Motion',
- 'MotionComment',
- 'MotionPollDecimalPlaces',
- 'OpenSlidesSettings',
- function($q, $filter, operator, gettextCatalog, PDFLayout, PdfMakeConverter, ImageConverter,
- HTMLValidizer, Category, Config, Motion, MotionComment, MotionPollDecimalPlaces, OpenSlidesSettings) {
- /**
- * Provides the content as JS objects for Motions in pdfMake context
- * @constructor
- */
-
- var createInstance = function(motion, motionVersion, params) {
- params = _.clone(params || {}); // Clone this to avoid sideeffects.
- _.defaults(params, {
- changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
- lineNumberMode: Config.get('motions_default_line_numbering').value,
- include: {
- text: true,
- reason: true,
- state: true,
- category: true,
- submitters: true,
- votingresult: true,
- motionBlock: true,
- origin: true,
- recommendation: true,
- },
- includeComments: {},
- });
-
- var converter, imageMap = {};
-
- // Query all image sources from motion text and reason
- var getImageSources = function () {
- var text = motion.getTextByMode(params.changeRecommendationMode, null);
- var reason = motion.getReason();
- var comments = '';
- _.forEach(params.includeComments, function (ok, id) {
- if (ok && motion.comments[id]) {
- comments += HTMLValidizer.validize(motion.comments[id]);
- }
- });
- var content = HTMLValidizer.validize(text) + HTMLValidizer.validize(motion.getReason()) + comments;
- var map = Function.prototype.call.bind([].map);
- return map($(content).find('img'), function(element) {
- return element.getAttribute('src');
- });
- };
-
- // title
- var identifier = motion.identifier ? ' ' + motion.identifier : '';
- var titlePlain = motion.getTitleWithChanges(params.changeRecommendationMode, motionVersion);
- var title = PDFLayout.createTitle(gettextCatalog.getString('Motion') + identifier + ': ' + titlePlain);
-
- // subtitle and sequential number
- var subtitleLines = [];
- if (motion.parent_id) {
- var parentMotion = Motion.get(motion.parent_id);
- subtitleLines.push(
- gettextCatalog.getString('Amendment to motion') + ': ' +
- (parentMotion.identifier ? parentMotion.identifier : parentMotion.getTitle())
- );
- }
- if (Config.get('motions_export_sequential_number').value) {
- subtitleLines.push(gettextCatalog.getString('Sequential number') + ': ' +
- motion.getSequentialNumber());
- }
- var subtitle = PDFLayout.createSubtitle(subtitleLines);
-
- // meta data table
- var metaTable = function() {
- var metaTableBody = [];
-
- // submitters
- var submitters = _.map(
- $filter('orderBy')(motion.submitters, 'weight'), function (submitter) {
- return submitter.user.get_full_name();
- }
- ).join(', ');
- if (params.include.submitters) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Submitters') + ':',
- style: ['bold', 'grey'],
- },
- {
- text: submitters,
- style: 'grey'
- }
- ]);
- }
-
- // state
- if (params.include.state) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('State') + ':',
- style: ['bold', 'grey']
- },
- {
- text: motion.getStateName(),
- style: 'grey'
- }
- ]);
- }
-
- // recommendation
- if (params.include.recommendation && motion.getRecommendationName()) {
- metaTableBody.push([
- {
- text: Config.get('motions_recommendations_by').value + ':',
- style: ['bold', 'grey']
- },
- {
- text: motion.getRecommendationName(),
- style: 'grey'
- }
- ]);
- }
-
- // category
- if (params.include.category && motion.category) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Category') + ':',
- style: ['bold', 'grey'] },
- {
- text: motion.category.prefix + ' - ' + motion.category.name,
- style: 'grey'
- }
- ]);
- }
-
- // motion block
- if (params.include.motionBlock && motion.motionBlock) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Motion block') + ':',
- style: ['bold', 'grey'] },
- {
- text: motion.motionBlock.title,
- style: 'grey'
- }
- ]);
- }
-
- // origin
- if (params.include.origin && motion.origin) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Origin') + ':',
- style: ['bold', 'grey'] },
- {
- text: motion.origin,
- style: 'grey'
- }
- ]);
- }
-
- // voting result
- if (params.include.votingresult && motion.polls.length > 0 && motion.polls[0].has_votes) {
- var column1 = [];
- var column2 = [];
- var column3 = [];
- motion.polls.map(function(poll, index) {
- if (poll.has_votes) {
- // votenumber
- if (motion.polls.length > 1) {
- column1.push(index + 1 + '. ' + gettextCatalog.getString('Vote'));
- column2.push('');
- column3.push('');
- }
- var precision = MotionPollDecimalPlaces.getPlaces(poll);
- // yes
- var yes = poll.getVote(poll.yes, 'yes');
- column1.push(gettextCatalog.getString('Yes') + ':');
- column2.push($filter('number')(yes.value, precision));
- column3.push(yes.percentStr);
- // no
- var no = poll.getVote(poll.no, 'no');
- column1.push(gettextCatalog.getString('No') + ':');
- column2.push($filter('number')(no.value, precision));
- column3.push(no.percentStr);
- // abstain
- var abstain = poll.getVote(poll.abstain, 'abstain');
- column1.push(gettextCatalog.getString('Abstain') + ':');
- column2.push($filter('number')(abstain.value, precision));
- column3.push(abstain.percentStr);
- // votes valid
- if (poll.votesvalid) {
- var valid = poll.getVote(poll.votesvalid, 'votesvalid');
- column1.push(gettextCatalog.getString('Valid votes') + ':');
- column2.push($filter('number')(valid.value, precision));
- column3.push(valid.percentStr);
- }
- // votes invalid
- if (poll.votesvalid) {
- var invalid = poll.getVote(poll.votesinvalid, 'votesinvalid');
- column1.push(gettextCatalog.getString('Invalid votes') + ':');
- column2.push($filter('number')(invalid.value, precision));
- column3.push(invalid.percentStr);
- }
- // votes cast
- if (poll.votescast) {
- var cast = poll.getVote(poll.votescast, 'votescast');
- column1.push(gettextCatalog.getString('Votes cast') + ':');
- column2.push($filter('number')(cast.value, precision));
- column3.push(cast.percentStr);
- }
- }
- });
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Voting result') + ':',
- style: ['bold', 'grey']
- },
- {
- columns: [
- {
- text: column1.join('\n'),
- width: 'auto'
- },
- {
- text: column2.join('\n'),
- width: 'auto',
- alignment: 'right'
- },
- {
- text: column3.join('\n'),
- width: 'auto',
- alignment: 'right'
- },
- ],
- columnGap: 7,
- style: 'grey'
- }
- ]);
- }
-
- // summary of change recommendations (for motion diff version only)
- if (params.changeRecommendationMode === 'diff' && motion.changeRecommendations.length) {
- var columnLineNumbers = [];
- var columnChangeType = [];
- angular.forEach(_.orderBy(motion.changeRecommendations, ['line_from']), function(change) {
- if (change.isTitleRecommendation()) {
- columnLineNumbers.push(
- gettextCatalog.getString('Title') + ': '
- );
- } else {
- // line numbers column
- var line;
- if (change.line_from >= change.line_to - 1) {
- line = change.line_from;
- } else {
- line = change.line_from + ' - ' + (change.line_to - 1);
- }
- columnLineNumbers.push(
- gettextCatalog.getString('Line') + ' ' + line + ': '
- );
- }
- // change type column
- if (change.getType(motion.getVersion(motionVersion).text) === 0) {
- columnChangeType.push(gettextCatalog.getString("Replacement"));
- } else if (change.getType(motion.getVersion(motionVersion).text) === 1) {
- columnChangeType.push(gettextCatalog.getString("Insertion"));
- } else if (change.getType(motion.getVersion(motionVersion).text) === 2) {
- columnChangeType.push(gettextCatalog.getString("Deletion"));
- } else if (change.getType(motion.getVersion(motionVersion).text) === 3) {
- columnChangeType.push(change.other_description);
- }
- });
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Summary of change recommendations'),
- style: ['bold', 'grey']
- },
- {
- columns: [
- {
- text: columnLineNumbers.join('\n'),
- width: 'auto'
- },
- {
- text: columnChangeType.join('\n'),
- width: 'auto'
- }
- ],
- columnGap: 7,
- style: 'grey'
- }
- ]);
- }
-
- if (metaTableBody.length) {
- // build table
- // Used placeholder for 'layout' functions whiche are
- // replaced by lineWitdh/lineColor function in pfd-worker.js.
- // TODO: Remove placeholder and us static values for LineWidth and LineColor
- // if pdfmake has fixed this.
- var metaTable = {
- table: {
- widths: ['35%','65%'],
- body: metaTableBody,
- },
- margin: [0, 0, 0, 20],
- layout: '{{motion-placeholder-to-insert-functions-here}}'
- };
- params.include.metatable = true;
- return metaTable;
- } else {
- return {};
- }
- };
-
- // motion title
- var motionTitle = function() {
- if (params.include.metatable && params.include.text && !motion.isParagraphBasedAmendment()) {
- return [{
- text: titlePlain,
- style: 'heading3'
- }];
- } else {
- return {};
- }
- };
-
- // motion preamble
- var motionPreamble = function () {
- return {
- text: Config.translate(Config.get('motions_preamble').value),
- margin: [0, 10, 0, 0]
- };
- };
-
- var escapeHtml = function(text) {
- return text.replace(/&/, '&').replace(/, '<').replace(/>/, '>');
- };
-
- // motion text (with line-numbers)
- var motionText = function() {
- var content = [];
- if (params.include.text) {
- var motionTextContent = '';
- if (motion.isParagraphBasedAmendment()) {
- // paragraph based amendment
- var diffs = motion.getAmendmentParagraphsLinesDiff();
- if (diffs.length) {
- content.push(motionPreamble());
- _.forEach(diffs, function (diff) {
- motionTextContent += diff.textPre + diff.text + diff.textPost;
- });
- } else {
- motionTextContent += gettextCatalog.getString('No changes at the text.');
- }
- } else {
- // lead motion or normal amendment
- content.push(motionPreamble());
- var titleChange = motion.getTitleChangeRecommendation();
- if (params.changeRecommendationMode === 'diff' && titleChange) {
- motionTextContent += '
' + gettextCatalog.getString('New title') + ': ' +
- escapeHtml(titleChange.text) + '
';
- }
- motionTextContent += motion.getTextByMode(params.changeRecommendationMode, motionVersion);
- }
- content.push(converter.convertHTML(motionTextContent, params.lineNumberMode));
- }
- return content;
- };
-
- // motion reason heading
- var motionReason = function() {
- if (params.include.reason) {
- var reason = [];
- if (motion.getReason(motionVersion)) {
- reason.push({
- text: gettextCatalog.getString('Reason'),
- style: 'heading3',
- marginTop: 25,
- });
- var width;
- if (params.lineNumberMode == 'outside') {
- width = '80%';
- } else {
- width = '100%';
- }
- reason.push({
- columns: [
- {
- width: width,
- stack: converter.convertHTML(motion.getReason(motionVersion), 'none'),
- },
- ]
- });
- }
- return reason;
- }
- };
-
- // motion comments handling
- var motionComments = function () {
- if (_.keys(params.includeComments).length !== 0) {
- var fields = MotionComment.getNoSpecialCommentsFields();
- var comments = [];
- _.forEach(params.includeComments, function (ok, id) {
- if (ok && motion.comments[id]) {
- var title = fields[id].name;
- if (!fields[id].public) {
- title += ' (' + gettextCatalog.getString('internal') + ')';
- }
- comments.push({
- text: title,
- style: 'heading3',
- marginTop: 25,
- });
- comments.push(converter.convertHTML(motion.comments[id]));
- }
- });
- return comments;
- }
- };
-
- // Generates content as a pdfmake consumable
- var getContent = function() {
- var content = [
- title,
- subtitle,
- metaTable(),
- motionTitle()
- ];
- content = content.concat(motionText());
-
- var reason = motionReason();
- if (reason) {
- content.push(reason);
- }
- var comments = motionComments();
- if (comments) {
- content.push(comments);
- }
- return content;
- };
-
- // getters
- var getTitle = function() {
- return motion.getTitle(motionVersion);
- };
-
- var getIdentifier = function() {
- return motion.identifier ? motion.identifier : '';
- };
-
- var getId = function() {
- return motion.id;
- };
-
- var getCategory = function() {
- return motion.category;
- };
-
- var getImageMap = function() {
- return imageMap;
- };
-
- return $q(function (resolve, reject) {
- ImageConverter.toBase64(getImageSources()).then(function (_imageMap) {
- imageMap = _imageMap;
- converter = PdfMakeConverter.createInstance(_imageMap);
- resolve({
- getContent: getContent,
- getTitle: getTitle,
- getIdentifier: getIdentifier,
- getId: getId,
- getCategory: getCategory,
- getImageMap: getImageMap,
- });
- }, reject);
- });
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('MotionPartialContentProvider', [
- '$q',
- 'gettextCatalog',
- 'Config',
- 'PDFLayout',
- 'PdfMakeConverter',
- 'ImageConverter',
- 'HTMLValidizer',
- function ($q, gettextCatalog, Config, PDFLayout, PdfMakeConverter, ImageConverter, HTMLValidizer) {
- /*
- * content should be an array of content blocks. Each content is an object providing a
- * heading and a text. E.g.
- * [{heading: 'comment1', text: ''}, {heading: ...}, ...]
- * */
- var createInstance = function (motion, content) {
-
- var converter, imageMap = {};
-
- // Query all image sources from the content
- var getImageSources = function () {
- var imageSources = [];
- _.forEach(content, function (contentBlock) {
- var html = HTMLValidizer.validize(contentBlock.text);
- imageSources = imageSources.concat(_.map($(html).find('img'), function(element) {
- return element.getAttribute('src');
- }));
- });
- return imageSources;
- };
-
- // title
- var identifier = motion.identifier ? ' ' + motion.identifier : '';
- var title = PDFLayout.createTitle(
- gettextCatalog.getString('Motion') + identifier + ': ' + motion.getTitle()
- );
-
- // subtitle and sequential number
- var subtitleLines = [];
- if (motion.parent_id) {
- var parentMotion = Motion.get(motion.parent_id);
- subtitleLines.push(
- gettextCatalog.getString('Amendment to motion') + ': ' +
- (parentMotion.identifier ? parentMotion.identifier : parentMotion.getTitle())
- );
- }
- if (Config.get('motions_export_sequential_number').value) {
- subtitleLines.push(gettextCatalog.getString('Sequential number') + ': ' + motion.id);
- }
- var subtitle = PDFLayout.createSubtitle(subtitleLines);
-
- // meta data table
- var metaTable = function() {
- var metaTableBody = [];
-
- // submitters
- var submitters = _.map(motion.submitters, function (submitter) {
- return submitter.user.get_full_name();
- }).join(', ');
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Submitters') + ':',
- style: ['bold', 'grey'],
- },
- {
- text: submitters,
- style: 'grey'
- }
- ]);
-
- // state
- metaTableBody.push([
- {
- text: gettextCatalog.getString('State') + ':',
- style: ['bold', 'grey']
- },
- {
- text: motion.getStateName(),
- style: 'grey'
- }
- ]);
-
- // recommendation
- if (motion.getRecommendationName()) {
- metaTableBody.push([
- {
- text: Config.get('motions_recommendations_by').value + ':',
- style: ['bold', 'grey']
- },
- {
- text: motion.getRecommendationName(),
- style: 'grey'
- }
- ]);
- }
-
- // category
- if (motion.category) {
- metaTableBody.push([
- {
- text: gettextCatalog.getString('Category') + ':',
- style: ['bold', 'grey'] },
- {
- text: motion.category.prefix + ' - ' + motion.category.name,
- style: 'grey'
- }
- ]);
- }
-
- // build table
- // Used placeholder for 'layout' functions whiche are
- // replaced by lineWitdh/lineColor function in pfd-worker.js.
- // TODO: Remove placeholder and us static values for LineWidth and LineColor
- // if pdfmake has fixed this.
- var metaTableJsonString = {
- table: {
- widths: ['30%','70%'],
- body: metaTableBody,
- },
- margin: [0, 0, 0, 20],
- layout: '{{motion-placeholder-to-insert-functions-here}}'
- };
- return metaTableJsonString;
- };
-
- var getContentBlockData = function (block) {
- var data = [];
- data.push({
- text: block.heading,
- style: 'heading3',
- marginTop: 25,
- });
- data.push(converter.convertHTML(block.text));
- return data;
- };
-
- // Generates content as a pdfmake consumable
- var getContent = function() {
- var pdfContent = [
- title,
- subtitle,
- metaTable(),
- ];
- _.forEach(content, function (contentBlock) {
- pdfContent.push(getContentBlockData(contentBlock));
- });
- return pdfContent;
- };
-
- var getImageMap = function () {
- return imageMap;
- };
-
- return $q(function (resolve, reject) {
- ImageConverter.toBase64(getImageSources()).then(function (_imageMap) {
- imageMap = _imageMap;
- converter = PdfMakeConverter.createInstance(_imageMap);
- resolve({
- getContent: getContent,
- getImageMap: getImageMap,
- });
- }, reject);
- });
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('PollContentProvider', [
- '$q',
- 'PDFLayout',
- 'gettextCatalog',
- 'Config',
- 'User',
- 'ImageConverter',
- function($q, PDFLayout, gettextCatalog, Config, User, ImageConverter) {
- /**
- * Generates a content provider for polls
- * @constructor
- * @param {string} title - title of poll
- * @param {string} id - if of poll
- */
- var createInstance = function(title, id) {
-
- var logoBallotPaperUrl = Config.get('logo_pdf_ballot_paper').value.path;
- var imageMap = {};
-
- // PDF header
- var header = function() {
- var columns = [];
-
- var text = Config.get('general_event_name').value;
- columns.push({
- text: text,
- fontSize: 8,
- alignment: 'left',
- width: '60%'
- });
-
- // logo
- if (logoBallotPaperUrl) {
- columns.push({
- image: logoBallotPaperUrl,
- fit: [90,25],
- alignment: 'right',
- width: '40%'
- });
- }
- return {
- color: '#555',
- fontSize: 10,
- margin: [30, 10, 10, -10], // [left, top, right, bottom]
- columns: columns,
- columnGap: 5
- };
- };
-
- /**
- * Returns a single section on the ballot paper
- * @function
- */
- var createSection = function() {
- var sheetend = 40;
- return {
- stack: [
- header(),
- {
- text: gettextCatalog.getString('Motion') + ' ' + id,
- style: 'title',
- },
- {
- text: title,
- style: 'description'
- },
- PDFLayout.createBallotEntry(gettextCatalog.getString('Yes')),
- PDFLayout.createBallotEntry(gettextCatalog.getString('No')),
- PDFLayout.createBallotEntry(gettextCatalog.getString('Abstain')),
- ],
- margin: [0, 0, 0, sheetend],
- };
- };
-
- /**
- * Returns Content for single motion
- * @function
- * @param {string} id - if of poll
- */
- var getContent = function() {
- var content = [];
- var amount;
- var amount_method = Config.get('motions_pdf_ballot_papers_selection').value;
- switch (amount_method) {
- case 'NUMBER_OF_ALL_PARTICIPANTS':
- amount = User.getAll().length;
- break;
- case 'NUMBER_OF_DELEGATES':
- //TODO: assumption that DELEGATES is always group id 2. This may not be true
- var group_id = 2;
- amount = User.filter({where: {'groups_id': {contains:group_id} }}).length;
- break;
- case 'CUSTOM_NUMBER':
- amount = Config.get('motions_pdf_ballot_papers_number').value;
- break;
- default:
- // should not happen.
- amount = 0;
- }
- var fullpages = Math.floor(amount / 8);
-
- for (var i=0; i < fullpages; i++) {
- content.push({
- table: {
- headerRows: 1,
- widths: ['*', '*'],
- body: [
- [createSection(), createSection()],
- [createSection(), createSection()],
- [createSection(), createSection()],
- [createSection(), createSection()]
- ],
- pageBreak: 'after'
- },
- layout: PDFLayout.getBallotLayoutLines(),
- rowsperpage: 4
- });
- }
- amount = amount - (fullpages * 8);
- if (amount > 0) {
- var partialpagebody = [];
- while (amount > 1) {
- partialpagebody.push([createSection(), createSection()]);
- amount -=2;
- }
- if (amount == 1) {
- partialpagebody.push([createSection(), '']);
- }
- content.push({
- table: {
- headerRows: 1,
- widths: ['50%', '50%'],
- body: partialpagebody
- },
- layout: PDFLayout.getBallotLayoutLines(),
- rowsperpage: 4
- });
- }
- return content;
- };
-
- var getImageMap = function () {
- return imageMap;
- };
-
- return $q(function (resolve, reject) {
- var imageSources = [
- logoBallotPaperUrl,
- ];
- ImageConverter.toBase64(imageSources).then(function (_imageMap) {
- imageMap = _imageMap;
- resolve({
- getContent: getContent,
- getImageMap: getImageMap,
- });
- }, reject);
- });
- };
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('MotionCatalogContentProvider', [
- 'gettextCatalog',
- 'PDFLayout',
- 'Category',
- 'Config',
- function(gettextCatalog, PDFLayout, Category, Config) {
- /**
- * Constructor
- * @function
- * @param {object} allMotions - A sorted array of all motions to parse
- * @param {string} sorting - The way the catalog has been sorted. Necessary for ToC
- */
- var createInstance = function(allMotions, sorting) {
-
- var title = PDFLayout.createTitle(
- Config.translate(Config.get('motions_export_title').value)
- );
-
- var createPreamble = function() {
- var preambleText = Config.get('motions_export_preamble').value;
- if (preambleText) {
- return {
- text: preambleText,
- style: "preamble"
- };
- } else {
- return "";
- }
- };
-
- var createTOContent = function() {
- var toc = [];
- var exportCategory = (sorting === 'identifier' || sorting === 'category.prefix');
- var uniqueCategories = getUniqueCategories();
- var tocTitle = {
- text: gettextCatalog.getString('Table of contents'),
- style: 'heading2'
- };
-
- // all motions need a page ID. We use the motion identifier for that
- _.forEach(allMotions, function (motion) {
- motion.getContent()[0].id = ''+motion.getId();
- });
-
- if (exportCategory && uniqueCategories) {
- // own table per category
- var catTocBody = [];
- _.forEach(uniqueCategories, function (category) {
- // push the name of the category
- // make a table for correct alignment
- catTocBody.push({
- table: {
- body: [
- [
- {
- text: category.prefix + ' - ' + category.name,
- style: 'tocCategoryTitle'
- }
- ],
- ]
- },
- layout: 'noBorders',
- });
-
- var tocBody = [];
- _.forEach(allMotions, function (motion) {
- if (motion.getCategory() && category.name === motion.getCategory().name) {
- tocBody.push(tocLine(motion, 'tocCategoryEntry'));
- }
- });
- catTocBody.push(tocTable(tocBody));
- });
-
- //handle thouse without category
- var uncatTocBody = [];
- _.forEach(allMotions, function (motion) {
- if (!motion.getCategory()) {
- uncatTocBody.push(tocLine(motion, 'tocEntry'));
- }
- });
-
- // only push this array if there is at least one entry
- if (uncatTocBody.length > 0) {
- catTocBody.push(tocTable(uncatTocBody));
- }
-
- toc.push(catTocBody);
- } else {
- // all categories in the same table
- var tocBody = [];
- _.forEach(allMotions, function (motion) {
- tocBody.push(tocLine(motion, 'tocEntry'));
- });
- toc.push(tocTable(tocBody));
- }
-
- return [
- tocTitle,
- toc,
- PDFLayout.addPageBreak()
- ];
- };
-
- // creates a new table of contents table body
- var tocTable = function (tocBody) {
- return {
- table: {
- widths: ['auto', '*', 'auto'],
- body: tocBody
- },
- layout: 'noBorders',
- style: 'tocCategorySection'
- };
- };
-
- // generates a line in the toc as list-object
- var tocLine = function (motion, style) {
- var firstColumn = "";
- if (motion.getIdentifier()) {
- firstColumn = motion.getIdentifier();
- }
- return [
- {
- text: firstColumn,
- style: style
- },
- {
- text: motion.getTitle(),
- style: 'tocEntry'
- },
- {
- pageReference: ''+motion.getId(),
- style: 'tocEntry',
- alignment: 'right'
- },
- ];
- };
-
- // returns a list of unique category names
- // necessary to create a ToC with categories
- // if a motions without category is found,
- // a corresponding entry should be added aswell
- var getUniqueCategories = function() {
- var categories = [];
- _.forEach(allMotions, function (motion) {
- if (motion.getCategory()) {
- categories.push(
- {
- name: motion.getCategory().name,
- prefix: motion.getCategory().prefix
- }
- );
- }
- });
- return _.uniqBy(categories, 'name');
- };
-
- // returns the pure content of the motion, parseable by pdfmake
- var getContent = function() {
- var motionContent = [];
- _.forEach(allMotions, function(motion, key) {
- motionContent.push(motion.getContent());
- if (key < allMotions.length - 1) {
- motionContent.push(PDFLayout.addPageBreak());
- }
- });
- var content = [];
- // print extra data (title, preamble, categories, toc) only for more than 1 motion
- if (allMotions.length > 1) {
- content.push(
- title,
- createPreamble(),
- createTOContent()
- );
- }
- content.push(motionContent);
- return content;
- };
-
- var getImageMap = function () {
- var imageMap = {};
- _.forEach(allMotions, function (motion) {
- _.forEach(motion.getImageMap(), function (data, path) {
- if (!imageMap[path]) {
- imageMap[path] = data;
- }
- });
- });
- return imageMap;
- };
-
- return {
- getContent: getContent,
- getImageMap: getImageMap,
- };
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('AmendmentContentProvider', [
- '$q',
- 'ImageConverter',
- 'PdfMakeConverter',
- 'HTMLValidizer',
- 'PDFLayout',
- 'Config',
- 'gettextCatalog',
- function ($q, ImageConverter, PdfMakeConverter, HTMLValidizer, PDFLayout, Config, gettextCatalog) {
- var createInstance = function (motions) {
- motions = _.filter(motions, function (motion) {
- return motion.parent_id;
- });
-
- var converter, imageMap = {};
-
- // Query all image sources from motion text and reason
- var getImageSources = function () {
- var sources = [];
- _.forEach(motions, function (motion) {
- var text = motion.getText();
- var reason = motion.getReason();
- var content = HTMLValidizer.validize(text) + HTMLValidizer.validize(motion.getReason());
- _.forEach($(content).find('img'), function (element) {
- sources.push(element.getAttribute('src'));
- });
- });
- return _.uniq(sources);
- };
-
- var createBundleContent = function (bundle) {
- return _.flatten(_.map(bundle, function (motion) {
- var content = [];
-
- // get diffs and title of the changed motions
- var motionText;
- var title = motion.identifier ? gettextCatalog.getString('Motion') + ' ' + motion.identifier : motion.getTitle();
- if (motion.isParagraphBasedAmendment()) {
- // get changed parts
- var paragraphs = motion.getAmendmentParagraphsLinesDiff();
- if (paragraphs.length) {
- // Put the changed lines into the info column
- var p = paragraphs[0];
- title += ' (' + gettextCatalog.getString('Line') + ' ';
- if (p.diffLineTo === p.diffLineFrom + 1) {
- title += p.diffLineFrom;
- } else {
- title += p.diffLineFrom + '-' + p.diffLineTo;
- }
- title += ')';
-
- // get the diff
- motionText = p.text;
- } else {
- motionText = gettextCatalog.getString('No changes at the text.');
- }
- } else { // 'normal' amendment
- motionText = motion.getText();
- }
- content.push({
- text: title,
- style: 'heading3',
- marginTop: 15,
- });
-
- // submitters
- var submitters = _.map(motion.submitters, function (submitter) {
- return submitter.user.get_full_name();
- }).join(', ');
- content.push({
- text: gettextCatalog.getString('Submitters') + ': ' + submitters,
- });
-
- // state
- content.push({
- text: gettextCatalog.getString('State') + ': ' + motion.getStateName(),
- });
-
- // recommendation
- var recommendations_by = Config.get('motions_recommendations_by').value;
- var recommendation = motion.getRecommendationName();
- if (recommendations_by && recommendation) {
- content.push({
- text: recommendations_by + ': ' + recommendation,
- });
- }
-
- return _.concat(content, converter.convertHTML(motionText, 'outside'));
- }));
- };
-
- var getBundleContent = function (bundle) {
- var leadMotion = bundle[0].getParentMotion();
- // title
- var title = leadMotion.identifier ? ' ' + leadMotion.identifier : '';
- title += ': ' + leadMotion.getTitle();
- title = PDFLayout.createTitle(gettextCatalog.getString('Amendments to motion') + title);
-
- var content = [title],
- foundAmendments = [];
-
- var headings = leadMotion.getTextHeadings().map(function(heading) {
- heading.amendments = [];
- return heading;
- });
- bundle.forEach(function(amendment) {
- var headingIdx = null;
- var changes = amendment.getAmendmentParagraphsByMode('diff');
- if (changes.length === 0) {
- return;
- }
- var amendmentLineNumber = changes[0].lineFrom;
- for (var i = 0; i < headings.length; i++) {
- if (headings[i].lineNumber <= amendmentLineNumber) {
- headingIdx = i;
- }
- }
- if (headingIdx !== null) {
- headings[headingIdx].amendments.push(amendment);
- foundAmendments.push(amendment.id);
- }
- });
-
- headings.forEach(function(heading) {
- if (heading.amendments.length === 0) {
- return;
- }
- content.push({
- text: heading.text,
- style: "heading2",
- marginTop: 25,
- });
- content = _.concat(content, createBundleContent(heading.amendments));
- });
-
- // If there was an amendment that did not have a heading, we append it at the bottom
- var missedAmendments = [];
- bundle.forEach(function(amendment) {
- if (foundAmendments.indexOf(amendment.id) === -1) {
- missedAmendments.push(amendment);
- }
- });
- if (missedAmendments.length > 0) {
- content = _.concat(content, createBundleContent(missedAmendments));
- }
-
- return content;
- };
-
- // Generates content as a pdfmake consumable
- var getContent = function() {
- if (motions.length === 0) {
- return [];
- }
-
- // Creates bundles of motions. All motions with the same parent are bundled together
- // respecting the order, in which they are sorted.
- // motionBundles is an array containing Arrays of motions with the same parent.
- var parentId = motions[0].parent_id;
- var motionBundles = [];
- var currentBundle = [];
- _.forEach(motions, function (motion) {
- if (motion.parent_id === parentId) {
- currentBundle.push(motion);
- } else {
- motionBundles.push(currentBundle);
- currentBundle = [motion];
- parentId = motion.parent_id;
- }
- });
- motionBundles.push(currentBundle);
-
- // Make the amendment table for each motion bundle.
- return _.map(motionBundles, function (bundle, index) {
- var content = getBundleContent(bundle);
- if (index < motionBundles.length - 1) {
- content.push(PDFLayout.addPageBreak());
- }
- return content;
- });
- };
-
- var getImageMap = function() {
- return imageMap;
- };
-
- return $q(function (resolve) {
- ImageConverter.toBase64(getImageSources()).then(function (_imageMap) {
- imageMap = _imageMap;
- converter = PdfMakeConverter.createInstance(_imageMap);
- resolve({
- getContent: getContent,
- getImageMap: getImageMap,
- });
- });
- });
- };
-
- return {
- createInstance: createInstance,
- };
- }
-])
-
-.factory('MotionPdfExport', [
- '$http',
- '$q',
- 'operator',
- 'Config',
- 'gettextCatalog',
- 'MotionChangeRecommendation',
- 'HTMLValidizer',
- 'PdfMakeConverter',
- 'MotionContentProvider',
- 'MotionCatalogContentProvider',
- 'PdfMakeDocumentProvider',
- 'PollContentProvider',
- 'PdfMakeBallotPaperProvider',
- 'MotionPartialContentProvider',
- 'AmendmentContentProvider',
- 'PdfCreate',
- 'PDFLayout',
- 'PersonalNoteManager',
- 'MotionComment',
- 'Messaging',
- 'FileSaver',
- function ($http, $q, operator, Config, gettextCatalog, MotionChangeRecommendation, HTMLValidizer,
- PdfMakeConverter, MotionContentProvider, MotionCatalogContentProvider, PdfMakeDocumentProvider,
- PollContentProvider, PdfMakeBallotPaperProvider, MotionPartialContentProvider, AmendmentContentProvider,
- PdfCreate, PDFLayout, PersonalNoteManager, MotionComment, Messaging, FileSaver) {
- return {
- getDocumentProvider: function (motions, params, singleMotion) {
- params = _.clone(params || {}); // Clone this to avoid sideeffects.
-
- if (singleMotion) {
- _.defaults(params, {
- version: motions.active_version,
- });
- motions = [motions];
- }
-
- //save the arrays of all motions to an array
- angular.forEach(motions, function (motion) {
- if (singleMotion) {
- motion.changeRecommendations = MotionChangeRecommendation.filter({
- 'where': {'motion_version_id': {'==': params.version}}
- });
- } else {
- motion.changeRecommendations = MotionChangeRecommendation.filter({
- 'where': {'motion_version_id': {'==': motion.active_version}}
- });
- }
- });
-
- var motionContentProviderArray = [];
- var motionContentProviderPromises = _.map(motions, function (motion) {
- var version = (singleMotion ? params.version : motion.active_version);
- return $q(function (resolve, reject) {
- MotionContentProvider.createInstance(
- motion, version, params
- ).then(function (contentProvider) {
- motionContentProviderArray.push(contentProvider);
- resolve();
- }, reject);
- });
- });
-
- return $q(function (resolve, reject) {
- $q.all(motionContentProviderPromises).then(function() {
- var documentProviderPromise;
- if (singleMotion) {
- documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionContentProviderArray[0]);
- } else {
- var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray, params.column);
- documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider);
- }
- documentProviderPromise.then(function (documentProvider) {
- resolve(documentProvider);
- }, reject);
- }, reject);
- });
- },
- export: function (motions, params, singleMotion) {
- params = params || {};
- params.filename = gettextCatalog.getString('motions') + '.pdf';
- this.getDocumentProvider(motions, params, singleMotion).then(
- function (documentProvider) {
- PdfCreate.download(documentProvider, params.filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- }
- );
- },
- exportZip: function (motions, params) {
- var messageId = Messaging.addMessage('
' +
- gettextCatalog.getString('Generating PDFs and ZIP archive') + ' ...', 'info');
- var zipFilename = params.filename || gettextCatalog.getString('motions') + '.zip';
- params.filename = void 0; // clear this, so we do not override the default filenames for each pdf.
-
- var self = this;
- var usedFilenames = [];
- var docMap = {};
- var docPromises = _.map(motions, function (motion) {
- var identifier = motion.identifier ? '-' + motion.identifier : '';
- var filename = gettextCatalog.getString('Motion') + identifier;
-
- // If the filename is already in use, try to append a number to it (like '(2)')
- if (_.includes(usedFilenames, filename)) {
- var i = 1;
- var filenameWithNumber = filename;
- while(_.includes(usedFilenames, filenameWithNumber)) {
- filenameWithNumber = filename + ' (' + i + ')';
- i++;
- }
- filename = filenameWithNumber;
- }
- usedFilenames.push(filename);
- filename += '.pdf';
-
- return $q(function (resolve, reject) {
- // get documentProvider for every motion.
- self.getDocumentProvider(motion, params, true).then(function (documentProvider) {
- docMap[filename] = documentProvider;
- resolve();
- }, reject);
- });
- });
- $q.all(docPromises).then(function () {
- PdfCreate.getBase64FromMultipleDocuments(docMap).then(function (pdfMap) {
- var zip = new JSZip();
- _.forEach(pdfMap, function (data, filename) {
- zip.file(filename, data, {base64: true});
- });
- Messaging.createOrEditMessage(messageId, '
' +
- gettextCatalog.getString('ZIP successfully generated.'), 'success', {timeout: 3000});
- zip.generateAsync({type: 'blob'}).then(function (content) {
- FileSaver.saveAs(content, zipFilename);
- });
- }, function (error) {
- Messaging.createOrEditMessage(messageId, '
' + gettextCatalog.getString('Error while generating ZIP file') +
- ':
' + error + '
', 'error');
- });
- }, function (error) {
- Messaging.createOrEditMessage(messageId, error.msg, 'error');
- });
- },
- createPollPdf: function (motion, version) {
- var id = motion.identifier.replace(' ', '');
- var title = motion.getTitle(version);
- var filename = gettextCatalog.getString('Motion') + '-' + id + '-' + gettextCatalog.getString('ballot-paper') + '.pdf';
- PollContentProvider.createInstance(title, id).then(function (pollContentProvider) {
- var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider);
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- },
- exportPersonalNote: function (motion, filename) {
- var personalNote = PersonalNoteManager.getNote(motion);
- var content = [{
- heading: gettextCatalog.getString('Personal note'),
- text: personalNote ? personalNote.note : '',
- }];
- MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) {
- PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- },
- exportComment: function (motion, commentId, filename) {
- var field = MotionComment.getNoSpecialCommentsFields()[commentId];
- if (field && motion.comments[commentId]) {
- var title = field.name;
- if (!field.public) {
- title += ' (' + gettextCatalog.getString('internal') + ')';
- }
- var content = [{
- heading: title,
- text: motion.comments[commentId],
- }];
- MotionPartialContentProvider.createInstance(motion, content).then(function (contentProvider) {
- PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- });
- }
- },
- exportAmendments: function (motions, filename) {
- AmendmentContentProvider.createInstance(motions).then(function (contentProvider) {
- PdfMakeDocumentProvider.createInstance(contentProvider).then(function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- });
- });
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/projector.js b/openslides/motions/static/js/motions/projector.js
deleted file mode 100644
index f4af95f03..000000000
--- a/openslides/motions/static/js/motions/projector.js
+++ /dev/null
@@ -1,98 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.projector', [
- 'OpenSlidesApp.motions',
- 'OpenSlidesApp.motions.motionservices',
- 'OpenSlidesApp.motions.motionBlockProjector',
-])
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('motions/motion', {
- template: 'static/templates/motions/slide_motion.html',
- });
- }
-])
-
-.controller('SlideMotionCtrl', [
- '$scope',
- '$timeout',
- 'Config',
- 'Motion',
- 'MotionChangeRecommendation',
- 'ChangeRecommendationView',
- 'User',
- 'Notify',
- 'ProjectorID',
- 'MotionPollDecimalPlaces',
- function($scope, $timeout, Config, Motion, MotionChangeRecommendation,
- ChangeRecommendationView, User, Notify, ProjectorID, MotionPollDecimalPlaces) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var motionId = $scope.element.id;
- $scope.mode = $scope.element.mode || 'original';
- $scope.lineNumberMode = Config.get('motions_default_line_numbering').value;
-
- var notifyNamePrefix = 'projector_' + ProjectorID() + '_motion_line_';
- var callbackId = Notify.registerCallback(notifyNamePrefix + 'request', function (params) {
- var line = params.params.line;
- if (!line) {
- return;
- }
- $scope.highlight = line;
- $timeout(function () {
- $scope.highlight = 0;
- }, 4000);
-
- var scrollTop = null;
- $('.line-number-' + line).each(function() {
- var top = $(this).offset().top;
- if (scrollTop === null || top < scrollTop) {
- scrollTop = top;
- }
- });
- if (scrollTop) {
- scrollTop += (-$scope.scroll); // Add the (reversed) scrolling ontop
- var scroll = Math.floor((scrollTop/250) - 0.2);
- var channel = params.senderReplyChannelName;
- Notify.notify(notifyNamePrefix + 'answer', {scroll: scroll}, null, [channel], null);
- }
- });
- $scope.$on('$destroy', function () {
- Notify.deregisterCallback(callbackId);
- });
-
- User.bindAll({}, $scope, 'users');
-
- $scope.$watch(function () {
- return Motion.lastModified(motionId);
- }, function () {
- $scope.motion = Motion.get(motionId);
- $scope.amendment_diff_paragraphs = $scope.motion.getAmendmentParagraphsLinesDiff();
- $scope.viewChangeRecommendations.setVersion($scope.motion, $scope.motion.active_version);
- _.forEach($scope.motion.polls, function (poll) {
- MotionPollDecimalPlaces.getPlaces(poll, true).then(function (decimalPlaces) {
- precisionCache[poll.id] = decimalPlaces;
- });
- });
- });
-
- var precisionCache = {};
- $scope.getPollVotesPrecision = function (poll) {
- if (!precisionCache[poll.id]) {
- return 0;
- }
- return precisionCache[poll.id];
- };
-
- // Change recommendation viewing
- $scope.viewChangeRecommendations = ChangeRecommendationView;
- $scope.viewChangeRecommendations.initProjector($scope, Motion.get(motionId), $scope.mode);
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/site.js b/openslides/motions/static/js/motions/site.js
deleted file mode 100644
index de91f8bcf..000000000
--- a/openslides/motions/static/js/motions/site.js
+++ /dev/null
@@ -1,3326 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.site', [
- 'OpenSlidesApp.motions',
- 'OpenSlidesApp.motions.motionservices',
- 'OpenSlidesApp.poll.majority',
- 'OpenSlidesApp.core.pdf',
- 'OpenSlidesApp.motions.docx',
- 'OpenSlidesApp.motions.pdf',
- 'OpenSlidesApp.motions.csv',
- 'OpenSlidesApp.motions.workflow',
-])
-
-.config([
- 'mainMenuProvider',
- 'gettext',
- function (mainMenuProvider, gettext) {
- mainMenuProvider.register({
- 'ui_sref': 'motions.motion.list',
- 'img_class': 'file-text',
- 'title': gettext('Motions'),
- 'weight': 300,
- 'perm': 'motions.can_see',
- });
- }
-])
-
-.config([
- 'SearchProvider',
- 'gettext',
- function (SearchProvider, gettext) {
- SearchProvider.register({
- 'verboseName': gettext('Motions'),
- 'collectionName': 'motions/motion',
- 'urlDetailState': 'motions.motion.detail',
- 'weight': 300,
- });
- }
-])
-
-.config([
- '$stateProvider',
- 'gettext',
- function($stateProvider, gettext) {
- $stateProvider
- .state('motions', {
- url: '/motions',
- abstract: true,
- template: "
",
- data: {
- title: gettext('Motions'),
- basePerm: 'motions.can_see',
- },
- })
- .state('motions.motion', {
- abstract: true,
- template: "
",
- })
- .state('motions.motion.list', {})
- .state('motions.motion.detail', {
- resolve: {
- motionId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- // redirects to motion detail and opens motion edit form dialog, uses edit url,
- // used by ui-sref links from agenda only
- // (from motion controller use MotionForm factory instead to open dialog in front of
- // current view without redirect)
- .state('motions.motion.detail.update', {
- onEnter: ['$stateParams', '$state', 'ngDialog', 'Motion',
- function($stateParams, $state, ngDialog, Motion) {
- ngDialog.open({
- template: 'static/templates/motions/motion-form.html',
- controller: 'MotionUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionId: function () {return $stateParams.id;},
- },
- preCloseCallback: function () {
- $state.go('motions.motion.detail', {motion: $stateParams.id});
- return true;
- }
- });
- }
- ]
- })
- .state('motions.motion.submitters', {
- url: '/submitters/{id:int}',
- controller: 'MotionSubmitterCtrl',
- resolve: {
- motionId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- },
- data: {
- title: gettext('Submitters'),
- basePerm: 'motions.can_manage',
- },
- })
- .state('motions.motion.amendment-list', {
- url: '/{id:int}/amendments',
- controller: 'MotionAmendmentListStateCtrl',
- params: {
- motionId: null,
- },
- resolve: {
- motionId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- .state('motions.motion.allamendments', {
- url: '/amendments',
- templateUrl: 'static/templates/motions/motion-amendment-list.html',
- controller: 'MotionAmendmentListStateCtrl',
- resolve: {
- motionId: function() { return void 0; },
- }
- })
- .state('motions.motion.import', {
- url: '/import',
- controller: 'MotionImportCtrl',
- })
- // categories
- .state('motions.category', {
- url: '/category',
- abstract: true,
- template: "
",
- data: {
- title: gettext('Categories'),
- },
- })
- .state('motions.category.list', {})
- .state('motions.category.sort', {
- url: '/sort/{id}',
- controller: 'CategorySortCtrl',
- templateUrl: 'static/templates/motions/category-sort.html',
- resolve: {
- categoryId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- },
- })
- // MotionBlock
- .state('motions.motionBlock', {
- url: '/blocks',
- abstract: true,
- template: '
',
- data: {
- title: gettext('Motion blocks'),
- },
- })
- .state('motions.motionBlock.list', {})
- .state('motions.motionBlock.detail', {
- resolve: {
- motionBlockId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- // redirects to motionBlock detail and opens motionBlock edit form dialog, uses edit url,
- // used by ui-sref links from agenda only
- // (from motionBlock controller use MotionBlockForm factory instead to open dialog in front
- // of current view without redirect)
- .state('motions.motionBlock.detail.update', {
- onEnter: ['$stateParams', '$state', 'ngDialog',
- function($stateParams, $state, ngDialog) {
- ngDialog.open({
- template: 'static/templates/motions/motion-block-form.html',
- controller: 'MotionBlockUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionBlockId: function () {
- return $stateParams.id;
- }
- },
- preCloseCallback: function() {
- $state.go('motions.motionBlock.detail', {motionBlock: $stateParams.id});
- return true;
- }
- });
- }
- ],
- })
- // Workflows and states
- .state('motions.workflow', {
- url: '/workflow',
- abstract: true,
- template: '
',
- data: {
- title: gettext('Workflows'),
- basePerm: 'motions.can_manage',
- },
- })
- .state('motions.workflow.list', {})
- .state('motions.workflow.detail', {
- resolve: {
- workflowId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- });
- }
-])
-
-.factory('ChangeRecommendationTitleForm', [
- 'gettextCatalog',
- 'Editor',
- 'Config',
- function(gettextCatalog) {
- return {
- // ngDialog for motion form
- getCreateDialog: function (motion, version) {
- return {
- template: 'static/templates/motions/change-recommendation-form.html',
- controller: 'ChangeRecommendationTitleCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motion: function() {
- return motion;
- },
- version: function() {
- return version;
- }
- }
- };
- },
- getEditDialog: function(change) {
- return {
- template: 'static/templates/motions/change-recommendation-form.html',
- controller: 'ChangeRecommendationTitleUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- change: function() {
- return change;
- }
- }
- };
- },
- // angular-formly fields for motion form
- getFormFields: function () {
- return [
- {
- key: 'identifier',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Identifier')
- },
- hide: true
- },
- {
- key: 'motion_version_id',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Motion')
- },
- hide: true
- },
- {
- key: 'text',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('New title'),
- required: false
- }
- }
- ];
- }
- };
- }
-])
-
-.factory('ChangeRecommendationTextForm', [
- 'gettextCatalog',
- 'Editor',
- 'Config',
- function(gettextCatalog, Editor) {
- return {
- // ngDialog for motion form
- getCreateDialog: function (motion, version, lineFrom, lineTo) {
- return {
- template: 'static/templates/motions/change-recommendation-form.html',
- controller: 'ChangeRecommendationTextCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motion: function() {
- return motion;
- },
- version: function() {
- return version;
- },
- lineFrom: function() {
- return lineFrom;
- },
- lineTo: function() {
- return lineTo;
- }
- }
- };
- },
- getEditDialog: function(change) {
- return {
- template: 'static/templates/motions/change-recommendation-form.html',
- controller: 'ChangeRecommendationTextUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- change: function() {
- return change;
- }
- }
- };
- },
- // angular-formly fields for motion form
- getFormFields: function (line_from, line_to) {
- return [
- {
- key: 'identifier',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Identifier')
- },
- hide: true
- },
- {
- key: 'motion_version_id',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Motion')
- },
- hide: true
- },
- {
- key: 'line_from',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('From Line')
- },
- hide: true
- },
- {
- key: 'line_to',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('To Line')
- },
- hide: true
- },
- {
- key: 'type',
- type: 'radio-buttons',
- templateOptions: {
- label: 'Type',
- options: [
- {name: gettextCatalog.getString('Replacement'), value: 0},
- {name: gettextCatalog.getString('Insertion'), value: 1},
- {name: gettextCatalog.getString('Deletion'), value: 2},
- {name: gettextCatalog.getString('Other'), value: 3},
- ]
- }
- },
- {
- key: 'other_description',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Description'),
- },
- hideExpression: "model.type !== 3",
- },
- {
- key: 'text',
- type: 'editor',
- templateOptions: {
- label: (
- line_from == line_to - 1 ?
- gettextCatalog.getString('Text in line %from%').replace(/%from%/, line_from) :
- gettextCatalog.getString('Text from line %from% to %to%')
- .replace(/%from%/, line_from).replace(/%to%/, line_to - 1)
- ),
- required: false
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- }
- }
- ];
- }
- };
- }
-])
-
-// Service for choosing the paragraph of a given motion that is to be amended
-.factory('AmendmentParagraphChooseForm', [
- function () {
- return {
- // ngDialog for motion form
- getDialog: function (motion, successCb) {
- return {
- template: 'static/templates/motions/amendment-paragraph-choose-form.html',
- controller: 'AmendmentParagraphChooseCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motion: function () { return motion; },
- successCb: function() { return successCb; },
- }
- };
- }
- };
- }
-])
-
-// Service for generic motion form (create and update)
-.factory('MotionForm', [
- '$filter',
- 'gettextCatalog',
- 'operator',
- 'Editor',
- 'MotionComment',
- 'Category',
- 'Config',
- 'Mediafile',
- 'MotionBlock',
- 'Tag',
- 'User',
- 'Workflow',
- 'Agenda',
- 'AgendaTree',
- 'ShowAsAgendaItemField',
- function ($filter, gettextCatalog, operator, Editor, MotionComment, Category, Config,
- Mediafile, MotionBlock, Tag, User, Workflow, Agenda, AgendaTree, ShowAsAgendaItemField) {
- return {
- // ngDialog for motion form
- // If motion is given and not null, we're editing an already existing motion
- // If parentMotion is give, we're dealing with an amendment
- // If paragraphNo is given as well, the amendment is paragraph-based
- // If paragraphTextPre is given, we're creating a modified version of another paragraph-based amendment
- getDialog: function (motion, parentMotion, paragraphNo, paragraphTextPre) {
- return {
- template: 'static/templates/motions/motion-form.html',
- controller: motion ? 'MotionUpdateCtrl' : 'MotionCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionId: function () {return motion ? motion.id : void 0;},
- parentMotion: function () {return parentMotion;},
- paragraphNo: function () {return paragraphNo;},
- paragraphTextPre: function () {return paragraphTextPre;}
- }
- };
- },
- // angular-formly fields for motion form
- getFormFields: function (isCreateForm, isParagraphBasedAmendment) {
- if (!isParagraphBasedAmendment) { // catch null and undefined. Angular formy doesn't like this.
- isParagraphBasedAmendment = false;
- }
-
- var workflows = Workflow.getAll();
- var images = Mediafile.getAllImages();
- var formFields = [];
- formFields.push({
- key: 'identifier',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Identifier')
- },
- hide: true
- });
-
- if (isCreateForm) {
- formFields.push({
- key: 'submitters_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Submitters'),
- options: User.getAll(),
- ngOptions: 'option.id as option.full_name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a submitter ...'),
- },
- hide: !operator.hasPerms('motions.can_manage')
- });
- }
-
- formFields = formFields.concat([
- {
- key: 'title',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Title'),
- required: true
- },
- hide: isParagraphBasedAmendment && isCreateForm
- },
- {
- template: '
' + Config.translate(Config.get('motions_preamble').value) + '
'
- },
- {
- key: 'text',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('Text'),
- required: !isParagraphBasedAmendment // Deleting the whole paragraph in an amendment should be possible
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- }
- },
- {
- key: 'reason',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('Reason'),
- },
- data: {
- ckeditorOptions: Editor.getOptions()
- }
- },
- {
- key: 'disable_versioning',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Trivial change'),
- description: gettextCatalog.getString("Don't create a new version.")
- },
- hide: true
- }
- ]);
-
- // show as agenda item + parent item
- if (isCreateForm) {
- formFields.push(ShowAsAgendaItemField('motions.can_manage'));
- formFields.push({
- key: 'agenda_parent_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Parent item'),
- options: AgendaTree.getFlatTree(Agenda.getAll()),
- ngOptions: 'item.id as item.getListViewTitle() for item in to.options | notself : model.agenda_item_id',
- placeholder: gettextCatalog.getString('Select a parent item ...')
- },
- hide: !operator.hasPerms('agenda.can_manage')
- });
- }
-
- // motion comments
- formFields = formFields.concat(MotionComment.getFormFields());
-
- // more
- formFields.push(
- {
- key: 'more',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Show extended fields')
- },
- hide: !operator.hasPerms('motions.can_manage')
- },
- {
- template: '
',
- hideExpression: '!model.more'
- }
- );
- // attachments
- if (Mediafile.getAll().length > 0) {
- formFields.push({
- key: 'attachments_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Attachment'),
- options: $filter('orderBy')(Mediafile.getAll(), 'title_or_filename'),
- ngOptions: 'option.id as option.title_or_filename for option in to.options',
- placeholder: gettextCatalog.getString('Select or search an attachment ...')
- },
- hideExpression: '!model.more'
- });
- }
- // category
- if (Category.getAll().length > 0) {
- formFields.push({
- key: 'category_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Category'),
- options: Category.getAll(),
- ngOptions: 'option.id as option.name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a category ...')
- },
- hideExpression: '!model.more'
- });
- }
- // motion block
- if (MotionBlock.getAll().length > 0) {
- formFields.push({
- key: 'motion_block_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Motion block'),
- options: MotionBlock.getAll(),
- ngOptions: 'option.id as option.title for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a motion block ...')
- },
- hideExpression: '!model.more'
- });
- }
- // origin
- formFields.push({
- key: 'origin',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Origin'),
- },
- hideExpression: '!model.more'
- });
- // tags
- if (Tag.getAll().length > 0) {
- formFields.push({
- key: 'tags_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Tags'),
- options: Tag.getAll(),
- ngOptions: 'option.id as option.name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a tag ...')
- },
- hideExpression: '!model.more'
- });
- }
- // supporters
- if (Config.get('motions_min_supporters').value > 0) {
- formFields.push({
- key: 'supporters_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Supporters'),
- options: User.getAll(),
- ngOptions: 'option.id as option.full_name for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a supporter ...')
- },
- hideExpression: '!model.more'
- });
- }
- // workflows
- if (workflows.length > 1) {
- formFields.push({
- key: 'workflow_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Workflow'),
- optionsAttr: 'bs-options',
- options: workflows,
- ngOptions: 'option.id as option.name | translate for option in to.options',
- placeholder: gettextCatalog.getString('Select or search a workflow ...')
- },
- hideExpression: '!model.more',
- });
- }
-
- return formFields;
- }
- };
- }
-])
-
-.factory('MotionCommentForm', [
- 'MotionComment',
- function (MotionComment) {
- return {
- // ngDialog for motion comment form
- getDialog: function (motion, commentFieldId) {
- return {
- template: 'static/templates/motions/motion-comment-form.html',
- controller: 'MotionCommentCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionId: function () {return motion.id;},
- commentFieldId: function () {return commentFieldId;},
- },
- };
- },
- // angular-formly fields for motion comment form
- getFormFields: function (commentFieldId) {
- return [
- MotionComment.getFormField(commentFieldId)
- ];
- },
- };
- }
-])
-
-.factory('CategoryForm', [
- 'gettextCatalog',
- function (gettextCatalog) {
- return {
- getDialog: function (category) {
- return {
- template: 'static/templates/motions/category-form.html',
- controller: category ? 'CategoryUpdateCtrl' : 'CategoryCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- categoryId: function () {return category ? category.id : void 0;},
- },
- };
-
- },
- getFormFields: function () {
- return [
- {
- key: 'prefix',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Prefix')
- },
- },
- {
- key: 'name',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Name')
- },
- }
- ];
- },
- };
- }
-])
-
-// Provide generic motionpoll form fields for poll update view
-.factory('MotionPollForm', [
- 'gettextCatalog',
- function (gettextCatalog) {
- return {
- getFormFields: function (precision) {
- var step = Math.pow(10, -precision);
- return [
- {
- key: 'yes',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Yes'),
- type: 'number',
- step: step,
- required: true
- }
- },
- {
- key: 'no',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('No'),
- type: 'number',
- step: step,
- required: true
- }
- },
- {
- key: 'abstain',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Abstain'),
- type: 'number',
- step: step,
- required: true
- }
- },
- {
- key: 'votesvalid',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Valid votes'),
- step: step,
- type: 'number'
- }
- },
- {
- key: 'votesinvalid',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Invalid votes'),
- step: step,
- type: 'number'
- }
- },
- {
- key: 'votescast',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Votes cast'),
- step: step,
- type: 'number'
- }
- }];
- }
- };
- }
-])
-
-.factory('MotionExportForm', [
- 'operator',
- 'gettextCatalog',
- 'Config',
- 'MotionComment',
- function (operator, gettextCatalog, Config, MotionComment) {
- var noSpecialCommentsFields = MotionComment.getNoSpecialCommentsFields();
- return {
- getDialog: function (motions, params, singleMotion) {
- return {
- template: 'static/templates/motions/motion-export-form.html',
- controller: 'MotionExportCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motions: function () {return motions;},
- params: function () {return params;},
- singleMotion: function () {return singleMotion;},
- },
- };
- },
- getFormFields: function (singleMotion, motions, formatChangeCallback) {
- var fields = [];
- var commentsAvailable = _.keys(noSpecialCommentsFields).length !== 0;
- var someMotionsHaveAmendments = _.some(motions, function (motion) {
- return motion.hasAmendments();
- });
- // if amendments amendments are already included. We owudl have them twice, if the option is enabled.
- if (Config.get('motions_amendments_main_table').value) {
- someMotionsHaveAmendments = false;
- }
- var getMetaInformationOptions = function (disabled) {
- if (!disabled) {
- disabled = {};
- }
- var options = [
- {name: gettextCatalog.getString('Submitters'), id: 'submitters', disabled: disabled.submitters},
- {name: gettextCatalog.getString('State'), id: 'state', disabled: disabled.state},
- ];
- if (Config.get('motions_recommendations_by').value) {
- options.push({
- name: gettextCatalog.getString('Recommendation'),
- id: 'recommendation',
- disabled: disabled.recommendation
- });
- }
- if (_.some(motions, function (motion) { return motion.category; })) {
- options.push({
- name: gettextCatalog.getString('Category'),
- id: 'category',
- disabled: disabled.category,
- });
- }
- if (_.some(motions, function (motion) { return motion.motionBlock; })) {
- options.push({
- name: gettextCatalog.getString('Motion block'),
- id: 'motionBlock',
- disabled: disabled.motionBlock,
- });
- }
- if (_.some(motions, function (motion) { return motion.origin; })) {
- options.push({
- name: gettextCatalog.getString('Origin'),
- id: 'origin',
- disabled: disabled.origin,
- });
- }
- options.push({
- name: gettextCatalog.getString('Voting result'),
- id: 'votingresult',
- disabled: disabled.votingResult
- });
- return options;
- };
- if (!singleMotion) {
- fields = [
- {
- key: 'format',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Format'),
- options: [
- {name: 'PDF', value: 'pdf'},
- {name: 'CSV', value: 'csv'},
- {name: 'DOCX', value: 'docx'},
- ],
- change: formatChangeCallback,
- },
- }
- ];
- }
- if (someMotionsHaveAmendments) {
- fields.push({
- key: 'amendments',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Amendments'),
- options: [
- {name: gettextCatalog.getString('Include'), value: true},
- {name: gettextCatalog.getString('Exclude'), value: false},
- ],
- },
- });
- }
- if (operator.hasPerms('motions.can_manage')) {
- fields.push.apply(fields, [
- {
- key: 'lineNumberMode',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Line numbering'),
- options: [
- {name: gettextCatalog.getString('None'), value: 'none'},
- {name: gettextCatalog.getString('inline'), value: 'inline'},
- {name: gettextCatalog.getString('outside'), value: 'outside'},
- ],
- },
- hideExpression: "model.format !== 'pdf'",
- },
- {
- key: 'lineNumberMode',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Line numbering'),
- options: [
- {name: gettextCatalog.getString('None'), value: 'none'},
- {name: gettextCatalog.getString('inline'), value: 'inline', disabled: true},
- {name: gettextCatalog.getString('outside'), value: 'outside', disabled: true},
- ],
- },
- hideExpression: "model.format === 'pdf'",
- },
- {
- key: 'changeRecommendationMode',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Change recommendations'),
- options: [
- {name: gettextCatalog.getString('Original version'), value: 'original'},
- {name: gettextCatalog.getString('Changed version'), value: 'changed'},
- {name: gettextCatalog.getString('Diff version'), value: 'diff'},
- {name: gettextCatalog.getString('Final version'), value: 'modified_agreed'},
- ],
- },
- hideExpression: "model.format !== 'pdf'",
- },
- {
- key: 'changeRecommendationMode',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Change recommendations'),
- options: [
- {name: gettextCatalog.getString('Original version'), value: 'original'},
- {name: gettextCatalog.getString('Changed version'), value: 'changed'},
- {name: gettextCatalog.getString('Diff version'), value: 'diff', disabled: true},
- {name: gettextCatalog.getString('Final version'), value: 'modified_agreed'},
- ],
- },
- hideExpression: "model.format === 'pdf'",
- },
- {
- key: 'include',
- type: 'checkbox-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Content'),
- options: [
- {name: gettextCatalog.getString('Text'), id: 'text'},
- {name: gettextCatalog.getString('Reason'), id: 'reason'},
- ],
- },
- },
- {
- key: 'include',
- type: 'checkbox-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Meta information'),
- options: getMetaInformationOptions(),
- },
- hideExpression: "model.format !== 'pdf'",
- },
- {
- key: 'include',
- type: 'checkbox-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Meta information'),
- options: getMetaInformationOptions({votingResult: true}),
- },
- hideExpression: "model.format !== 'csv'",
- },
- ]);
- if (commentsAvailable) {
- fields.push({
- key: 'includeComments',
- type: 'checkbox-buttons',
- templateOptions: {
- label: gettextCatalog.getString('Comments'),
- options: _.map(noSpecialCommentsFields, function (field, id) {
- return {
- name: gettextCatalog.getString(field.name),
- id: id,
- };
- }),
- },
- hideExpression: "model.format === 'csv'",
- });
- }
- }
- if (!singleMotion) {
- fields.push({
- key: 'pdfFormat',
- type: 'radio-buttons',
- templateOptions: {
- label: gettextCatalog.getString('PDF format'),
- options: [
- {name: gettextCatalog.getString('One PDF'), value: 'pdf'},
- {name: gettextCatalog.getString('Multiple PDFs in a zip arcive'), value: 'zip'},
- ],
- },
- hideExpression: "model.format !== 'pdf'",
- });
- }
- return fields;
- },
- };
- }
-])
-
-.controller('MotionExportCtrl', [
- '$scope',
- 'Config',
- 'MotionExportForm',
- 'MotionPdfExport',
- 'MotionCsvExport',
- 'MotionDocxExport',
- 'motions',
- 'params',
- 'singleMotion',
- function ($scope, Config, MotionExportForm, MotionPdfExport, MotionCsvExport,
- MotionDocxExport, motions, params, singleMotion) {
- $scope.formFields = MotionExportForm.getFormFields(singleMotion, motions, function () {
- if ($scope.params.format !== 'pdf') {
- $scope.params.changeRecommendationMode = 'original';
- $scope.params.lineNumberMode = 'none';
- $scope.params.include.votingresult = false;
- }
- if ($scope.params.format === 'docx') {
- $scope.params.include.state = false;
- $scope.params.include.submitter = true;
- $scope.params.include.motionBlock = false;
- $scope.params.include.origin = false;
- $scope.params.include.recommendation = false;
- } else {
- $scope.params.include.state = true;
- $scope.params.include.motionBlock = true;
- $scope.params.include.origin = true;
- $scope.params.include.recommendation = true;
- }
- if ($scope.params.format === 'pdf') {
- $scope.params.include.state = true;
- $scope.params.include.votingresult = true;
- }
- });
- $scope.params = params || {};
- _.defaults($scope.params, {
- format: 'pdf',
- pdfFormat: 'pdf',
- changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
- lineNumberMode: Config.get('motions_default_line_numbering').value,
- amendments: false,
- include: {
- text: true,
- reason: true,
- state: true,
- category: true,
- submitters: true,
- votingresult: true,
- motionBlock: true,
- origin: true,
- recommendation: true,
- },
- includeComments: {},
- });
- // Always change the mode from agreed to modified_agreed. If a motion does not have a modified
- // final version, the agreed will be taken.
- if ($scope.params.changeRecommendationMode === 'agreed') {
- $scope.params.changeRecommendationMode = 'modified_agreed';
- }
- $scope.motions = motions;
- $scope.singleMotion = singleMotion;
-
- // Add amendments to motions. The amendments are sorted by their identifier
- var prepareAmendments = function (motions) {
- var allMotions = [];
- _.forEach(motions, function (motion) {
- allMotions.push(motion);
- allMotions = allMotions.concat(
- _.sortBy(motion.getAmendments(), function (amendment) {
- return amendment.identifier;
- })
- );
- });
- return allMotions;
- };
-
- $scope.export = function () {
- if ($scope.params.amendments) {
- motions = prepareAmendments(motions);
- }
- switch ($scope.params.format) {
- case 'pdf':
- if ($scope.params.pdfFormat === 'pdf') {
- MotionPdfExport.export(motions, $scope.params, singleMotion);
- } else {
- MotionPdfExport.exportZip(motions, $scope.params);
- }
- break;
- case 'csv':
- MotionCsvExport.export(motions, $scope.params);
- break;
- case 'docx':
- MotionDocxExport.export(motions, $scope.params);
- break;
- }
- $scope.closeThisDialog();
- };
- }
-])
-
-// Cache for MotionPollDetailCtrl so that users choices are keeped during user actions (e. g. save poll form).
-.value('MotionPollDetailCtrlCache', {})
-
-// Child controller of MotionDetailCtrl for each single poll.
-.controller('MotionPollDetailCtrl', [
- '$scope',
- 'MajorityMethodChoices',
- 'Config',
- 'MotionPollDetailCtrlCache',
- 'MotionPollDecimalPlaces',
- function ($scope, MajorityMethodChoices, Config, MotionPollDetailCtrlCache, MotionPollDecimalPlaces) {
- // Define choices.
- $scope.methodChoices = MajorityMethodChoices;
- // TODO: Get $scope.baseChoices from config_variables.py without copying them.
-
- $scope.votesPrecision = MotionPollDecimalPlaces.getPlaces($scope.poll);
-
- // Setup empty cache with default values.
- if (typeof MotionPollDetailCtrlCache[$scope.poll.id] === 'undefined') {
- MotionPollDetailCtrlCache[$scope.poll.id] = {
- method: $scope.config('motions_poll_default_majority_method'),
- };
- }
-
- // Fetch users choices from cache.
- $scope.method = MotionPollDetailCtrlCache[$scope.poll.id].method;
-
- // Define result function.
- $scope.isReached = function () {
- return $scope.poll.isReached($scope.method);
- };
-
- // Define template controll function
- $scope.hideMajorityCalculation = function () {
- return typeof $scope.isReached() === 'undefined' && $scope.method !== 'disabled';
- };
-
- // Save current values to cache on detroy of this controller.
- $scope.$on('$destroy', function() {
- MotionPollDetailCtrlCache[$scope.poll.id] = {
- method: $scope.method,
- };
- });
- }
-])
-
-.controller('MotionListCtrl', [
- '$scope',
- '$state',
- '$http',
- 'gettext',
- 'gettextCatalog',
- 'operator',
- 'ngDialog',
- 'MotionForm',
- 'Motion',
- 'MotionComment',
- 'Category',
- 'Config',
- 'Tag',
- 'Workflow',
- 'User',
- 'Agenda',
- 'MotionBlock',
- 'Projector',
- 'ProjectionDefault',
- 'osTableFilter',
- 'osTableSort',
- 'osTablePagination',
- 'MotionExportForm',
- 'MotionPdfExport',
- 'PersonalNoteManager',
- function($scope, $state, $http, gettext, gettextCatalog, operator, ngDialog, MotionForm, Motion,
- MotionComment, Category, Config, Tag, Workflow, User, Agenda, MotionBlock, Projector,
- ProjectionDefault, osTableFilter, osTableSort, osTablePagination, MotionExportForm,
- MotionPdfExport, PersonalNoteManager) {
- Category.bindAll({}, $scope, 'categories');
- MotionBlock.bindAll({}, $scope, 'motionBlocks');
- Tag.bindAll({}, $scope, 'tags');
- Workflow.bindAll({}, $scope, 'workflows');
- User.bindAll({}, $scope, 'users');
- Projector.bindAll({}, $scope, 'projectors');
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'motions'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.$watch(function () {
- return Motion.lastModified();
- }, function () {
- // get all main motions and order by identifier (after custom ordering)
- var motions;
- if (Config.get('motions_amendments_main_table').value) {
- motions = Motion.getAll();
- } else {
- motions = Motion.filter({parent_id: undefined});
- }
-
- $scope.motions = _.orderBy(motions, ['identifier']);
- _.forEach($scope.motions, function (motion) {
- MotionComment.populateFields(motion);
- motion.personalNote = PersonalNoteManager.getNote(motion);
- // For filtering, we cannot filter for .personalNote.star
- motion.star = motion.personalNote ? motion.personalNote.star : false;
- motion.hasPersonalNote = motion.personalNote ? !!motion.personalNote.note : false;
- if (motion.star === undefined) {
- motion.star = false;
- }
- });
- $scope.collectStatesAndRecommendations();
- });
- $scope.alert = {};
-
- // Motion comments
- $scope.noSpecialCommentsFields = MotionComment.getNoSpecialCommentsFields();
- $scope.showCommentsFilter = function () {
- return _.keys($scope.noSpecialCommentsFields).length > 0;
- };
-
- // collect all states and all recommendations of all workflows
- $scope.collectStatesAndRecommendations = function () {
- // Special case: If it is the first time updated, update the state filter.
- // This causes to set the done/undone states correct on page load.
- var doStateFilterUpdate = !$scope.states;
- $scope.states = [];
- $scope.recommendations = [];
- var workflows = $scope.collectAllUsedWorkflows();
- _.forEach(workflows, function (workflow) {
- if (workflows.length > 1) {
- var workflowHeader = {
- headername: workflow.name,
- workflowHeader: true,
- };
- $scope.states.push(workflowHeader);
- $scope.recommendations.push(workflowHeader);
- }
-
- var firstEndStateSeen = false;
- _.forEach(_.orderBy(workflow.states, 'id'), function (state) {
- if (state.next_states_id.length === 0 && !firstEndStateSeen) {
- $scope.states.push({divider: true});
- firstEndStateSeen = true;
- }
- $scope.states.push(state);
- if (state.recommendation_label) {
- $scope.recommendations.push(state);
- }
- });
- });
- if (doStateFilterUpdate) {
- updateStateFilter();
- }
- };
- $scope.collectAllUsedWorkflows = function () {
- return _.filter(Workflow.getAll(), function (workflow) {
- return _.some($scope.motions, function (motion) {
- return motion.state.workflow_id === workflow.id;
- });
- });
- };
-
- $scope.stateFilter = [];
- var updateStateFilter = function () {
- $scope.stateFilter = _.clone($scope.filter.multiselectFilters.state);
-
- var doneIndex = _.indexOf($scope.stateFilter, -1);
- if (doneIndex > -1) { // contains -1 (done)
- $scope.stateFilter.splice(doneIndex, 1); // remove -1
- _.forEach($scope.states, function (state) {
- if (!state.workflowHeader && !state.divider) {
- if (state.next_states_id.length === 0) { // add all done state
- $scope.stateFilter.push(state.id);
- }
- }
- });
- }
-
- var undoneIndex = _.indexOf($scope.stateFilter, -2);
- if (undoneIndex > -1) { // contains -2 (undone)
- $scope.stateFilter.splice(undoneIndex, 1); // remove -2
- _.forEach($scope.states, function (state) {
- if (!state.workflowHeader && !state.divider) {
- if (state.next_states_id.length !== 0) { // add all undone state
- $scope.stateFilter.push(state.id);
- }
- }
- });
- }
- $scope.stateFilter = _.uniq($scope.stateFilter);
- };
-
- // This value may be overritten, so the filters, sorting and pagination in an
- // derived view are independent to this view.
- var osTablePrefix = $scope.osTablePrefix || 'MotionTable';
-
- // Filtering
- $scope.filter = osTableFilter.createInstance(osTablePrefix + 'Filter');
-
- if (!$scope.filter.existsStorageEntry()) {
- $scope.filter.multiselectFilters = {
- state: [],
- category: [],
- motionBlock: [],
- tag: [],
- recommendation: [],
- comment: [],
- };
- $scope.filter.booleanFilters = {
- isFavorite: {
- value: undefined,
- choiceYes: gettext('Marked as favorite'),
- choiceNo: gettext('Not marked as favorite'),
- },
- hasPersonalNote: {
- value: undefined,
- choiceYes: gettext('Personal note set'),
- choiceNo: gettext('Personal note not set'),
- },
- };
- }
- $scope.filter.propertyList = ['identifier', 'origin'];
- $scope.filter.propertyFunctionList = [
- function (motion) {return motion.getTitle();},
- function (motion) {return motion.category ? motion.category.name : '';},
- function (motion) {return motion.motionBlock ? motion.motionBlock.name : '';},
- function (motion) {return motion.recommendation ? motion.getRecommendationName() : '';},
- ];
- $scope.filter.propertyDict = {
- 'submitters': function (submitter) {
- return submitter.user.get_short_name();
- },
- 'supporters': function (supporter) {
- return supporter.get_short_name();
- },
- 'tags': function (tag) {
- return tag.name;
- },
- };
- $scope.getItemId = {
- state: function (motion) {return motion.state_id;},
- comment: function (motion) {
- var ids = [];
- _.forEach(motion.comments, function (comment, id) {
- if (comment) {
- ids.push(id);
- }
- });
- return ids;
- },
- category: function (motion) {return motion.category_id;},
- motionBlock: function (motion) {return motion.motion_block_id;},
- tag: function (motion) {return motion.tags_id;},
- recommendation: function (motion) {return motion.recommendation_id;},
- };
- $scope.operateStateFilter = function (id, danger) {
- $scope.filter.operateMultiselectFilter('state', id, danger);
- updateStateFilter();
- };
- $scope.resetFilters = function (danger) {
- $scope.filter.reset(danger);
- updateStateFilter();
- };
- // Sorting
- $scope.sort = osTableSort.createInstance(osTablePrefix + 'Sort');
- if (!$scope.sort.column) {
- $scope.sort.column = 'identifier';
- }
- $scope.sortOptions = [
- {name: 'identifier',
- display_name: gettext('Identifier')},
- {name: 'getTitle()',
- display_name: gettext('Title')},
- {name: 'submitters[0].user.get_short_name()',
- display_name: gettext('Submitters')},
- {name: 'category.' + Config.get('motions_export_category_sorting').value,
- display_name: gettext('Category')},
- {name: 'motionBlock.title',
- display_name: gettext('Motion block')},
- {name: 'state.name',
- display_name: gettext('State')},
- {name: 'log_messages[log_messages.length-1].time',
- display_name: gettext('Creation date')},
- {name: 'log_messages[0].time',
- display_name: gettext('Last modified')},
- ];
-
- // pagination
- $scope.pagination = osTablePagination.createInstance(osTablePrefix + 'Pagination');
-
- $scope.hasTag = function (motion, tag) {
- return _.indexOf(motion.tags_id, tag.id) > -1;
- };
-
- $scope.save = function (motion) {
- Motion.save(motion, {method: 'PATCH'});
- };
- // delete single motion
- $scope.delete = function (motion) {
- Motion.destroy(motion.id);
- };
- $scope.toggleTag = function (motion, tag) {
- if ($scope.hasTag(motion, tag)) {
- // remove
- motion.tags_id = _.filter(motion.tags_id, function (tag_id){
- return tag_id != tag.id;
- });
- } else {
- motion.tags_id.push(tag.id);
- }
- $scope.save(motion);
- };
- $scope.toggleCategory = function (motion, category) {
- if (motion.category_id == category.id) {
- motion.category_id = null;
- } else {
- motion.category_id = category.id;
- }
- $scope.save(motion);
- };
- $scope.toggleMotionBlock = function (motion, block) {
- if (motion.motion_block_id == block.id) {
- motion.motion_block_id = null;
- } else {
- motion.motion_block_id = block.id;
- }
- $scope.save(motion);
- };
- $scope.toggleStar = function (motion) {
- if (motion.personalNote) {
- motion.personalNote.star = !motion.personalNote.star;
- } else {
- motion.personalNote = {star: true};
- }
- PersonalNoteManager.saveNote(motion, motion.personalNote);
- };
-
- // open new/edit dialog
- $scope.openDialog = function (motion) {
- ngDialog.open(MotionForm.getDialog(motion));
- };
- // Export dialog
- $scope.openExportDialog = function (motions) {
- ngDialog.open(MotionExportForm.getDialog(motions, $scope.sort));
- };
- $scope.pdfExport = function (motions) {
- MotionPdfExport.export(motions);
- };
-
- // *** select mode functions ***
- $scope.isSelectMode = false;
- // check all checkboxes from filtered motions
- $scope.checkAll = function (motions) {
- $scope.selectedAll = !$scope.selectedAll;
- _.forEach(motions, function (motion) {
- motion.selected = $scope.selectedAll;
- });
- };
- // uncheck all checkboxes if isSelectMode is closed
- $scope.uncheckAll = function () {
- if (!$scope.isSelectMode) {
- $scope.selectedAll = false;
- _.forEach($scope.motions, function (motion) {
- motion.selected = false;
- });
- }
- };
- var selectModeAction = function (motions, predicate) {
- angular.forEach(motions, function (motion) {
- if (motion.selected) {
- predicate(motion);
- }
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // delete selected motions
- $scope.deleteMultiple = function (motions) {
- selectModeAction(motions, function (motion) {
- $scope.delete(motion);
- });
- };
- // set status for selected motions
- $scope.setStatusMultiple = function (motions, stateId) {
- selectModeAction(motions, function (motion) {
- $http.put('/rest/motions/motion/' + motion.id + '/set_state/', {'state': stateId});
- });
- };
- // set category for selected motions
- $scope.setCategoryMultiple = function (motions, categoryId) {
- selectModeAction(motions, function (motion) {
- motion.category_id = categoryId === 'no_category_selected' ? null : categoryId;
- $scope.save(motion);
- });
- };
- // set status for selected motions
- $scope.setMotionBlockMultiple = function (motions, motionBlockId) {
- selectModeAction(motions, function (motion) {
- motion.motion_block_id = motionBlockId === 'no_motionBlock_selected' ? null : motionBlockId;
- $scope.save(motion);
- });
- };
- }
-])
-
-.controller('MotionDetailCtrl', [
- '$scope',
- '$http',
- '$timeout',
- '$window',
- '$filter',
- 'operator',
- 'ngDialog',
- 'gettextCatalog',
- 'MotionForm',
- 'AmendmentParagraphChooseForm',
- 'ChangeRecommendationCreate',
- 'ChangeRecommendationView',
- 'MotionStateAndRecommendationParser',
- 'MotionChangeRecommendation',
- 'Motion',
- 'MotionComment',
- 'Category',
- 'Mediafile',
- 'Tag',
- 'User',
- 'Workflow',
- 'Config',
- 'motionId',
- 'MotionInlineEditing',
- 'MotionCommentsInlineEditing',
- 'Editor',
- 'Projector',
- 'ProjectionDefault',
- 'MotionBlock',
- 'MotionPdfExport',
- 'PersonalNoteManager',
- 'Notify',
- 'WebpageTitle',
- 'EditingWarning',
- function($scope, $http, $timeout, $window, $filter, operator, ngDialog, gettextCatalog,
- MotionForm, AmendmentParagraphChooseForm, ChangeRecommendationCreate, ChangeRecommendationView,
- MotionStateAndRecommendationParser, MotionChangeRecommendation, Motion, MotionComment,
- Category, Mediafile, Tag, User, Workflow, Config, motionId, MotionInlineEditing,
- MotionCommentsInlineEditing, Editor, Projector, ProjectionDefault, MotionBlock,
- MotionPdfExport, PersonalNoteManager, Notify, WebpageTitle, EditingWarning) {
- var motion = Motion.get(motionId);
- Category.bindAll({}, $scope, 'categories');
- Mediafile.bindAll({}, $scope, 'mediafiles');
- Tag.bindAll({}, $scope, 'tags');
- User.bindAll({}, $scope, 'users');
- Workflow.bindAll({}, $scope, 'workflows');
- MotionBlock.bindAll({}, $scope, 'motionBlocks');
- Motion.bindAll({}, $scope, 'motions');
-
-
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- $scope.projectors = Projector.getAll();
- var projectiondefault = ProjectionDefault.filter({name: 'motions'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.$watch(function () {
- return Motion.lastModified(motionId);
- }, function () {
- $scope.motion = Motion.get(motionId);
- $scope.amendment_diff_paragraphs = $scope.motion.getAmendmentParagraphsLinesDiff();
- MotionComment.populateFields($scope.motion);
- if (motion.comments) {
- $scope.stateExtension = $scope.motion.comments[$scope.commentFieldForStateId];
- $scope.recommendationExtension = $scope.motion.comments[$scope.commentFieldForRecommendationId];
- }
- $scope.motion.personalNote = PersonalNoteManager.getNote($scope.motion);
- $scope.navigation.evaluate();
-
- var webpageTitle = gettextCatalog.getString('Motion') + ' ';
- if ($scope.motion.identifier) {
- webpageTitle += $scope.motion.identifier + ' - ';
- }
- webpageTitle += $scope.motion.getTitle();
- WebpageTitle.updateTitle(webpageTitle);
-
- $scope.createChangeRecommendation.setVersion(motion, motion.active_version);
- $scope.viewChangeRecommendations.setVersion(motion, motion.active_version);
- });
- $scope.$watch(function () {
- return Motion.lastModified();
- }, function () {
- $scope.motions = Motion.getAll();
- $scope.amendments = Motion.filter({parent_id: motion.id});
- });
- $scope.projectionModes = [
- {mode: 'original',
- label: 'Original version'},
- {mode: 'changed',
- label: 'Changed version'},
- {mode: 'diff',
- label: 'Diff version'},
- {mode: 'agreed',
- label: 'Final version'},
- {mode: 'modified_agreed',
- label: 'Final print template'},
- ];
- var motionDefaultRecommendationTextMode = Config.get('motions_recommendation_text_mode').value;
- // Change to the modified final version, if exists
- if (motionDefaultRecommendationTextMode === 'agreed' && motion.getModifiedFinalVersion()) {
- motionDefaultRecommendationTextMode = 'modified_agreed';
- }
- $scope.projectionMode = _.find($scope.projectionModes, function (mode) {
- return mode.mode == motionDefaultRecommendationTextMode;
- });
- if (motion.isProjected().length) {
- var modeMapping = motion.isProjectedWithMode();
- _.forEach($scope.projectionModes, function (mode) {
- if (mode.mode === modeMapping[0].mode) {
- $scope.projectionMode = mode;
- }
- });
- }
- $scope.setProjectionMode = function (mode) {
- $scope.projectionMode = mode;
- var isProjected = motion.isProjectedWithMode();
- if (isProjected.length) {
- _.forEach(isProjected, function (mapping) {
- if (mapping.mode != mode.mode) { // change the mode if it is different
- motion.project(mapping.projectorId, mode.mode);
- }
- });
- }
- };
- $scope.commentsFields = MotionComment.getCommentsFields();
- $scope.noSpecialCommentsFields = MotionComment.getNoSpecialCommentsFields();
- $scope.commentFieldForStateId = MotionComment.getFieldIdForFlag('forState');
- $scope.commentFieldForRecommendationId = MotionComment.getFieldIdForFlag('forRecommendation');
- $scope.version = motion.active_version;
- $scope.isCollapsed = true;
- $scope.lineNumberMode = Config.get('motions_default_line_numbering').value;
- $scope.setLineNumberMode = function(mode) {
- $scope.lineNumberMode = mode;
- };
-
- $scope.showAmendmentContext = false;
- $scope.setShowAmendmentContext = function($event) {
- $event.preventDefault();
- $event.stopPropagation();
- $scope.showAmendmentContext = !$scope.showAmendmentContext;
- };
-
- if (motion.parent_id) {
- Motion.bindOne(motion.parent_id, $scope, 'parent');
- }
-
- $scope.scrollToLine = 0;
- $scope.highlight = 0;
- $scope.linesForProjector = false;
- $scope.scrollToAndHighlight = function (line) {
- $scope.scrollToLine = line;
- $scope.highlight = line;
-
- // The same line number can occur twice in diff view; we scroll to the first one in this case
- var scrollTop = null;
- $('.line-number-' + line).each(function() {
- var top = $(this).offset().top;
- if (top > 0 && (scrollTop === null || top < scrollTop)) {
- scrollTop = top;
- }
- });
-
- if (scrollTop) {
- // Scroll local; 50 pixel above the line, so it's not completely squeezed to the screen border
- $('html, body').animate({
- 'scrollTop': scrollTop - 50
- }, 1000);
- // remove the line highlight after 2 seconds.
- $timeout(function () {
- $scope.highlight = 0;
- }, 2000);
- }
-
- $scope.scrollProjectorToLine(line);
- };
- $scope.scrollProjectorToLine = function (line) {
- var projectorIds = $scope.motion.isProjected();
- if (!$scope.linesForProjector || !line || !projectorIds.length) {
- return;
- }
- var projectorId = projectorIds[0];
- var notifyNamePrefix = 'projector_' + projectorId + '_motion_line_';
-
- // register callback
- var callbackId = Notify.registerCallback(notifyNamePrefix + 'answer', function (params) {
- Notify.deregisterCallback(callbackId);
- $http.post('/rest/core/projector/' + projectorId + '/set_scroll/', params.params.scroll);
- });
-
- // Query all projectors
- Notify.notify(notifyNamePrefix + 'request', {line: line}, null, null, [projectorId]);
- };
- $scope.toggleLinesForProjector = function () {
- $scope.linesForProjector = !$scope.linesForProjector;
- $scope.scrollProjectorToLine($scope.scrollToLine);
- };
-
- // open edit dialog
- $scope.openDialog = function (motion) {
- if ($scope.inlineEditing.active) {
- $scope.disableMotionInlineEditing();
- }
- ngDialog.open(MotionForm.getDialog(motion));
- };
- $scope.save = function (motion) {
- Motion.save(motion, {method: 'PATCH'});
- };
- // Navigation buttons
- $scope.navigation = {
- evaluate: function () {
- var motions = $filter('orderByEmptyLast')(Motion.getAll(), 'identifier');
- var thisIndex = _.findIndex(motions, function (motion) {
- return motion.id === $scope.motion.id;
- });
- this.count = motions.length;
- this.nextMotion = thisIndex < motions.length-1 ? motions[thisIndex+1] : _.head(motions);
- this.previousMotion = thisIndex > 0 ? motions[thisIndex-1] : _.last(motions);
- },
- };
- // support
- $scope.support = function () {
- $http.post('/rest/motions/motion/' + motion.id + '/support/');
- };
- // unsupport
- $scope.unsupport = function () {
- $http.delete('/rest/motions/motion/' + motion.id + '/support/');
- };
- // open dialog for new amendment
- $scope.newAmendment = function () {
- var openMainDialog = function (paragraphNo) {
- var dialog = MotionForm.getDialog(null, motion, paragraphNo);
- dialog.scope = $scope;
- ngDialog.open(dialog);
- };
-
- if (Config.get('motions_amendments_text_mode').value === 'paragraph') {
- var dialog = AmendmentParagraphChooseForm.getDialog($scope.motion, openMainDialog);
- dialog.scope = $scope;
- ngDialog.open(dialog);
- } else {
- openMainDialog();
- }
- };
- // follow recommendation
- $scope.followRecommendation = function () {
- $http.post('/rest/motions/motion/' + motion.id + '/follow_recommendation/', {
- 'recommendationExtension': $scope.recommendationExtension
- });
- };
- // toggle functions for meta information
- $scope.toggleCategory = function (category) {
- if ($scope.motion.category_id == category.id) {
- $scope.motion.category_id = null;
- } else {
- $scope.motion.category_id = category.id;
- }
- $scope.save($scope.motion);
- };
- $scope.toggleMotionBlock = function (block) {
- if ($scope.motion.motion_block_id == block.id) {
- $scope.motion.motion_block_id = null;
- } else {
- $scope.motion.motion_block_id = block.id;
- }
- $scope.save($scope.motion);
-
- };
- $scope.toggleTag = function (tag) {
- if (_.indexOf($scope.motion.tags_id, tag.id) > -1) {
- // remove
- $scope.motion.tags_id = _.filter($scope.motion.tags_id,
- function (tag_id){
- return tag_id != tag.id;
- }
- );
- } else {
- $scope.motion.tags_id.push(tag.id);
- }
- $scope.save($scope.motion);
- };
- // save additional state field
- $scope.saveAdditionalStateField = function (stateExtension) {
- motion['comment_' + $scope.commentFieldForStateId] = stateExtension;
- $scope.save(motion);
- };
- // save additional recommendation field
- $scope.saveAdditionalRecommendationField = function (recommendationExtension) {
- motion['comment_' + $scope.commentFieldForRecommendationId] = recommendationExtension;
- $scope.save(motion);
- };
- $scope.addMotionToRecommendationField = function (motion) {
- $scope.recommendationExtension += MotionStateAndRecommendationParser.formatMotion(motion);
- };
- // create poll
- $scope.create_poll = function () {
- $http.post('/rest/motions/motion/' + motion.id + '/create_poll/', {});
- };
- // open poll update dialog
- $scope.openPollDialog = function (poll, voteNumber) {
- ngDialog.open({
- template: 'static/templates/motions/motion-poll-form.html',
- controller: 'MotionPollUpdateCtrl',
- className: 'ngdialog-theme-default',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- motionpollId: function () {
- return poll.id;
- },
- voteNumber: function () {
- return voteNumber;
- }
- }
- });
- };
- // delete poll
- $scope.delete_poll = function (poll) {
- poll.DSDestroy();
- };
- // show specific version
- $scope.showVersion = function (version) {
- $scope.version = version.id;
- $scope.inlineEditing.setVersion(motion, version.id);
- $scope.reasonInlineEditing.setVersion(motion, version.id);
- $scope.createChangeRecommendation.setVersion(motion, version.id);
- $scope.viewChangeRecommendations.setVersion(motion, motion.active_version);
- };
- // permit specific version
- $scope.permitVersion = function (version) {
- $http.put('/rest/motions/motion/' + motion.id + '/manage_version/',
- {'version_number': version.version_number})
- .then(function(success) {
- $scope.showVersion(version);
- });
- };
- // delete specific version
- $scope.deleteVersion = function (version) {
- $http.delete('/rest/motions/motion/' + motion.id + '/manage_version/',
- {headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({version_number: version.version_number})})
- .then(function(success) {
- $scope.showVersion({id: motion.active_version});
- });
- };
- // check if there is at least one comment field
- $scope.commentFieldsAvailable = function () {
- return _.keys($scope.noSpecialCommentsFields).length > 0;
- };
- // personal note
- // For pinning the personal note container we need to adjust the width with JS. We
- // do not use angular here, because on every window resize a digist cycle would trigger.
- // This costs too much performance. We use JQuery here, because it is fast for DOM
- // manipulation and very responsive.
- $scope.toggleStar = function () {
- if ($scope.motion.personalNote) {
- $scope.motion.personalNote.star = !$scope.motion.personalNote.star;
- } else {
- $scope.motion.personalNote = {star: true};
- }
- PersonalNoteManager.saveNote($scope.motion, $scope.motion.personalNote);
- };
- $scope.personalNotePinned = false;
- $scope.pinPersonalNote = function () {
- $scope.personalNotePinned = !$scope.personalNotePinned;
- if ($scope.personalNotePinned) {
- resizePersonalNoteContainer();
- } else {
- $('#personalNote').css('width', '');
- }
- };
- $scope.gotoPersonalNote = function () {
- var pos = $('#personalNote').offset();
- $window.scrollTo(pos.left, pos.top);
- };
- var resizePersonalNoteContainer = function () {
- if ($scope.personalNotePinned) {
- var width = $('#main-column').width() - 40; // Subtract 2x20px margin
- $('#personalNote').css('width', width + 'px');
- }
- };
- $(window).resize(resizePersonalNoteContainer);
-
- // Inline editing functions
- $scope.inlineEditing = MotionInlineEditing.createInstance($scope, motion,
- 'view-original-text-inline-editor', true, Editor.getOptions('inline'),
- function (obj) {
- return motion.getTextWithLineBreaks($scope.version);
- },
- function (obj) {
- motion.setTextStrippingLineBreaks(obj.editor.getData());
- motion.disable_versioning = (obj.trivialChange &&
- Config.get('motions_allow_disable_versioning').value);
- }
- );
- $scope.reasonInlineEditing = MotionInlineEditing.createInstance($scope, motion,
- 'reason-inline-editor', true, Editor.getOptions('inline'),
- function (obj) {
- return motion.getReason($scope.version);
- },
- function (obj) {
- motion.reason = obj.editor.getData();
- motion.disable_versioning = (obj.trivialChange &&
- Config.get('motions_allow_disable_versioning').value);
- }
- );
- $scope.modifiedFinalVersionInlineEditing = MotionInlineEditing.createInstance($scope, motion,
- 'view-modified-agreed-inline-editor', true, Editor.getOptions('inline'),
- function (obj) {
- return motion.getModifiedFinalVersionWithLineBreaks($scope.version);
- },
- function (obj) {
- motion.setModifiedFinalVersionStrippingLineBreaks(obj.editor.getData());
- motion.disable_versioning = (obj.trivialChange &&
- Config.get('motions_allow_disable_versioning').value);
- }
- );
- // Wrapper functions for $scope.inlineEditing, to warn other users.
- var editingStoppedCallback;
- $scope.enableMotionInlineEditing = function () {
- editingStoppedCallback = EditingWarning.editingStarted('motion_update_' + motion.id);
- if ($scope.motion.getReason($scope.version)) {
- $scope.reasonInlineEditing.enable();
- }
- $scope.inlineEditing.enable();
- };
- $scope.disableMotionInlineEditing = function () {
- if (editingStoppedCallback) {
- editingStoppedCallback();
- }
- if ($scope.motion && $scope.motion.getReason($scope.version)) {
- $scope.reasonInlineEditing.disable();
- }
- $scope.inlineEditing.disable();
- };
- $scope.textReasonSaveToolbarVisible = function () {
- return ($scope.inlineEditing.changed && $scope.inlineEditing.active) ||
- ($scope.reasonInlineEditing.changed && $scope.reasonInlineEditing.active);
- };
- $scope.textReasonSave = function () {
- if ($scope.motion.getReason($scope.version)) {
- $scope.reasonInlineEditing.save();
- }
- $scope.inlineEditing.save();
- };
- $scope.textReasonRevert = function () {
- if ($scope.motion.getReason($scope.version)) {
- $scope.reasonInlineEditing.revert();
- }
- $scope.inlineEditing.revert();
- };
- $scope.commentsInlineEditing = MotionCommentsInlineEditing.createInstances($scope, motion);
- $scope.personalNoteInlineEditing = MotionInlineEditing.createInstance($scope, motion,
- 'personal-note-inline-editor', false, Editor.getOptions('inline'),
- function (obj) {
- return motion.personalNote ? motion.personalNote.note : '';
- },
- function (obj) {
- if (motion.personalNote) {
- motion.personalNote.note = obj.editor.getData();
- } else {
- motion.personalNote = {note: obj.editor.getData()};
- }
- PersonalNoteManager.saveNote(motion, motion.personalNote);
- obj.revert();
- obj.disable();
- return true; // Do not update the motion via patch request.
- }
- );
-
- // Change recommendation creation functions
- $scope.createChangeRecommendation = ChangeRecommendationCreate;
- $scope.createChangeRecommendation.init($scope, motion);
-
- // Change recommendation and amendment viewing
- $scope.viewChangeRecommendations = ChangeRecommendationView;
- $scope.viewChangeRecommendations.initSite($scope, motion, motionDefaultRecommendationTextMode);
-
- // PDF creating functions
- $scope.pdfExport = function () {
- var identifier = $scope.motion.identifier ? '-' + $scope.motion.identifier : '';
- var params = {
- filename: gettextCatalog.getString('Motion') + identifier + '.pdf',
- version: $scope.version,
- changeRecommendationMode: $scope.viewChangeRecommendations.mode,
- lineNumberMode: $scope.lineNumberMode,
- };
- MotionPdfExport.export(motion, params, true);
- };
- $scope.createPollPdf = function () {
- MotionPdfExport.createPollPdf($scope.motion, $scope.version);
- };
- $scope.exportComment = function (commentId) {
- var identifier = $scope.motion.identifier ? '-' + $scope.motion.identifier : '';
- var commentsString = ' - ' + gettextCatalog.getString('Comments');
- var filename = gettextCatalog.getString('Motion') + identifier + commentsString + '.pdf';
- MotionPdfExport.exportComment($scope.motion, commentId, filename);
- };
- $scope.exportPersonalNote = function () {
- var identifier = $scope.motion.identifier ? '-' + $scope.motion.identifier : '';
- var personalNoteString = ' - ' + gettextCatalog.getString('personal note');
- var filename = gettextCatalog.getString('Motion') + identifier + personalNoteString + '.pdf';
- MotionPdfExport.exportPersonalNote($scope.motion, filename);
- };
- }
-])
-
-.controller('ChangeRecommendationTitleUpdateCtrl', [
- '$scope',
- 'MotionChangeRecommendation',
- 'ChangeRecommendationTitleForm',
- 'diffService',
- 'change',
- 'ErrorMessage',
- function ($scope, MotionChangeRecommendation, ChangeRecommendationTitleForm, diffService, change, ErrorMessage) {
- $scope.alert = {};
- $scope.model = angular.copy(change);
-
- // get all form fields
- $scope.formFields = ChangeRecommendationTitleForm.getFormFields();
- // save motion
- $scope.save = function (change) {
- // inject the changed change recommendation (copy) object back into DS store
- MotionChangeRecommendation.inject(change);
- // save changed change recommendation object on server
- MotionChangeRecommendation.save(change).then(
- function() {
- $scope.closeThisDialog();
- },
- function (error) {
- MotionChangeRecommendation.refresh(change);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('ChangeRecommendationTitleCreateCtrl', [
- '$scope',
- 'Motion',
- 'MotionChangeRecommendation',
- 'ChangeRecommendationTitleForm',
- 'Config',
- 'diffService',
- 'motion',
- 'version',
- function($scope, Motion, MotionChangeRecommendation, ChangeRecommendationTitleForm, Config, diffService, motion,
- version) {
- $scope.alert = {};
-
- $scope.model = {
- text: version.title,
- motion_version_id: version.id
- };
-
- // get all form fields
- $scope.formFields = ChangeRecommendationTitleForm.getFormFields();
- // save motion
- $scope.save = function (change) {
- change.line_from = 0;
- change.line_to = 0;
- MotionChangeRecommendation.create(change).then(
- function() {
- $scope.closeThisDialog();
- }
- );
- };
- }
-])
-
-.controller('ChangeRecommendationTextUpdateCtrl', [
- '$scope',
- 'MotionChangeRecommendation',
- 'ChangeRecommendationTextForm',
- 'diffService',
- 'change',
- 'ErrorMessage',
- function ($scope, MotionChangeRecommendation, ChangeRecommendationTextForm, diffService, change, ErrorMessage) {
- $scope.alert = {};
- $scope.model = angular.copy(change);
- $scope.model._change_object = undefined;
-
- // get all form fields
- $scope.formFields = ChangeRecommendationTextForm.getFormFields(change.line_from, change.line_to);
- // save motion
- $scope.save = function (change) {
- change.text = diffService.removeDuplicateClassesInsertedByCkeditor(change.text);
- // inject the changed change recommendation (copy) object back into DS store
- MotionChangeRecommendation.inject(change);
- // save changed change recommendation object on server
- MotionChangeRecommendation.save(change).then(
- function() {
- $scope.closeThisDialog();
- },
- function (error) {
- MotionChangeRecommendation.refresh(change);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('ChangeRecommendationTextCreateCtrl', [
- '$scope',
- 'Motion',
- 'MotionChangeRecommendation',
- 'ChangeRecommendationTextForm',
- 'Config',
- 'diffService',
- 'motion',
- 'version',
- 'lineFrom',
- 'lineTo',
- function($scope, Motion, MotionChangeRecommendation, ChangeRecommendationTextForm, Config, diffService, motion,
- version, lineFrom, lineTo) {
- $scope.alert = {};
-
- var html = motion.getTextWithLineBreaks(version.id),
- lineData = diffService.extractRangeByLineNumbers(html, lineFrom, lineTo);
-
- $scope.model = {
- text: lineData.outerContextStart + lineData.innerContextStart +
- lineData.html + lineData.innerContextEnd + lineData.outerContextEnd,
- line_from: lineFrom,
- line_to: lineTo,
- motion_version_id: version.id,
- type: 0
- };
-
- // get all form fields
- $scope.formFields = ChangeRecommendationTextForm.getFormFields(lineFrom, lineTo);
- // save motion
- $scope.save = function (motion) {
- motion.text = diffService.removeDuplicateClassesInsertedByCkeditor(motion.text);
- MotionChangeRecommendation.create(motion).then(
- function() {
- $scope.closeThisDialog();
- }
- );
- };
- }
-])
-
-.controller('AmendmentParagraphChooseCtrl', [
- '$scope',
- '$state',
- 'Motion',
- 'motion',
- 'successCb',
- function($scope, $state, Motion, motion, successCb) {
- $scope.model = angular.copy(motion);
- $scope.model.paragraph_selected = null;
-
- $scope.paragraphs = motion.getTextParagraphs(motion.active_version, true).map(function(text, index) {
- // This prevents an error in ng-repeater's duplication detection if two identical paragraphs occur
- return {
- "paragraphNo": index,
- "text": text
- };
- });
-
- $scope.gotoMotionForm = function() {
- var paragraphNo = parseInt($scope.model.paragraph_selected);
- successCb(paragraphNo);
- $scope.closeThisDialog();
- };
- }
-])
-
-.controller('MotionCreateCtrl', [
- '$scope',
- '$state',
- 'gettext',
- 'gettextCatalog',
- 'operator',
- 'Motion',
- 'MotionForm',
- 'parentMotion',
- 'paragraphNo',
- 'paragraphTextPre',
- 'Category',
- 'Config',
- 'Mediafile',
- 'Tag',
- 'User',
- 'Workflow',
- 'Agenda',
- 'ErrorMessage',
- function($scope, $state, gettext, gettextCatalog, operator, Motion, MotionForm, parentMotion,
- paragraphNo, paragraphTextPre, Category, Config, Mediafile, Tag, User, Workflow,
- Agenda, ErrorMessage) {
- Category.bindAll({}, $scope, 'categories');
- Mediafile.bindAll({}, $scope, 'mediafiles');
- Tag.bindAll({}, $scope, 'tags');
- User.bindAll({}, $scope, 'users');
- Workflow.bindAll({}, $scope, 'workflows');
-
- $scope.model = {
- agenda_type: parseInt(Config.get('agenda_new_items_default_visibility').value),
- };
-
- $scope.alert = {};
-
- // Check whether this is a new amendment.
- var isAmendment = parentMotion && parentMotion.id,
- isParagraphBasedAmendment = false;
-
- // Set default values for create form
- // ... for amendments add parent_id
- if (isAmendment) {
- if (Config.get('motions_amendments_text_mode').value === 'fulltext') {
- $scope.model.text = parentMotion.getText();
- }
- if (Config.get('motions_amendments_text_mode').value === 'paragraph' &&
- paragraphNo !== undefined) {
- var paragraphs = parentMotion.getTextParagraphs(parentMotion.active_version, false);
- $scope.model.text = paragraphs[paragraphNo];
- isParagraphBasedAmendment = true;
- }
- if (paragraphTextPre !== undefined) {
- $scope.model.text = paragraphTextPre;
- }
- if (parentMotion.identifier) {
- $scope.model.title = gettextCatalog.getString('Amendment to') +
- ' ' + parentMotion.identifier;
- } else {
- $scope.model.title = gettextCatalog.getString('Amendment to motion ') +
- ' ' + parentMotion.getTitle();
- }
- $scope.model.paragraphNo = paragraphNo;
- $scope.model.parent_id = parentMotion.id;
- $scope.model.category_id = parentMotion.category_id;
- $scope.model.motion_block_id = parentMotion.motion_block_id;
- Motion.bindOne($scope.model.parent_id, $scope, 'parent');
- }
- // ... preselect default workflow if exist
- var workflow = Workflow.get(Config.get('motions_workflow').value);
- if (!workflow) {
- workflow = _.first(Workflow.getAll());
- }
- if (workflow) {
- $scope.model.workflow_id = workflow.id;
- } else {
- $scope.alert = {
- type: 'danger',
- msg: gettextCatalog.getString('No workflows exists. You will not ' +
- 'be able to create a motion.'),
- show: true,
- };
- }
-
- // get all form fields
- $scope.formFields = MotionForm.getFormFields(true, isParagraphBasedAmendment);
-
- // save motion
- $scope.save = function (motion, gotoDetailView) {
- if (isAmendment && motion.paragraphNo !== undefined) {
- var orig_paragraphs = parentMotion.getTextParagraphs(parentMotion.active_version, false);
- motion.amendment_paragraphs = orig_paragraphs.map(function (_, idx) {
- return (idx === motion.paragraphNo ? motion.text : null);
- });
- }
-
- // The attribute motion.agenda_parent_id is set by the form, see form definition.
- Motion.create(motion).then(
- function(success) {
- if (isAmendment || gotoDetailView) {
- $state.go('motions.motion.detail', {id: success.id});
- }
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('MotionUpdateCtrl', [
- '$scope',
- '$state',
- 'Motion',
- 'Category',
- 'Config',
- 'Mediafile',
- 'MotionForm',
- 'Tag',
- 'User',
- 'Workflow',
- 'Agenda',
- 'motionId',
- 'operator',
- 'ErrorMessage',
- 'EditingWarning',
- function ($scope, $state, Motion, Category, Config, Mediafile, MotionForm,
- Tag, User, Workflow, Agenda, motionId, operator, ErrorMessage,
- EditingWarning) {
- Category.bindAll({}, $scope, 'categories');
- Mediafile.bindAll({}, $scope, 'mediafiles');
- Tag.bindAll({}, $scope, 'tags');
- User.bindAll({}, $scope, 'users');
- Workflow.bindAll({}, $scope, 'workflows');
- $scope.alert = {};
-
- // set initial values for form model by create deep copy of motion object
- // so list/detail view is not updated while editing
- var motion = Motion.get(motionId);
- // We need to clone this by hand. angular and lodash are not capable of keeping
- // crossreferences out.
- $scope.model = {
- id: motion.id,
- parent_id: motion.parent_id,
- identifier: motion.identifier,
- title: motion.getTitle(),
- text: motion.getText(),
- reason: motion.getReason(),
- submitters_id: _.map(motion.submitters_id),
- supporters_id: _.map(motion.supporters_id),
- tags_id: _.map(motion.tags_id),
- state_id: motion.state_id,
- recommendation_id: motion.recommendation_id,
- origin: motion.origin,
- workflow_id: motion.workflow_id,
- comments: _.clone(motion.comments),
- attachments_id: _.map(motion.attachments_id),
- active_version: motion.active_version,
- agenda_item_id: motion.agenda_item_id,
- category_id: motion.category_id,
- motion_block_id: motion.motion_block_id,
- };
- // Clone comments
- _.forEach(motion.comments, function (comment, index) {
- $scope.model['comment_' + index] = comment;
- });
- $scope.model.disable_versioning = false;
- $scope.model.more = false;
- if (motion.isParagraphBasedAmendment()) {
- motion.getVersion(motion.active_version).amendment_paragraphs.forEach(function(paragraph_amend, paragraphNo) {
- // Hint: this assumes there is only one modified paragraph
- if (paragraph_amend !== null) {
- $scope.model.text = paragraph_amend;
- $scope.model.paragraphNo = paragraphNo;
- }
- });
- $scope.model.title = motion.getTitle();
- }
-
- // get all form fields
- $scope.formFields = MotionForm.getFormFields(false, motion.isParagraphBasedAmendment());
- // override default values for update form
- for (var i = 0; i < $scope.formFields.length; i++) {
- if ($scope.formFields[i].key == "identifier") {
- // show identifier field if the operator has manage permissions
- $scope.formFields[i].hide = !operator.hasPerms('motions.can_manage');
- }
- if ($scope.formFields[i].key == "title") {
- // get title of latest version
- $scope.formFields[i].defaultValue = motion.getTitle(-1);
- }
- if ($scope.formFields[i].key == "text") {
- // get text of latest version
- $scope.formFields[i].defaultValue = motion.getText(-1);
- }
- if ($scope.formFields[i].key == "reason") {
- // get reason of latest version
- $scope.formFields[i].defaultValue = motion.getReason(-1);
- }
- if ($scope.formFields[i].key == "disable_versioning") {
- if (Config.get('motions_allow_disable_versioning').value && motion.state.versioning) {
- // check current state if versioning is active
- $scope.formFields[i].hide = false;
- }
- }
- if ($scope.formFields[i].key == "workflow_id") {
- // get saved workflow id from state
- $scope.formFields[i].defaultValue = motion.state.workflow_id;
- }
- }
-
- // Displaying a warning, if other users edit this motion too
- var editingStoppedCallback = EditingWarning.editingStarted('motion_update_' + motionId);
- $scope.$on('$destroy', editingStoppedCallback);
-
- // Save motion
- $scope.save = function (model, gotoDetailView) {
- if ($scope.model.paragraphNo !== undefined) {
- var parentMotion = motion.getParentMotion();
- var orig_paragraphs = parentMotion.getTextParagraphs(parentMotion.active_version, false);
- $scope.model.amendment_paragraphs = orig_paragraphs.map(function (_, idx) {
- return (idx === $scope.model.paragraphNo ? $scope.model.text : null);
- });
- }
-
- // inject the changed motion (copy) object back into DS store
- Motion.inject(model);
- // save changed motion object on server
- Motion.save(model).then(
- function(success) {
- if (gotoDetailView) {
- $state.go('motions.motion.detail', {id: success.id});
- }
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(model);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('MotionCommentCtrl', [
- '$scope',
- 'Motion',
- 'MotionComment',
- 'MotionCommentForm',
- 'motionId',
- 'commentFieldId',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, Motion, MotionComment, MotionCommentForm, motionId, commentFieldId,
- gettextCatalog, ErrorMessage) {
- $scope.alert = {};
-
- // set initial values for form model by create deep copy of motion object
- // so list/detail view is not updated while editing
- var motion = Motion.get(motionId);
- $scope.model = angular.copy(motion);
- $scope.formFields = MotionCommentForm.getFormFields(commentFieldId);
-
- var fields = MotionComment.getNoSpecialCommentsFields();
- var title = gettextCatalog.getString('Edit comment %%comment%% of motion %%motion%%');
- title = title.replace('%%comment%%', fields[commentFieldId].name);
- $scope.title = title.replace('%%motion%%', motion.getTitle());
-
- $scope.model.title = motion.getTitle(-1);
- $scope.model.text = motion.getText(-1);
- $scope.model.reason = motion.getReason(-1);
-
- if (motion.isParagraphBasedAmendment()) {
- motion.getVersion(motion.active_version).amendment_paragraphs.forEach(function(paragraph_amend, paragraphNo) {
- // Hint: this assumes there is only one modified paragraph
- if (paragraph_amend !== null) {
- $scope.model.text = paragraph_amend;
- $scope.model.paragraphNo = paragraphNo;
- }
- });
- }
-
- $scope.save = function (motion) {
- if (motion.isParagraphBasedAmendment()) {
- motion.getVersion(motion.active_version).amendment_paragraphs.forEach(function(paragraph_amend, paragraphNo) {
- // Hint: this assumes there is only one modified paragraph
- if (paragraph_amend !== null) {
- $scope.model.text = paragraph_amend;
- $scope.model.paragraphNo = paragraphNo;
- }
- });
- }
-
- // inject the changed motion (copy) object back into DS store
- Motion.inject(motion);
- // save changed motion object on server
- Motion.save(motion).then(
- function(success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original motion object from server
- Motion.refresh(motion);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('MotionPollUpdateCtrl', [
- '$scope',
- 'gettextCatalog',
- 'MotionPoll',
- 'MotionPollForm',
- 'MotionPollDecimalPlaces',
- 'motionpollId',
- 'voteNumber',
- 'ErrorMessage',
- function ($scope, gettextCatalog, MotionPoll, MotionPollForm, MotionPollDecimalPlaces,
- motionpollId, voteNumber, ErrorMessage) {
- // set initial values for form model by create deep copy of motionpoll object
- // so detail view is not updated while editing poll
- var motionpoll = MotionPoll.get(motionpollId);
- $scope.model = angular.copy(motionpoll);
- $scope.voteNumber = voteNumber;
- var precision = MotionPollDecimalPlaces.getPlaces(motionpoll);
- $scope.formFields = MotionPollForm.getFormFields(precision);
- $scope.alert = {};
-
- // save motionpoll
- $scope.save = function (poll) {
- poll.DSUpdate({
- motion_id: poll.motion_id,
- votes: {"Yes": poll.yes, "No": poll.no, "Abstain": poll.abstain},
- votesvalid: poll.votesvalid,
- votesinvalid: poll.votesinvalid,
- votescast: poll.votescast
- })
- .then(function (success) {
- $scope.alert.show = false;
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('MotionSubmitterCtrl', [
- '$scope',
- '$filter',
- '$http',
- 'User',
- 'Motion',
- 'motionId',
- 'ErrorMessage',
- function ($scope, $filter, $http, User, Motion, motionId, ErrorMessage) {
- User.bindAll({}, $scope, 'users');
- $scope.submitterSelectBox = {};
- $scope.alert = {};
-
- $scope.$watch(function () {
- return Motion.lastModified(motionId);
- }, function () {
- $scope.motion = Motion.get(motionId);
- $scope.submitters = $filter('orderBy')($scope.motion.submitters, 'weight');
- });
-
- $scope.addSubmitter = function (userId) {
- $scope.submitterSelectBox = {};
- $http.post('/rest/motions/motion/' + $scope.motion.id + '/manage_submitters/', {
- 'user': userId
- }).then(
- function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
-
- $scope.removeSubmitter = function (userId) {
- $http.delete('/rest/motions/motion/' + $scope.motion.id + '/manage_submitters/', {
- headers: {'Content-Type': 'application/json'},
- data: JSON.stringify({user: userId})
- }).then(
- function (success) {
- $scope.alert.show = false;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
-
- // save reordered list of submitters
- $scope.treeOptions = {
- dropped: function (event) {
- var submitterIds = _.map($scope.submitters, function (submitter) {
- return submitter.id;
- });
- $http.post('/rest/motions/motion/' + $scope.motion.id + '/sort_submitters/', {
- submitters: submitterIds,
- });
- }
- };
- }
-])
-
-.controller('MotionAmendmentListStateCtrl', [
- '$scope',
- 'motionId',
- function ($scope, motionId) {
- $scope.motionId = motionId;
- $scope.osTablePrefix = 'AmendmentTable';
- }
-])
-
-.controller('MotionAmendmentListCtrl', [
- '$scope',
- '$sessionStorage',
- '$state',
- 'Motion',
- 'MotionComment',
- 'MotionForm',
- 'PersonalNoteManager',
- 'ngDialog',
- 'MotionCommentForm',
- 'MotionChangeRecommendation',
- 'MotionPdfExport',
- 'AmendmentCsvExport',
- 'gettextCatalog',
- 'gettext',
- function ($scope, $sessionStorage, $state, Motion, MotionComment, MotionForm,
- PersonalNoteManager, ngDialog, MotionCommentForm, MotionChangeRecommendation,
- MotionPdfExport, AmendmentCsvExport, gettextCatalog, gettext) {
- if ($scope.motionId) {
- $scope.leadMotion = Motion.get($scope.motionId);
- }
-
- var updateMotions = function () {
- // check, if lead motion is given
- var amendments;
- if ($scope.leadMotion) {
- amendments = Motion.filter({parent_id: $scope.leadMotion.id});
- } else {
- amendments = _.filter(Motion.getAll(), function (motion) {
- return motion.parent_id;
- });
- }
- // always order by identifier (after custom ordering)
- $scope.amendments = _.orderBy(amendments, ['identifier']);
-
- _.forEach($scope.amendments, function (amendment) {
- MotionComment.populateFields(amendment);
- amendment.personalNote = PersonalNoteManager.getNote(amendment);
- // For filtering, we cannot filter for .personalNote.star
- amendment.star = amendment.personalNote ? amendment.personalNote.star : false;
- amendment.hasPersonalNote = amendment.personalNote ? !!amendment.personalNote.note : false;
- if (amendment.star === undefined) {
- amendment.star = false;
- }
-
- // add a custom sort attribute
- var parentMotion = amendment.getParentMotion();
- amendment.parentMotionAndLineNumber = parentMotion.identifier;
- if (amendment.isParagraphBasedAmendment()) {
- var paragraphs = amendment.getAmendmentParagraphsLinesDiff();
- var diffLine = '0';
- if (paragraphs.length) {
- diffLine = '' + paragraphs[0].diffLineFrom;
- }
- while (diffLine.length < 6) {
- diffLine = '0' + diffLine;
- }
- amendment.parentMotionAndLineNumber += ' ' + diffLine;
- }
- });
-
- // Get all lead motions
- $scope.leadMotions = _.orderBy(Motion.filter({parent_id: undefined}), ['identifier']);
-
- //updateCollissions();
- };
-
- var updateCollissions = function () {
- $scope.collissions = {};
- _.forEach($scope.amendments, function (amendment) {
- if (amendment.isParagraphBasedAmendment()) {
- var parentMotion = amendment.getParentMotion();
- // get all change recommendations _and_ changes by amendments from the
- // parent motion. From all get the unified change object.
- var parentChangeRecommendations = _.filter(
- MotionChangeRecommendation.filter({
- 'where': {'motion_version_id': {'==': parentMotion.active_version}}
- }), function (change) {
- return change.isTextRecommendation();
- }
- );
- var parentChanges = parentChangeRecommendations.map(function (cr) {
- return cr.getUnifiedChangeObject();
- }).concat(
- _.map(parentMotion.getParagraphBasedAmendmentsForDiffView(), function (amendment) {
- return amendment.getUnifiedChangeObject();
- })
- );
- var change = amendment.getUnifiedChangeObject();
- if (change) {
- change.setOtherChangesForCollission(parentChanges);
- $scope.collissions[amendment.id] = !!change.getCollissions().length;
- }
- }
- });
- };
-
- //$scope.$watch(function () {
- // return MotionChangeRecommendation.lastModified();
- //}, updateCollissions);
-
- $scope.$watch(function () {
- return Motion.lastModified();
- }, updateMotions);
-
- $scope.selectLeadMotion = function (motion) {
- $scope.leadMotion = motion;
- updateMotions();
- if ($scope.leadMotion) {
- $state.transitionTo('motions.motion.amendment-list',
- {id: $scope.leadMotion.id},
- {notify: false}
- );
- } else {
- $state.transitionTo('motions.motion.allamendments', {},
- {notify: false}
- );
- }
- };
-
- // Save expand state so the session
- if ($sessionStorage.amendmentTableExpandState) {
- $scope.toggleExpandContent();
- }
- $scope.saveExpandState = function (state) {
- $sessionStorage.amendmentTableExpandState = state;
- };
-
- // add custom sorting
- $scope.sortOptions.unshift({
- name: 'parentMotionAndLineNumber',
- display_name: gettext('Parent motion and line number'),
- });
- if (!$scope.sort.column || $scope.sort.column === 'identifier') {
- $scope.sort.column = 'parentMotionAndLineNumber';
- }
-
- $scope.isTextExpandable = function (comment, characters) {
- comment = $(comment).text();
- return comment.length > characters;
- };
- $scope.getTextPreview = function (comment, characters) {
- comment = $(comment).text();
- if (comment.length > characters) {
- comment = comment.substr(0, characters) + '...';
- }
- return comment;
- };
- $scope.editComment = function (motion, fieldId) {
- ngDialog.open(MotionCommentForm.getDialog(motion, fieldId));
- };
-
- $scope.createModifiedAmendment = function (amendment) {
- var paragraphNo,
- paragraphText;
- if (amendment.isParagraphBasedAmendment()) {
- // We assume there is only one affected paragraph
- amendment.getVersion(amendment.active_version).amendment_paragraphs.forEach(function(parText, parNo) {
- if (parText !== null) {
- paragraphNo = parNo;
- paragraphText = parText;
- }
- });
- } else {
- paragraphText = amendment.getText();
- }
- ngDialog.open(MotionForm.getDialog(null, amendment.getParentMotion(), paragraphNo, paragraphText));
- };
-
- $scope.amendmentPdfExport = function (motions) {
- var filename;
- if ($scope.leadMotion) {
- filename = gettextCatalog.getString('Amendments to') + ' ' +
- $scope.leadMotion.getTitle();
- } else {
- filename = gettextCatalog.getString('Amendments');
- }
- filename += '.pdf';
- MotionPdfExport.exportAmendments(motions, filename);
- };
-
- $scope.exportCsv = function (motions) {
- AmendmentCsvExport.export(motions);
- };
- }
-])
-
-.controller('MotionImportCtrl', [
- '$scope',
- '$q',
- 'gettext',
- 'Category',
- 'Motion',
- 'MotionBlock',
- 'User',
- 'MotionCsvExport',
- function ($scope, $q, gettext, Category, Motion, MotionBlock, User, MotionCsvExport) {
- // set initial data for csv import
- $scope.motions = [];
-
- // set csv
- $scope.csvConfig = {
- accept: '.csv, .txt',
- encodingOptions: ['UTF-8', 'ISO-8859-1'],
- parseConfig: {
- skipEmptyLines: true,
- },
- };
-
- var FIELDS = ['identifier', 'title', 'text', 'reason', 'submitter', 'category', 'origin', 'motionBlock'];
- $scope.motions = [];
- $scope.onCsvChange = function (csv) {
- $scope.motions = [];
- var motions = [];
- _.forEach(csv.data, function (row) {
- if (row.length >= 3) {
- var filledRow = _.zipObject(FIELDS, row);
- motions.push(filledRow);
- }
- });
-
- _.forEach(motions, function (motion) {
- motion.selected = true;
- // identifier
- if (motion.identifier !== '') {
- // All motion objects are already loaded via the resolve statement from ui-router.
- var motions = Motion.getAll();
- if (_.find(motions, function (item) {
- return item.identifier === motion.identifier;
- })) {
- motion.importerror = true;
- motion.identifier_error = gettext('Error: Identifier already exists.');
- }
- }
- // title
- if (!motion.title) {
- motion.importerror = true;
- motion.title_error = gettext('Error: Title is required.');
- }
- // text
- if (!motion.text) {
- motion.importerror = true;
- motion.text_error = gettext('Error: Text is required.');
- } else if (!motion.text.startsWith('
')) {
- motion.text = '
' + motion.text + '
';
- }
- // Reason
- if (motion.reason && !motion.reason.startsWith('
')) {
- motion.reason = '
' + motion.reason + '
';
- }
- // submitter
- if (motion.submitter && motion.submitter !== '') {
- _.forEach(User.getAll(), function (user) {
- var user_short_name = [user.title, user.first_name, user.last_name].join(' ').trim();
- if (user_short_name == motion.submitter.trim()) {
- motion.submitters_id = [user.id];
- motion.submitter = user.full_name;
- }
- });
- if (!motion.submitters_id) {
- motion.submitter_create = gettext('New participant will be created.');
- }
- }
- // category
- if (motion.category && motion.category !== '') {
- angular.forEach(Category.getAll(), function (category) {
- // search for existing category
- if (category.name == motion.category.trim()) {
- motion.category_id = category.id;
- motion.category = category.name;
- }
- });
- if (!motion.category_id) {
- motion.category_create = gettext('New category will be created.');
- }
- }
- // Motion block
- if (motion.motionBlock && motion.motionBlock !== '') {
- angular.forEach(MotionBlock.getAll(), function (block) {
- // search for existing block
- if (block.title == motion.motionBlock.trim()) {
- motion.motion_block_id = block.id;
- motion.motionBlock = block.title;
- }
- });
- if (!motion.motion_block_id) {
- motion.motionBlock_create = gettext('New motion block will be created.');
- }
- }
-
- $scope.motions.push(motion);
- });
- $scope.calcStats();
- };
-
- $scope.calcStats = function () {
- $scope.motionsWillNotBeImported = 0;
- $scope.motionsWillBeImported = 0;
-
- $scope.motions.forEach(function(motion) {
- if (!motion.importerror && motion.selected) {
- $scope.motionsWillBeImported++;
- } else {
- $scope.motionsWillNotBeImported++;
- }
- });
- };
-
- // Counter for creations
- $scope.usersCreated = 0;
- $scope.categoriesCreated = 0;
-
- // import from csv file
- $scope.import = function () {
- $scope.csvImporting = true;
-
- // Reset counters
- $scope.usersCreated = 0;
- $scope.categoriesCreated = 0;
- $scope.motionBlocksCreated = 0;
-
- var importedUsers = [];
- var importedCategories = [];
- var importedMotionBlocks = [];
- // collect users, categories and motion blocks
- angular.forEach($scope.motions, function (motion) {
- if (motion.selected && !motion.importerror) {
- // collect user if not exists
- if (!motion.submitters_id && motion.submitter) {
- var index = motion.submitter.indexOf(' ');
- var user = {
- first_name: motion.submitter.substr(0, index),
- last_name: motion.submitter.substr(index+1),
- groups_id: []
- };
- importedUsers.push(user);
- }
- // collect category if not exists
- if (!motion.category_id && motion.category) {
- var category = {
- name: motion.category,
- prefix: motion.category.charAt(0)
- };
- importedCategories.push(category);
- }
- // collect motion block if not exists
- if (!motion.motion_block_id && motion.motionBlock) {
- var motionBlock = {
- title: motion.motionBlock,
- };
- importedMotionBlocks.push(motionBlock);
- }
- }
- });
-
- // unique users, categories and motion blocks
- var importedUsersUnique = _.uniqWith(importedUsers, function (u1, u2) {
- return u1.first_name == u2.first_name &&
- u1.last_name == u2.last_name;
- });
- var importedCategoriesUnique = _.uniqWith(importedCategories, function (c1, c2) {
- return c1.name == c2.name;
- });
- var importedMotionBlocksUnique = _.uniqWith(importedMotionBlocks, function (c1, c2) {
- return c1.title == c2.title;
- });
-
- // Promises for users and categories
- var createPromises = [];
-
- // create users and categories
- _.forEach(importedUsersUnique, function (user) {
- createPromises.push(User.create(user).then(
- function (success) {
- user.id = success.id;
- $scope.usersCreated++;
- }
- ));
- });
- _.forEach(importedCategoriesUnique, function (category) {
- createPromises.push(Category.create(category).then(
- function (success) {
- category.id = success.id;
- $scope.categoriesCreated++;
- }
- ));
- });
- _.forEach(importedMotionBlocksUnique, function (motionBlock) {
- createPromises.push(MotionBlock.create(motionBlock).then(
- function (success) {
- motionBlock.id = success.id;
- $scope.motionBlocksCreated++;
- }
- ));
- });
-
- // wait for users and categories to create
- $q.all(createPromises).then( function() {
- angular.forEach($scope.motions, function (motion) {
- if (motion.selected && !motion.importerror) {
- // now, add user
- if (!motion.submitters_id && motion.submitter) {
- var index = motion.submitter.indexOf(' ');
- var first_name = motion.submitter.substr(0, index);
- var last_name = motion.submitter.substr(index+1);
-
- // search for user, set id.
- _.forEach(importedUsersUnique, function (user) {
- if (user.first_name == first_name &&
- user.last_name == last_name) {
- motion.submitters_id = [user.id];
- }
- });
- }
- // add category
- if (!motion.category_id && motion.category) {
- var name = motion.category;
-
- // search for category, set id.
- _.forEach(importedCategoriesUnique, function (category) {
- if (category.name == name) {
- motion.category_id = category.id;
- }
- });
- }
- // add motion block
- if (!motion.motion_block_id && motion.motionBlock) {
- var title = motion.motionBlock;
-
- // search for motion block
- _.forEach(importedMotionBlocksUnique, function (motionBlock) {
- if (motionBlock.title == title) {
- motion.motion_block_id = motionBlock.id;
- }
- });
- }
-
-
- // finally create motion
- Motion.create(motion).then(
- function(success) {
- motion.imported = true;
- }
- );
- }
- });
- });
- $scope.csvimported = true;
- };
- $scope.clear = function () {
- $scope.motions = [];
- };
- // download CSV example file
- $scope.downloadCSVExample = function () {
- MotionCsvExport.downloadExample();
- };
- }
-])
-
-.controller('CategoryListCtrl', [
- '$scope',
- 'Category',
- 'ngDialog',
- 'CategoryForm',
- function($scope, Category, ngDialog, CategoryForm) {
- Category.bindAll({}, $scope, 'categories');
-
- // setup table sorting
- $scope.sortColumn = 'name';
- $scope.reverse = false;
- // function to sort by clicked column
- $scope.toggleSort = function (column) {
- if ($scope.sortColumn === column) {
- $scope.reverse = !$scope.reverse;
- }
- $scope.sortColumn = column;
- };
-
- // delete selected category
- $scope.delete = function (category) {
- Category.destroy(category.id);
- };
- $scope.editOrCreate = function (category) {
- ngDialog.open(CategoryForm.getDialog(category));
- };
- }
-])
-
-.controller('CategoryCreateCtrl', [
- '$scope',
- 'Category',
- 'CategoryForm',
- 'ErrorMessage',
- function($scope, Category, CategoryForm, ErrorMessage) {
- $scope.model = {};
- $scope.alert = {};
- $scope.formFields = CategoryForm.getFormFields();
- $scope.save = function (category) {
- Category.create(category).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('CategoryUpdateCtrl', [
- '$scope',
- 'Category',
- 'categoryId',
- 'CategoryForm',
- 'ErrorMessage',
- function ($scope, Category, categoryId, CategoryForm, ErrorMessage) {
- $scope.alert = {};
- $scope.model = angular.copy(Category.get(categoryId));
- $scope.formFields = CategoryForm.getFormFields();
- $scope.save = function (category) {
- Category.inject(category);
- Category.save(category).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original category object from server
- Category.refresh(category);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('CategorySortCtrl', [
- '$scope',
- '$stateParams',
- '$http',
- 'Category',
- 'categoryId',
- 'Motion',
- 'ErrorMessage',
- function ($scope, $stateParams, $http, Category, categoryId, Motion, ErrorMessage) {
- Category.bindOne(categoryId, $scope, 'category');
- Motion.bindAll({}, $scope, 'motions');
- $scope.filter = { category_id: categoryId,
- parent_id: null,
- orderBy: 'identifier' };
-
- $scope.$watch(function () {
- return Motion.lastModified();
- }, function () {
- var motions = Motion.filter($scope.filter);
- $scope.items = _.map(motions, function (motion) {
- return {
- id: motion.id,
- item: motion
- };
- });
- });
-
- $scope.alert = {};
- // Numbers all motions in this category by the given order in $scope.items
- $scope.numbering = function () {
- // Create a list of all motion ids in the current order.
- var sorted_motions = [];
- $scope.items.forEach(function (item) {
- sorted_motions.push(item.item.id);
- });
-
- // renumber them
- $http.post('/rest/motions/category/' + $scope.category.id + '/numbering/',
- {'motions': sorted_motions} ).then(
- function (success) {
- $scope.alert = { type: 'success', msg: success.data.detail, show: true };
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-//mark all motions config strings for translation in javascript
-.config([
- 'gettext',
- function (gettext) {
- gettext('Motions');
-
- // subgroup General
- gettext('General');
- gettext('Workflow of new motions');
- gettext('Identifier');
- gettext('Numbered per category');
- gettext('Serially numbered');
- gettext('Set it manually');
- gettext('Motion preamble');
- gettext('The assembly may decide:');
- gettext('Default line numbering');
- /// Line numbering: Outside
- gettext('Outside');
- /// Line numbering: Inline
- gettext('Inline');
- /// Line numbering: None
- gettext('None');
- gettext('Line length');
- gettext('The maximum number of characters per line. Relevant when line numbering is enabled. Min: 40');
- gettext('Hide reason on projector');
- gettext('Hide meta information box on projector');
- gettext('Hide recommendation on projector');
- gettext('Stop submitting new motions by non-staff users');
- gettext('Allow to disable versioning');
- gettext('Name of recommender');
- gettext('Default text version for change recommendations');
- gettext('Will be displayed as label before selected recommendation. Use an empty value to disable the recommendation system.');
- gettext('Edit comment %%comment%% of motion %%motion%%');
-
- // subgroup Amendments
- gettext('Amendments');
- gettext('Activate amendments');
- gettext('Show amendments together with motions');
- gettext('Prefix for the identifier for amendments');
- gettext('Apply text for new amendments');
- gettext('The title of the motion is always applied.');
- gettext('Amendment to');
- gettext('How to create new amendments');
- gettext('Empty text field');
- gettext('Edit the whole motion text');
- gettext('Paragraph-based, Diff-enabled');
-
- // subgroup Supporters
- gettext('Supporters');
- gettext('Number of (minimum) required supporters for a motion');
- gettext('Choose 0 to disable the supporting system.');
- gettext('Remove all supporters of a motion if a submitter edits his ' +
- 'motion in early state');
-
- // subgroup Supporters
- gettext('Comments');
- gettext('Comment fields for motions');
- gettext('Public');
- gettext('Private');
-
- // subgroup Voting and ballot papers
- gettext('Voting and ballot papers');
- gettext('The 100 % base of a voting result consists of');
- gettext('Yes/No/Abstain');
- gettext('Yes/No');
- gettext('All valid ballots');
- gettext('All casted ballots');
- gettext('Disabled (no percents)');
- gettext('Required majority');
- gettext('Default method to check whether a motion has reached the required majority.');
- gettext('Simple majority');
- gettext('Two-thirds majority');
- gettext('Three-quarters majority');
- gettext('Disabled');
- gettext('Number of ballot papers (selection)');
- gettext('Number of all delegates');
- gettext('Number of all participants');
- gettext('Use the following custom number');
- gettext('Custom number of ballot papers');
-
- // subgroup PDF and DOCX
- gettext('Title for PDF and DOCX documents (all motions)');
- gettext('Preamble text for PDF and DOCX documents (all motions)');
- gettext('Sort categories by');
- gettext('Include the sequential number in PDF and DOCX');
-
- // misc strings (used dynamically in templates by translate filter)
- gettext('needed');
- gettext('Amendment');
- }
-]);
-
-}());
diff --git a/openslides/motions/static/js/motions/workflow.js b/openslides/motions/static/js/motions/workflow.js
deleted file mode 100644
index 79ace06ed..000000000
--- a/openslides/motions/static/js/motions/workflow.js
+++ /dev/null
@@ -1,253 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.motions.workflow', [])
-
-.controller('WorkflowListCtrl', [
- '$scope',
- 'Workflow',
- 'ngDialog',
- 'ErrorMessage',
- function ($scope, Workflow, ngDialog, ErrorMessage) {
- $scope.alert = {};
- Workflow.bindAll({}, $scope, 'workflows');
- $scope.create = function () {
- ngDialog.open({
- template: 'static/templates/motions/workflow-edit.html',
- controller: 'WorkflowCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- });
- };
- $scope.delete = function (workflow) {
- Workflow.destroy(workflow).then(null, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('WorkflowDetailCtrl', [
- '$scope',
- '$sessionStorage',
- 'permissions',
- 'Workflow',
- 'MotionState',
- 'workflowId',
- 'ngDialog',
- 'gettext',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, $sessionStorage, permissions, Workflow, MotionState, workflowId,
- ngDialog, gettext, gettextCatalog, ErrorMessage) {
- $scope.permissions = permissions;
- $scope.alert = {};
-
- $scope.$watch(function () {
- return Workflow.lastModified(workflowId);
- }, function () {
- $scope.workflow = Workflow.get(workflowId);
- $scope.states = $scope.workflow.states;
- $scope.states = _.orderBy($scope.states, 'id');
- _.forEach($scope.states, function (state) {
- state.newActionWord = gettextCatalog.getString(state.action_word);
- state.newRecommendationLabel = gettextCatalog.getString(state.recommendation_label);
- });
- });
-
- $scope.booleanMembers = [
- {name: 'allow_support',
- displayName: gettext('Allow support'),},
- {name: 'allow_create_poll',
- displayName: gettext('Allow create poll'),},
- {name: 'allow_submitter_edit',
- displayName: gettext('Allow submitter edit'),},
- {name: 'versioning',
- displayName: gettext('Versioning'),},
- {name: 'leave_old_version_active',
- displayName: gettext('Leave old version active'),},
- {name: 'dont_set_identifier',
- displayName: gettext('Set identifier'),
- inverse: true,},
- {name: 'show_state_extension_field',
- displayName: gettext('Show state extension field'),},
- {name: 'show_recommendation_extension_field',
- displayName: gettext('Show recommendation extension field'),}
- ];
- $scope.cssClasses = {
- 'danger': gettext('Red'),
- 'success': gettext('Green'),
- 'warning': gettext('Yellow'),
- 'default': gettext('Grey'),
- 'primary': gettext('Blue'),
- };
- $scope.getPermissionDisplayName = function (permission) {
- if (permission) {
- return _.find($scope.permissions, function (perm) {
- return perm.value === permission;
- }).display_name;
- }
- };
- $scope.clickPermission = function (state, permission) {
- state.required_permission_to_see =
- state.required_permission_to_see === permission.value ? '' : permission.value;
- $scope.save(state);
- };
- $scope.xor = function (a, b) {
- return (a && !b) || (!a && b);
- };
-
- $scope.changeBooleanMember = function (state, memberName) {
- state[memberName] = !state[memberName];
- $scope.save(state);
- };
- $scope.setMember = function (state, member, value) {
- state[member] = value;
- $scope.save(state);
- };
- $scope.clickNextStateEntry = function (state, clickedStateId) {
- var index = state.next_states_id.indexOf(clickedStateId);
- if (index > -1) { // remove now
- state.next_states_id.splice(index, 1);
- } else { // add
- state.next_states_id.push(clickedStateId);
- }
- $scope.save(state);
- };
- $scope.save = function (state) {
- MotionState.save(state).then(null, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- // Save expand state so the session
- if ($sessionStorage.motionStateTableExpandState) {
- $scope.toggleExpandContent();
- }
- $scope.saveExpandState = function (state) {
- $sessionStorage.motionStateTableExpandState = state;
- };
-
- $scope.openStateDialog = function (state) {
- ngDialog.open({
- template: 'static/templates/motions/state-edit.html',
- controller: state ? 'StateRenameCtrl' : 'StateCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- state: function () {return state;},
- workflow: function () {return $scope.workflow;},
- }
- });
- };
- $scope.openWorkflowDialog = function () {
- ngDialog.open({
- template: 'static/templates/motions/workflow-edit.html',
- controller: 'WorkflowRenameCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- workflow: function () {return $scope.workflow;},
- }
- });
- };
-
- $scope.delete = function (state) {
- MotionState.destroy(state).then(null, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('WorkflowCreateCtrl', [
- '$scope',
- 'Workflow',
- 'ErrorMessage',
- function ($scope, Workflow, ErrorMessage) {
- $scope.save = function () {
- var workflow = {
- name: $scope.newName,
- };
- Workflow.create(workflow).then(function (success) {
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('WorkflowRenameCtrl', [
- '$scope',
- 'workflow',
- 'Workflow',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, workflow, Workflow, gettextCatalog, ErrorMessage) {
- $scope.workflow = workflow;
- $scope.newName = gettextCatalog.getString(workflow.name);
- $scope.save = function () {
- workflow.name = $scope.newName;
- Workflow.save(workflow).then(function (success) {
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('StateCreateCtrl', [
- '$scope',
- 'workflow',
- 'MotionState',
- 'ErrorMessage',
- function ($scope, workflow, MotionState, ErrorMessage) {
- $scope.newName = '';
- $scope.actionWord = '';
- $scope.save = function () {
- var state = {
- name: $scope.newName,
- action_word: $scope.actionWord,
- workflow_id: workflow.id,
- allow_create_poll: true,
- allow_support: true,
- allow_submitter_edit: true,
- };
- MotionState.create(state).then(function () {
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-])
-
-.controller('StateRenameCtrl', [
- '$scope',
- 'MotionState',
- 'state',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, MotionState, state, gettextCatalog, ErrorMessage) {
- $scope.state = state;
- $scope.newName = gettextCatalog.getString(state.name);
- $scope.actionWord = gettextCatalog.getString(state.action_word);
- $scope.save = function () {
- state.name = $scope.newName;
- state.action_word = $scope.actionWord;
- MotionState.save(state).then(function () {
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- }
-]);
-
-}());
diff --git a/openslides/motions/static/templates/motions/amendment-paragraph-choose-form.html b/openslides/motions/static/templates/motions/amendment-paragraph-choose-form.html
deleted file mode 100644
index c4108f1a3..000000000
--- a/openslides/motions/static/templates/motions/amendment-paragraph-choose-form.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
Please choose the paragraph to amend
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/category-form.html b/openslides/motions/static/templates/motions/category-form.html
deleted file mode 100644
index 50683e1d8..000000000
--- a/openslides/motions/static/templates/motions/category-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
Edit category
-
New category
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/category-list.html b/openslides/motions/static/templates/motions/category-list.html
deleted file mode 100644
index 489c98c1c..000000000
--- a/openslides/motions/static/templates/motions/category-list.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
- Name
-
-
-
- Prefix
-
-
-
-
-
- {{ category.name }}
-
- {{ category.prefix }}
-
-
diff --git a/openslides/motions/static/templates/motions/category-sort.html b/openslides/motions/static/templates/motions/category-sort.html
deleted file mode 100644
index 2d9e08cac..000000000
--- a/openslides/motions/static/templates/motions/category-sort.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
- Drag and drop motions to reorder the category. Then click the button to renumber.
-
-
-
- Numbering
-
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/change-recommendation-form.html b/openslides/motions/static/templates/motions/change-recommendation-form.html
deleted file mode 100644
index 7ed470e85..000000000
--- a/openslides/motions/static/templates/motions/change-recommendation-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
Edit change recommendation
-
New change recommendation
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-amendment-list.html b/openslides/motions/static/templates/motions/motion-amendment-list.html
deleted file mode 100644
index 3de76eb7a..000000000
--- a/openslides/motions/static/templates/motions/motion-amendment-list.html
+++ /dev/null
@@ -1,414 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- Select ...
-
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
-
-
-
-
-
-
-
- --- Select action ---
- Delete
- Set status
- Set category
- Set motion block
-
-
-
- --- Select state ---
-
- {{ (state.workflowHeader ? state.headername : state.name) | translate }}
-
-
-
-
- Set status
-
-
-
- --- Select category ---
-
- {{ category.prefix }} – {{ category.name }}
-
- No category
-
-
-
- Set category
-
-
-
- --- Select motion block ---
-
- {{ motionBlock.title }}
-
- No motion block
-
-
-
- Set motion block
-
-
-
-
- Delete selected amendments
-
-
-
-
-
-
- {{ amendmentsFiltered.length }} /
- {{ amendments.length }}
- amendments ,
- {{(amendments|filter:{selected:true}).length}} {{ "selected" | translate }}
-
-
-
- Page {{ pagination.currentPage }} /
- {{ Math.ceil(amendmentsFiltered.length/pagination.itemsPerPage) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ amendment.getStateName() }}
-
-
-
-
-
-
-
-
-
- by
-
- {{ submitter.user.get_full_name() }}, ,
- ... [+{{ amendment.submitters.length - 1 }}]
-
-
-
-
-
-
-
-
-
-
-
- No changes at the text.
-
-
-
-
- {{ getTextPreview(amendment.getText(), 400) }}
-
-
-
-
-
-
-
-
- {{ field.name }}
-
-
- {{ getTextPreview(amendment.comments[id], 30) }}
-
-
-
-
-
-
- Create modified amendment
-
-
-
-
-
-
-
- {{ amendment.supporters.length }}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-block-detail.html b/openslides/motions/static/templates/motions/motion-block-detail.html
deleted file mode 100644
index 2a8c119e2..000000000
--- a/openslides/motions/static/templates/motions/motion-block-detail.html
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-block-form.html b/openslides/motions/static/templates/motions/motion-block-form.html
deleted file mode 100644
index f069e703f..000000000
--- a/openslides/motions/static/templates/motions/motion-block-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
Edit motion block
-
New motion block
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-block-list.html b/openslides/motions/static/templates/motions/motion-block-list.html
deleted file mode 100644
index 58362a7a3..000000000
--- a/openslides/motions/static/templates/motions/motion-block-list.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-comment-form.html b/openslides/motions/static/templates/motions/motion-comment-form.html
deleted file mode 100644
index 8f65843db..000000000
--- a/openslides/motions/static/templates/motions/motion-comment-form.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
{{ title }}
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail.html b/openslides/motions/static/templates/motions/motion-detail.html
deleted file mode 100644
index 078582ef2..000000000
--- a/openslides/motions/static/templates/motions/motion-detail.html
+++ /dev/null
@@ -1,666 +0,0 @@
-
-
-
-
-
-
- Meta information
-
-
-
-
-
-
-
-
-
-
Submitters
-
- Submitters
-
-
-
-
-
- {{ submitter.user.get_full_name() }}
-
-
-
-
-
Supporters
-
-
- {{ supporters.get_full_name() }}
-
-
-
-
- Support motion
-
-
-
-
- Unsupport motion
-
-
-
-
-
-
-
-
-
State
-
-
-
- State
-
-
-
-
-
-
- {{ motion.getStateName() }}
-
-
- {{ commentsFields[commentFieldForStateId].name }}
-
-
-
-
-
-
-
-
-
-
-
- {{ config('motions_recommendations_by') }}
-
-
-
-
- {{ config('motions_recommendations_by') | translate }}
-
-
-
-
-
-
- {{ motion.getRecommendationName() }}
-
-
-
- {{ commentsFields[commentFieldForRecommendationId].name }}
-
-
-
-
-
-
-
-
-
-
-
- Motion
-
-
-
-
-
-
-
- Follow recommendation
-
-
-
-
-
Category
-
-
-
- Category
-
-
-
-
-
-
- {{ motion.category.prefix }} – {{ motion.category.name }}
-
-
-
-
Motion block
-
-
-
- Motion block
-
-
-
-
-
-
{{ motion.motionBlock.title }}
-
{{ motion.motionBlock.title }}
-
-
-
Tags
-
-
-
- Tags
-
-
-
-
-
-
- {{ tag.name }}{{$last ? '' : ', '}}
-
-
-
-
Origin
- {{ motion.origin }}
-
-
-
-
Voting result
-
-
-
- Vote
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Yes :
-
- {{ voteYes.value | number:votesPrecision }} {{ voteYes.percentStr }}
-
-
-
-
-
-
-
-
-
- No :
-
- {{ voteNo.value | number:votesPrecision }} {{ voteNo.percentStr }}
-
-
-
-
-
-
-
- ∅
-
- Abstain :
-
- {{ voteAbstain.value | number:votesPrecision }} {{ voteAbstain.percentStr }}
-
-
-
-
-
-
-
-
-
- Valid votes :
-
- {{ votesValid.value | number:votesPrecision }} {{ votesValid.percentStr }}
-
-
-
-
-
-
- Invalid votes :
-
- {{ votesInvalid.value | number:votesPrecision }} {{ votesInvalid.percentStr }}
-
-
-
-
- ∑
-
- Votes cast :
-
- {{ votesCast.value | number:votesPrecision }} {{ votesCast.percentStr }}
-
-
-
-
-
-
-
-
- Required majority :
-
-
-
-
-
-
-
-
- Quorum ({{ (voteYes.value - isReached()) | number:votesPrecision }}) reached.
-
-
- Quorum ({{ (voteYes.value - isReached()) | number:votesPrecision }}) not reached.
-
-
-
-
-
-
-
-
-
- New vote
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ config('motions_preamble') | translate }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- New version on these changes
-
-
-
-
-
-
-
-
-
- At least two amendments or change recommendations affecting the same line are to be integrated.
- This leads to undeterministic results.
- Please resolve this conflict by not accepting multiple changes affecting the same line.
-
-
-
-
-
-
- Create final print template
-
-
-
-
-
-
- New version on these changes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Attachments
-
-
-
-
-
-
-
-
- Show history
-
-
-
-
-
- {{ message.message }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/amendment-paragraph-diff.html b/openslides/motions/static/templates/motions/motion-detail/amendment-paragraph-diff.html
deleted file mode 100644
index 5af81f791..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/amendment-paragraph-diff.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
- No changes at the text.
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/change-summary.html b/openslides/motions/static/templates/motions/motion-detail/change-summary.html
deleted file mode 100644
index 59491881d..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/change-summary.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
- Summary of changes :
-
-
-
-
- Reject all change recommendations
-
-
-
-
-
- No change recommendations yet
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/comments.html b/openslides/motions/static/templates/motions/motion-detail/comments.html
deleted file mode 100644
index ed12dcf35..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/comments.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/personal-note.html b/openslides/motions/static/templates/motions/motion-detail/personal-note.html
deleted file mode 100644
index 34f1e685a..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/personal-note.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/toolbar-line-numbering.html b/openslides/motions/static/templates/motions/motion-detail/toolbar-line-numbering.html
deleted file mode 100644
index 16bff7cd4..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/toolbar-line-numbering.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
- Line numbering :
-
-
-
- none
-
-
-
- inline
-
-
-
- outside
-
-
-
-
-
-
- Line numbering
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/toolbar.html b/openslides/motions/static/templates/motions/motion-detail/toolbar.html
deleted file mode 100644
index 5986ab95a..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/toolbar.html
+++ /dev/null
@@ -1,154 +0,0 @@
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/view-diff.html b/openslides/motions/static/templates/motions/motion-detail/view-diff.html
deleted file mode 100644
index 5575abcf0..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/view-diff.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
- Rejected :
-
-
-
-
New title :
-
{{ title_change_recommendation.text }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Rejected :
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/view-modified-agreed.html b/openslides/motions/static/templates/motions/motion-detail/view-modified-agreed.html
deleted file mode 100644
index 957269966..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/view-modified-agreed.html
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
- Delete final print template
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-detail/view-original.html b/openslides/motions/static/templates/motions/motion-detail/view-original.html
deleted file mode 100644
index 8f2531878..000000000
--- a/openslides/motions/static/templates/motions/motion-detail/view-original.html
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-export-form.html b/openslides/motions/static/templates/motions/motion-export-form.html
deleted file mode 100644
index f0fefa826..000000000
--- a/openslides/motions/static/templates/motions/motion-export-form.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
Export motions
-
Export motion
-
Export motion "{{ motions.getTitle() }}"
-
-
diff --git a/openslides/motions/static/templates/motions/motion-form.html b/openslides/motions/static/templates/motions/motion-form.html
deleted file mode 100644
index 32f862997..000000000
--- a/openslides/motions/static/templates/motions/motion-form.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
Edit motion
-
New motion
-
New amendment to motion {{ parent.identifier || parent.getTitle() }}
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-import.html b/openslides/motions/static/templates/motions/motion-import.html
deleted file mode 100644
index 8af7b7560..000000000
--- a/openslides/motions/static/templates/motions/motion-import.html
+++ /dev/null
@@ -1,143 +0,0 @@
-
-
-
-
-
Select a CSV file
-
-
-
Please note:
-
- Required comma or semicolon separated values with these column header names in the first row :
-
- Identifier ,
- Title ,
- Text ,
- Reason ,
- Submitter ,
- Category ,
- Origin ,
- Motion block
-
- Identifier, reason, submitter, category, origin and motion block are optional and may be empty.
- Additional columns after the required ones may be present and won't affect the import.
- Only double quotes are accepted as text delimiter (no single quotes).
- Download CSV example file
-
-
-
-
Preview
-
-
-
-
- {{ motionsWillNotBeImported }}
- motions will be not imported.
-
-
-
- {{ motionsWillBeImported }}
- motions will be imported.
-
-
-
-
-
- {{ motionsImported.length }}
- motions were successfully imported.
- (Users created : {{ usersCreated }},
- Categories created : {{ categoriesCreated }},
- Motion blocks created : {{ motionBlocksCreated }})
-
-
-
-
- Clear preview
-
-
- Import {{ motionsWillBeImported }} motions
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-list.html b/openslides/motions/static/templates/motions/motion-list.html
deleted file mode 100644
index 4a7863656..000000000
--- a/openslides/motions/static/templates/motions/motion-list.html
+++ /dev/null
@@ -1,466 +0,0 @@
-
-
-
-
-
-
-
-
- Select ...
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
-
-
-
-
- --- Select action ---
- Delete
- Set status
- Set category
- Set motion block
-
-
-
- --- Select state ---
-
- {{ (state.workflowHeader ? state.headername : state.name) | translate }}
-
-
-
-
- Set status
-
-
-
- --- Select category ---
-
- {{ category.prefix }} – {{ category.name }}
-
- No category
-
-
-
- Set category
-
-
-
- --- Select motion block ---
-
- {{ motionBlock.title }}
-
- No motion block
-
-
-
- Set motion block
-
-
-
-
- Delete selected motions
-
-
-
-
-
-
- {{ motionsFiltered.length }} /
- {{ motions.length }}
- motions ,
- {{(motions|filter:{selected:true}).length}} {{ "selected" | translate }}
-
-
-
-
- Page {{ pagination.currentPage }} /
- {{ pagination.getPageCount(motionsFiltered) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ motion.identifier }}
-
-
-
-
-
-
-
-
-
- {{ motion.getStateName() }}
-
-
-
-
-
-
-
-
-
-
-
- {{ motion.getRecommendationName() }}
-
-
-
-
-
-
-
-
-
-
- by
-
- {{ submitter.user.get_full_name() }}, ,
- ... [+{{ motion.submitters.length - 1 }}]
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ motion.category.prefix }} – {{ motion.category.name }}
-
-
-
-
-
-
-
-
-
- {{ motion.category.prefix }} – {{ motion.category.name }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ motion.motionBlock.title }}
-
-
-
-
-
-
-
-
-
- {{ motion.motionBlock.title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ tag.name }},
-
-
-
-
-
-
-
-
-
-
-
- {{ tag.name }},
-
-
-
-
-
-
-
-
- {{ motion.origin | limitTo:25 }}{{ motion.origin.length > 25 ? '...' : '' }}
-
-
-
-
-
-
-
-
-
- {{ motion.supporters.length }}
-
-
-
-
-
-
{{ motion.agenda_item.getItemNumberWithAncestors() }}
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-poll-form.html b/openslides/motions/static/templates/motions/motion-poll-form.html
deleted file mode 100644
index 9e790e3c1..000000000
--- a/openslides/motions/static/templates/motions/motion-poll-form.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
Vote {{ voteNumber }}
-
-
- {{ alert.msg }}
-
-
-
- Special values :
- -1 = majority
- -2 = undocumented
-
-
diff --git a/openslides/motions/static/templates/motions/motion-submitters.html b/openslides/motions/static/templates/motions/motion-submitters.html
deleted file mode 100644
index a5e4d0a36..000000000
--- a/openslides/motions/static/templates/motions/motion-submitters.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
- {{ $index + 1 }}.
- {{ submitter.user.get_full_name() }}
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/motion-table-filters.html b/openslides/motions/static/templates/motions/motion-table-filters.html
deleted file mode 100644
index 82a21c507..000000000
--- a/openslides/motions/static/templates/motions/motion-table-filters.html
+++ /dev/null
@@ -1,357 +0,0 @@
-
-
-
-
- State
-
-
-
-
-
-
-
- Recommendation
-
-
-
-
-
-
-
- Category
-
-
-
-
-
-
-
- Motion block
-
-
-
-
-
-
-
-
-
-
-
-
- Tag
-
-
-
-
-
-
-
- Misc
-
-
-
-
-
-
-
- Sort
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- All Filters
-
-
-
-
-
- {{ state.name | translate }}
-
-
-
-
- done
-
-
-
- undone
-
-
-
-
-
- {{ category.prefix }} – {{ category.name }}
-
-
-
-
- No category set
-
-
-
-
-
- {{ motionBlock.title }}
-
-
-
-
-
-
- {{ commentsField.name }}
-
-
-
-
- No comments set
-
-
-
-
-
- {{ recommendation.recommendation_label | translate }}
-
-
-
-
- No motion block set
-
-
-
-
-
- {{ tag.name }}
-
-
-
-
- No tag set
-
-
-
-
-
- {{ booleanFilter.value ? booleanFilter.choiceYes : booleanFilter.choiceNo | translate }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/slide_motion.html b/openslides/motions/static/templates/motions/slide_motion.html
deleted file mode 100644
index 564d655ed..000000000
--- a/openslides/motions/static/templates/motions/slide_motion.html
+++ /dev/null
@@ -1,171 +0,0 @@
-
-
-
-
State
- {{ motion.getStateName() }}
-
-
-
-
{{ config('motions_recommendations_by') }}
- {{ motion.getRecommendationName() }}
-
-
-
-
Submitters
-
- {{ submitter.user.get_full_name() }},
-
-
-
-
Voting result
-
-
-
- Vote {{ motion.polls.length - $index }}:
-
-
-
-
-
-
-
- Yes :
-
- {{ voteYes.value | number:getPollVotesPrecision(poll) }} {{ voteYes.percentStr }}
-
-
-
-
-
-
-
-
-
- No :
-
- {{ voteNo.value | number:getPollVotesPrecision(poll) }} {{ voteNo.percentStr }}
-
-
-
-
-
-
-
- ∅
-
- Abstain :
-
- {{ voteAbstain.value | number:getPollVotesPrecision(poll) }} {{ voteAbstain.percentStr }}
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ motion.getTitleWithChanges(mode) }}
-
- Motion {{ motion.identifier }}
- | Version {{ motion.getVersion().version_number }}
-
-
-
- (Line {{ paragraph.diffLineFrom }})
-
-
- (Line {{ paragraph.diffLineFrom }}-{{ paragraph.diffLineTo }})
-
-
-
-
-
-
-
-
-
{{ config('motions_preamble') | translate }}
-
-
-
-
-
-
-
-
-
-
- New title :
-
-
{{ title_change_recommendation.text }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/slide_motion_block.html b/openslides/motions/static/templates/motions/slide_motion_block.html
deleted file mode 100644
index 6ccdc555c..000000000
--- a/openslides/motions/static/templates/motions/slide_motion_block.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
{{ motionBlock.agenda_item.getTitle() }}
- Motion block — {{motionBlock.motions.length }} Motions
-
-
-
-
-
- {{ motion.identifier }}:
- {{ getShortTitle(motion) }}
-
-
- {{ motion.getRecommendationName() }}
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/state-edit.html b/openslides/motions/static/templates/motions/state-edit.html
deleted file mode 100644
index 37a4f960b..000000000
--- a/openslides/motions/static/templates/motions/state-edit.html
+++ /dev/null
@@ -1,28 +0,0 @@
-
Edit state
-
Create new state
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/workflow-detail.html b/openslides/motions/static/templates/motions/workflow-detail.html
deleted file mode 100644
index c59e31dd9..000000000
--- a/openslides/motions/static/templates/motions/workflow-detail.html
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-
-
- {{ alert.msg }}
-
-
-
-
-
- Permissions
-
-
- {{ state.name | translate }}
-
-
- {{ state.name | translate | limitTo: 1 }}...
-
-
-
-
-
-
-
-
- Action word
-
-
-
-
-
- {{ state.action_word | translate }}
-
-
- —
-
-
-
-
-
-
-
-
- Recommendation label
-
-
-
-
-
- {{ state.recommendation_label | translate }}
-
-
- —
-
-
-
-
-
-
-
-
- {{ member.displayName | translate }}
-
-
-
-
-
-
-
-
- Label color
-
-
-
-
-
- {{ cssClasses[state.css_class] | translate }}
-
-
-
-
-
-
-
-
-
- Required permission to see
-
-
-
-
-
-
- {{ getPermissionDisplayName(state.required_permission_to_see) | translate }}
-
-
- —
-
-
-
-
-
-
-
-
-
-
- Next states
-
-
-
- —
-
-
-
- {{ nextState.name | translate }},
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/motions/static/templates/motions/workflow-edit.html b/openslides/motions/static/templates/motions/workflow-edit.html
deleted file mode 100644
index 4772757ba..000000000
--- a/openslides/motions/static/templates/motions/workflow-edit.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
Edit name
-
Create new workflow
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/motions/static/templates/motions/workflow-list.html b/openslides/motions/static/templates/motions/workflow-list.html
deleted file mode 100644
index 5abb8a7bd..000000000
--- a/openslides/motions/static/templates/motions/workflow-list.html
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
- {{ alert.msg }}
-
-
-
-
-
- Name
-
-
-
-
-
-
- {{ workflow.name | translate }}
-
-
-
-
-
-
diff --git a/openslides/motions/urls.py b/openslides/motions/urls.py
deleted file mode 100644
index 277e22dce..000000000
--- a/openslides/motions/urls.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.conf.urls import url
-
-from . import views
-
-
-urlpatterns = [
- url(r'^docxtemplate/$',
- views.MotionDocxTemplateView.as_view(),
- name='motions_docx_template'),
-]
diff --git a/openslides/motions/views.py b/openslides/motions/views.py
index 1e1ca0f6a..af0132f03 100644
--- a/openslides/motions/views.py
+++ b/openslides/motions/views.py
@@ -26,7 +26,6 @@ from ..utils.rest_api import (
detail_route,
list_route,
)
-from ..utils.views import BinaryTemplateView
from .access_permissions import (
CategoryAccessPermissions,
MotionAccessPermissions,
@@ -1016,12 +1015,3 @@ class StateViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Generi
msg = self.getProtectedErrorMessage('workflow', e)
raise ValidationError({'detail': msg})
return result
-
-
-# Special views
-
-class MotionDocxTemplateView(BinaryTemplateView):
- """
- Returns the template for motions docx export
- """
- template_name = 'templates/docx/motions.docx'
diff --git a/openslides/old_urls.py b/openslides/old_urls.py
deleted file mode 100644
index 428e0347b..000000000
--- a/openslides/old_urls.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from django.conf import settings
-from django.conf.urls import include, url
-from django.contrib.staticfiles.urls import urlpatterns
-from django.views.generic import RedirectView
-
-from openslides.core import views as core_views
-from openslides.mediafiles.views import protected_serve
-from openslides.utils.plugins import get_all_plugin_urlpatterns
-from openslides.utils.rest_api import router
-
-
-urlpatterns += get_all_plugin_urlpatterns()
-
-urlpatterns += [
- url(r'^%s(?P
.*)$' % settings.MEDIA_URL.lstrip('/'), protected_serve, {'document_root': settings.MEDIA_ROOT}),
- url(r'^(?P.*[^/])$', RedirectView.as_view(url='/%(url)s/', permanent=True)),
- url(r'^rest/', include(router.urls)),
- url(r'^agenda/', include('openslides.agenda.urls')),
- url(r'^motions/', include('openslides.motions.urls')),
- url(r'^users/', include('openslides.users.urls')),
- url(r'^core/', include('openslides.core.urls')),
- # The old angular webclient
- # TODO: Change me or at least my comment
- url(r'^webclient/(?Psite|projector)/$',
- core_views.WebclientJavaScriptView.as_view(),
- name='core_webclient_javascript'),
-
- # View for the projectors are handled by angular.
- url(r'^projector/(\d+)/$', core_views.ProjectorView.as_view()),
-
- # Original view without resolutioncontrol for the projectors are handled by angular.
- url(r'^real-projector/(\d+)/$', core_views.RealProjectorView.as_view()),
-
- # Main entry point for all angular pages.
- # Has to be the last entry in the urls.py
- url(r'^.*$', core_views.IndexView.as_view(), name="index"),
-]
diff --git a/openslides/poll/static/js/poll/majority.js b/openslides/poll/static/js/poll/majority.js
deleted file mode 100644
index f2461183e..000000000
--- a/openslides/poll/static/js/poll/majority.js
+++ /dev/null
@@ -1,41 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.poll.majority', [])
-
-.value('MajorityMethodChoices', [
- {'value': 'simple_majority', 'display_name': 'Simple majority'},
- {'value': 'two-thirds_majority', 'display_name': 'Two-thirds majority'},
- {'value': 'three-quarters_majority', 'display_name': 'Three-quarters majority'},
- {'value': 'disabled', 'display_name': 'Disabled'},
-])
-
-.factory('MajorityMethods', [
- function () {
- return {
- 'simple_majority': function (vote, base) {
- return Math.ceil(-(base / 2 - vote)) - 1;
- },
- 'two-thirds_majority': function (vote, base) {
- var result = -(base * 2 - vote * 3) / 3;
- if (result % 1 !== 0) {
- result = Math.ceil(result) - 1;
- }
- return result;
- },
- 'three-quarters_majority': function (vote, base) {
- var result = -(base * 3 - vote * 4) / 4;
- if (result % 1 !== 0) {
- result = Math.ceil(result) - 1;
- }
- return result;
- },
- 'disabled': function () {
- return undefined;
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/topics/static/js/topics/base.js b/openslides/topics/static/js/topics/base.js
deleted file mode 100644
index c0491dedf..000000000
--- a/openslides/topics/static/js/topics/base.js
+++ /dev/null
@@ -1,48 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.topics', [])
-
-.factory('Topic', [
- 'DS',
- 'jsDataModel',
- 'gettext',
- function(DS, jsDataModel, gettext) {
- var name = 'topics/topic';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Topic'),
- methods: {
- getResourceName: function () {
- return name;
- },
- getAgendaTitle: function () {
- return this.title;
- },
- getCSVExportText: function () {
- return this.text;
- },
- },
- relations: {
- belongsTo: {
- 'agenda/item': {
- localKey: 'agenda_item_id',
- localField: 'agenda_item',
- }
- },
- hasMany: {
- 'mediafiles/mediafile': {
- localField: 'attachments',
- localKeys: 'attachments_id',
- }
- }
- }
- });
- }
-])
-
-.run(['Topic', function(Topic) {}]);
-
-}());
diff --git a/openslides/topics/static/js/topics/csv.js b/openslides/topics/static/js/topics/csv.js
deleted file mode 100644
index 68fa7e9e8..000000000
--- a/openslides/topics/static/js/topics/csv.js
+++ /dev/null
@@ -1,32 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.topics.csv', [])
-
-.factory('TopicsCsvExample', [
- 'gettextCatalog',
- 'CsvDownload',
- function (gettextCatalog, CsvDownload) {
- var makeHeaderline = function () {
- var headerline = ['Title', 'Text', 'Duration', 'Comment', 'Internal item'];
- return _.map(headerline, function (entry) {
- return gettextCatalog.getString(entry);
- });
- };
- return {
- downloadExample: function () {
- var csvRows = [makeHeaderline(),
- // example entries
- ['Demo 1', 'Demo text 1', '1:00', 'test comment', ''],
- ['Break', '', '0:10', '', '1'],
- ['Demo 2', 'Demo text 2', '1:30', '', '']
-
- ];
- CsvDownload(csvRows, gettextCatalog.getString('agenda-example') + '.csv');
- },
- };
- }
-]);
-
-}());
diff --git a/openslides/topics/static/js/topics/projector.js b/openslides/topics/static/js/topics/projector.js
deleted file mode 100644
index e910351c1..000000000
--- a/openslides/topics/static/js/topics/projector.js
+++ /dev/null
@@ -1,28 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.topics.projector', ['OpenSlidesApp.topics'])
-
-.config([
- 'slidesProvider',
- function (slidesProvider) {
- slidesProvider.registerSlide('topics/topic', {
- template: 'static/templates/topics/slide_topic.html'
- });
- }
-])
-
-.controller('SlideTopicCtrl', [
- '$scope',
- 'Topic',
- function($scope, Topic) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- Topic.bindOne(id, $scope, 'topic');
- }
-]);
-
-})();
diff --git a/openslides/topics/static/js/topics/site.js b/openslides/topics/static/js/topics/site.js
deleted file mode 100644
index 627bee0a7..000000000
--- a/openslides/topics/static/js/topics/site.js
+++ /dev/null
@@ -1,369 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.topics.site', ['OpenSlidesApp.topics', 'OpenSlidesApp.topics.csv'])
-
-.config([
- '$stateProvider',
- 'gettext',
- function($stateProvider, gettext) {
- $stateProvider
- .state('topics', {
- url: '/topics',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Topics'),
- },
- })
- .state('topics.topic', {
- abstract: true,
- template: " ",
- })
- .state('topics.topic.detail', {
- resolve: {
- topicId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }],
- }
- })
- // redirects to topic detail and opens topic edit form dialog, uses edit url,
- // used by ui-sref links from agenda only
- // (from topic controller use TopicForm factory instead to open dialog in front
- // of current view without redirect)
- .state('topics.topic.detail.update', {
- onEnter: ['$stateParams', '$state', 'ngDialog',
- function($stateParams, $state, ngDialog) {
- ngDialog.open({
- template: 'static/templates/topics/topic-form.html',
- controller: 'TopicUpdateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- topicId: function() {
- return $stateParams.id;
- },
- },
- preCloseCallback: function() {
- $state.go('topics.topic.detail', {topic: $stateParams.id});
- return true;
- }
- });
- }],
- })
- .state('topics.topic.import', {
- url: '/import',
- controller: 'TopicImportCtrl',
- });
- }
-])
-
-.factory('TopicForm', [
- '$filter',
- 'gettextCatalog',
- 'operator',
- 'Editor',
- 'Mediafile',
- 'Agenda',
- 'AgendaTree',
- 'ShowAsAgendaItemField',
- function ($filter, gettextCatalog, operator, Editor, Mediafile, Agenda,
- AgendaTree, ShowAsAgendaItemField) {
- return {
- // ngDialog for topic form
- getDialog: function (topic) {
- return {
- template: 'static/templates/topics/topic-form.html',
- controller: (topic) ? 'TopicUpdateCtrl' : 'TopicCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- topicId: function () {return topic ? topic.id: void 0;}
- },
- };
- },
- getFormFields: function (isCreateForm) {
- var images = Mediafile.getAllImages();
- var formFields = [
- {
- key: 'title',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Title'),
- required: true
- }
- },
- {
- key: 'text',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('Text')
- },
- data: {
- ckeditorOptions: Editor.getOptions(images)
- }
- }];
- // attachments
- if (Mediafile.getAll().length > 0) {
- formFields.push({
- key: 'attachments_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Attachment'),
- options: $filter('orderBy')(Mediafile.getAll(), 'title_or_filename'),
- ngOptions: 'option.id as option.title_or_filename for option in to.options',
- placeholder: gettextCatalog.getString('Select or search an attachment ...')
- }
- });
- }
-
- // show as agenda item + parent item
- if (isCreateForm) {
- formFields.push(ShowAsAgendaItemField('agenda.can_manage'));
- formFields.push({
- key: 'agenda_parent_id',
- type: 'select-single',
- templateOptions: {
- label: gettextCatalog.getString('Parent item'),
- options: AgendaTree.getFlatTree(Agenda.getAll()),
- ngOptions: 'item.id as item.getListViewTitle() for item in to.options | notself : model.agenda_item_id',
- placeholder: gettextCatalog.getString('Select a parent item ...')
- },
- hide: !operator.hasPerms('agenda.can_manage')
- });
- }
-
- return formFields;
- }
- };
- }
-])
-
-.controller('TopicDetailCtrl', [
- '$scope',
- 'ngDialog',
- 'TopicForm',
- 'Topic',
- 'topicId',
- 'Projector',
- 'ProjectionDefault',
- 'WebpageTitle',
- 'gettextCatalog',
- function($scope, ngDialog, TopicForm, Topic, topicId, Projector, ProjectionDefault, WebpageTitle,
- gettextCatalog) {
- $scope.$watch(function () {
- return Topic.lastModified(topicId);
- }, function () {
- $scope.topic = Topic.get(topicId);
- WebpageTitle.updateTitle(gettextCatalog.getString('Topic') + ' ' +
- $scope.topic.agenda_item.getTitle());
- });
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'topics'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.openDialog = function (topic) {
- ngDialog.open(TopicForm.getDialog(topic));
- };
- }
-])
-
-.controller('TopicCreateCtrl', [
- '$scope',
- '$state',
- 'Topic',
- 'TopicForm',
- 'Agenda',
- 'Config',
- 'ErrorMessage',
- function($scope, $state, Topic, TopicForm, Agenda, Config, ErrorMessage) {
- $scope.model = {
- agenda_type: 1, // Default is a public item. The config field
- // 'agenda_new_items_default_visibility' is not used.
- };
- // get all form fields
- $scope.formFields = TopicForm.getFormFields(true);
- // save form
- $scope.save = function (topic) {
- Topic.create(topic).then(
- function (success) {
- $scope.closeThisDialog();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('TopicUpdateCtrl', [
- '$scope',
- '$state',
- 'Topic',
- 'TopicForm',
- 'Agenda',
- 'topicId',
- 'ErrorMessage',
- function($scope, $state, Topic, TopicForm, Agenda, topicId, ErrorMessage) {
- var topic = Topic.get(topicId);
- $scope.alert = {};
- // set initial values for form model by create deep copy of topic object
- // so list/detail view is not updated while editing
- $scope.model = angular.copy(topic);
- // get all form fields
- $scope.formFields = TopicForm.getFormFields();
-
- // save form
- $scope.save = function (topic) {
- // inject the changed topic (copy) object back into DS store
- Topic.inject(topic);
- // save changed topic object on server
- Topic.save(topic).then(
- function(success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original topic object from server
- Topic.refresh(topic);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('TopicImportCtrl', [
- '$scope',
- 'gettext',
- 'Agenda',
- 'Topic',
- 'HumanTimeConverter',
- 'TopicsCsvExample',
- function($scope, gettext, Agenda, Topic, HumanTimeConverter, TopicsCsvExample) {
- // Big TODO: Change wording from "item" to "topic".
- // import from textarea
- $scope.importByLine = function () {
- if ($scope.itemlist) {
- $scope.titleItems = _.filter($scope.itemlist[0].split("\n"));
- $scope.importcounter = 0;
- _.forEach($scope.titleItems, function(title, index) {
- var item = {title: title};
- item.agenda_type = 1; // The new topic is not hidden.
- item.agenda_weight = 1000 + index;
- // TODO: create all items in bulk mode
- Topic.create(item).then(
- function(success) {
- $scope.importcounter++;
- }
- );
- });
- }
- };
-
- // *** CSV import ***
- $scope.csvConfig = {
- accept: '.csv, .txt',
- encodingOptions: ['UTF-8', 'ISO-8859-1'],
- parseConfig: {
- skipEmptyLines: true,
- },
- };
- var FIELDS = ['title', 'text', 'duration', 'comment', 'is_hidden'];
- $scope.items = [];
- $scope.onCsvChange = function (csv) {
- $scope.items = [];
-
- var items = [];
- _.forEach(csv.data, function (row) {
- if (row.length > 1) {
- var filledRow = _.zipObject(FIELDS, row);
- items.push(filledRow);
- }
- });
-
- _.forEach(items, function (item, index) {
- item.selected = true;
-
- if (!item.title) {
- item.importerror = true;
- item.title_error = gettext('Error: Title is required.');
- }
- // duration
- if (item.duration) {
- var time = HumanTimeConverter.humanTimeToSeconds(item.duration, {hours: true})/60;
- if (time <= 0) { // null instead of 0 or negative duration
- time = null;
- }
- item.duration = time;
- } else {
- delete item.duration;
- }
- // is_hidden
- if (item.is_hidden) {
- if (item.is_hidden == '1') {
- item.type = 2;
- } else {
- item.type = 1;
- }
- } else {
- item.type = 1;
- }
- // set weight for right csv row order
- // (Use 1000+ to protect existing items and prevent collision
- // with new items which use weight 10000 as default.)
- item.weight = 1000 + index;
- $scope.items.push(item);
- });
- $scope.calcStats();
- };
-
- $scope.calcStats = function () {
- $scope.itemsWillNotBeImported = 0;
- $scope.itemsWillBeImported = 0;
-
- $scope.items.forEach(function(item) {
- if (item.selected && !item.importerror) {
- $scope.itemsWillBeImported++;
- } else {
- $scope.itemsWillNotBeImported++;
- }
- });
- };
-
- // import from csv file
- $scope.import = function () {
- $scope.csvImporting = true;
- angular.forEach($scope.items, function (item) {
- if (item.selected && !item.importerror) {
- item.agenda_type = item.type;
- item.agenda_comment = item.comment;
- item.agenda_duration = item.duration;
- item.agenda_weight = item.weight;
- Topic.create(item).then(
- function(success) {
- item.imported = true;
- }
- );
- }
- });
- $scope.csvimported = true;
- };
- $scope.clear = function () {
- $scope.items = null;
- };
- // download CSV example file
- $scope.downloadCSVExample = function () {
- TopicsCsvExample.downloadExample();
- };
- }
-]);
-
-}());
diff --git a/openslides/topics/static/templates/topics/slide_topic.html b/openslides/topics/static/templates/topics/slide_topic.html
deleted file mode 100644
index 29da04115..000000000
--- a/openslides/topics/static/templates/topics/slide_topic.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
{{ topic.agenda_item.getTitle() }}
-
-
diff --git a/openslides/topics/static/templates/topics/topic-detail.html b/openslides/topics/static/templates/topics/topic-detail.html
deleted file mode 100644
index ec33b3741..000000000
--- a/openslides/topics/static/templates/topics/topic-detail.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
diff --git a/openslides/topics/static/templates/topics/topic-form.html b/openslides/topics/static/templates/topics/topic-form.html
deleted file mode 100644
index a5329b05a..000000000
--- a/openslides/topics/static/templates/topics/topic-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-Edit topic
-New topic
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/topics/static/templates/topics/topic-import.html b/openslides/topics/static/templates/topics/topic-import.html
deleted file mode 100644
index 2d801dbcc..000000000
--- a/openslides/topics/static/templates/topics/topic-import.html
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
-
-
Import by copy/paste
-
Copy and paste your topic titles in this textbox. Keep each item in a single line.
-
-
-
-
-
Import
-
-
- {{ importcounter }} / {{ titleItems.length }} {{ "imported" | translate }}
-
-
-
-
-
-
-
-
Import by CSV file
-
-
Select a CSV file
-
-
-
Please note:
-
- Required comma or semicolon separated values with these column header names in the first row :
-
- Title ,
- Text ,
- Duration ,
- Comment ,
- Internal item
-
- Title is required. All other fields are optional and may be empty.
- Only double quotes are accepted as text delimiter (no single quotes).
- Download CSV example file
-
-
-
-
Preview
-
-
-
-
- {{ itemsWillNotBeImported }}
- topics will be not imported.
-
-
-
- {{ itemsWillBeImported }}
- topics will be imported.
-
-
-
-
-
- {{ itemsImported.length }}
- topics were successfully imported.
-
-
-
-
- Clear preview
-
-
- Import {{ itemsWillBeImported }} topics
-
-
-
-
-
diff --git a/openslides/urls.py b/openslides/urls.py
index d3da9d09b..2fbd665f1 100644
--- a/openslides/urls.py
+++ b/openslides/urls.py
@@ -1,6 +1,5 @@
from django.conf import settings
from django.conf.urls import include, url
-from django.contrib.staticfiles.urls import urlpatterns
from django.views.generic import RedirectView
from openslides.mediafiles.views import protected_serve
@@ -9,9 +8,7 @@ from openslides.utils.rest_api import router
from .core import views as core_views
-# Urls for /static/ are already in urlpatterns
-
-urlpatterns += [
+urlpatterns = [
# URLs for /media/
url(r'^%s(?P.*)$' % settings.MEDIA_URL.lstrip('/'), protected_serve, {'document_root': settings.MEDIA_ROOT}),
@@ -25,19 +22,7 @@ urlpatterns += [
# Other urls defined by modules and plugins
url(r'^apps/', include('openslides.urls_apps')),
- # The old angular webclient
- # TODO: Change me or at least my comment
- url(r'^webclient/(?Psite|projector)/$',
- core_views.WebclientJavaScriptView.as_view(),
- name='core_webclient_javascript'),
-
- # View for the projectors are handled by angular.
- url(r'^projector/(\d+)/$', core_views.ProjectorView.as_view()),
-
- # Original view without resolutioncontrol for the projectors are handled by angular.
- url(r'^real-projector/(\d+)/$', core_views.RealProjectorView.as_view()),
-
# Main entry point for all angular pages.
# Has to be the last entry in the urls.py
- url(r'^.*$', core_views.IndexView.as_view(), name="index"),
+ url(r'^(?P.*)$', core_views.IndexView.as_view(), name="index"),
]
diff --git a/openslides/urls_apps.py b/openslides/urls_apps.py
index 8ef1ef6ab..c5b719c24 100644
--- a/openslides/urls_apps.py
+++ b/openslides/urls_apps.py
@@ -7,7 +7,5 @@ urlpatterns = get_all_plugin_urlpatterns()
urlpatterns += [
url(r'^core/', include('openslides.core.urls')),
- url(r'^agenda/', include('openslides.agenda.urls')),
- url(r'^motions/', include('openslides.motions.urls')),
url(r'^users/', include('openslides.users.urls')),
]
diff --git a/openslides/users/static/css/users/_site.scss b/openslides/users/static/css/users/_site.scss
deleted file mode 100644
index b21f9e5c3..000000000
--- a/openslides/users/static/css/users/_site.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-.user_details {
- fieldset {
- margin-bottom: 10px;
- }
- legend {
- margin-bottom: 5px;
- }
- label {
- margin: 10px 0 0 0;
- display: block;
- font-family: $font-medium;
- font-family: $font-medium, sans-serif;
- font-weight: normal;
- &:after {
- content: ":";
- }
- }
-}
diff --git a/openslides/users/static/js/users/base.js b/openslides/users/static/js/users/base.js
deleted file mode 100644
index eddde81c3..000000000
--- a/openslides/users/static/js/users/base.js
+++ /dev/null
@@ -1,178 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.users', [])
-
-.factory('User', [
- 'DS',
- 'Group',
- 'jsDataModel',
- 'gettext',
- 'gettextCatalog',
- 'Config',
- function(DS, Group, jsDataModel, gettext, gettextCatalog, Config) {
- var name = 'users/user';
- return DS.defineResource({
- name: name,
- useClass: jsDataModel,
- verboseName: gettext('Participants'),
- verboseNamePlural: gettext('Participants'),
- computed: {
- full_name: function () {
- return this.get_full_name();
- },
- short_name: function () {
- return this.get_short_name();
- },
- },
- methods: {
- getResourceName: function () {
- return name;
- },
- /*
- * Returns a short form of the name.
- *
- * Example:
- * - Dr. Max Mustermann
- * - Professor Dr. Enders, Christoph
- */
- get_short_name: function() {
- var title = _.trim(this.title),
- firstName = _.trim(this.first_name),
- lastName = _.trim(this.last_name),
- name = '';
- if (Config.get('users_sort_by') && Config.get('users_sort_by').value == 'last_name') {
- if (lastName && firstName) {
- name += [lastName, firstName].join(', ');
- } else {
- name += lastName || firstName;
- }
- } else {
- name += [firstName, lastName].join(' ');
- }
- if (name.trim() === '') {
- name = this.username;
- }
- if (title !== '') {
- name = title + ' ' + name;
- }
- return name.trim();
- },
- /*
- * Returns a long form of the name.
- *
- * Example:
- * - Dr. Max Mustermann (Villingen)
- * - Professor Dr. Enders, Christoph (Leipzig)
- */
- get_full_name: function() {
- var name = this.get_short_name(),
- structure_level = _.trim(this.structure_level),
- number = _.trim(this.number),
- addition = [];
-
- // addition: add number and structure level
- if (structure_level) {
- addition.push(structure_level);
- }
- if (number) {
- addition.push(
- /// abbreviation for number
- gettextCatalog.getString('No.') + ' ' + number
- );
- }
- if (addition.length > 0) {
- name += ' (' + addition.join(' · ') + ')';
- }
- return name.trim();
- },
- getPerms: function() {
- var allPerms = [];
- var allGroups = [];
- if (this.groups_id) {
- allGroups = this.groups_id.slice(0);
- }
- if (allGroups.length === 0) {
- allGroups.push(1); // add default group
- }
- _.forEach(allGroups, function(groupId) {
- var group = Group.get(groupId);
- if (group) {
- _.forEach(group.permissions, function(perm) {
- allPerms.push(perm);
- });
- }
- });
- return _.uniq(allPerms);
- },
- // link name which is shown in search result
- getSearchResultName: function () {
- return this.get_full_name();
- },
- // subtitle of search result
- getSearchResultSubtitle: function () {
- return "Participant";
- },
- },
- relations: {
- hasMany: {
- 'users/group': {
- localField: 'groups',
- localKey: 'groups_id',
- }
- }
- }
- });
- }
-])
-
-.factory('Group', [
- 'DS',
- function(DS) {
- var name = 'users/group';
- var permissions;
- return DS.defineResource({
- name: name,
- });
- }
-])
-
-.factory('PersonalNote', [
- 'DS',
- function (DS) {
- var name = 'users/personal-note';
- return DS.defineResource({
- name: name,
- relations: {
- hasOne: {
- 'users/user': {
- localField: 'user',
- localKey: 'user_id',
- }
- }
- }
- });
- }
-])
-
-.run([
- 'User',
- 'Group',
- 'PersonalNote',
- function(User, Group) {}
-])
-
-// Mark strings for translation in JavaScript.
-.config([
- 'gettext',
- function (gettext) {
- // default group names (from users/signals.py)
- gettext('Default');
- gettext('Delegates');
- gettext('Staff');
- gettext('Committees');
- }
-]);
-
-}());
diff --git a/openslides/users/static/js/users/csv.js b/openslides/users/static/js/users/csv.js
deleted file mode 100644
index d0ac2cb84..000000000
--- a/openslides/users/static/js/users/csv.js
+++ /dev/null
@@ -1,74 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.users.csv', [])
-
-.factory('UserCsvExport', [
- '$filter',
- 'Group',
- 'gettextCatalog',
- 'CsvDownload',
- function ($filter, Group, gettextCatalog, CsvDownload) {
- var makeHeaderline = function () {
- var headerline = ['Title', 'Given name', 'Surname', 'Structure level', 'Participant number', 'Groups',
- 'Comment', 'Is active', 'Is present', 'Is a committee', 'Initial password', 'Email'];
- return _.map(headerline, function (entry) {
- return gettextCatalog.getString(entry);
- });
- };
- return {
- export: function (users) {
- var csvRows = [
- makeHeaderline()
- ];
- _.forEach(users, function (user) {
- var groups = _.map(user.groups_id, function (id) {
- return gettextCatalog.getString(Group.get(id).name);
- }).join(',');
- var row = [];
- row.push('"' + user.title + '"');
- row.push('"' + user.first_name + '"');
- row.push('"' + user.last_name + '"');
- row.push('"' + user.structure_level + '"');
- row.push('"' + user.number + '"');
- row.push('"' + groups + '"');
- row.push('"' + user.comment + '"');
- row.push(user.is_active ? '1' : '0');
- row.push(user.is_present ? '1' : '0');
- row.push(user.is_committee ? '1' : '0');
- row.push('"' + user.default_password + '"');
- row.push('"' + user.email + '"');
- csvRows.push(row);
- });
- CsvDownload(csvRows, gettextCatalog.getString('participants') + '.csv');
- },
-
- downloadExample: function () {
- // try to get an example with two groups and one with one group
- var groups = $filter('orderBy')(Group.getAll(), 'id');
- var csvGroups = '';
- var csvGroup = '';
- if (groups.length >= 3) { // do not pick groups[0], this is the default group
- csvGroups = '"' + gettextCatalog.getString(groups[1].name) +
- ', ' + gettextCatalog.getString(groups[2].name) + '"';
- }
- if (groups.length >= 2) {
- csvGroup = gettextCatalog.getString(groups[groups.length - 1].name); // take last group
- }
-
- var csvRows = [makeHeaderline(),
- // example entries
- ['Dr.', 'Max', 'Mustermann', 'Berlin','1234567890', csvGroups, 'xyz', '1', '1', '', 'initialPassword', ''],
- ['', 'John', 'Doe', 'Washington','75/99/8-2', csvGroup, 'abc', '1', '1', '', '', 'john.doe@email.com'],
- ['', 'Fred', 'Bloggs', 'London', '', '', '', '', '', '', '', ''],
- ['', '', 'Executive Board', '', '', '', '', '', '', '1', '', ''],
-
- ];
- CsvDownload(csvRows, gettextCatalog.getString('participants-example') + '.csv');
- }
- };
- }
-]);
-
-}());
diff --git a/openslides/users/static/js/users/pdf.js b/openslides/users/static/js/users/pdf.js
deleted file mode 100644
index 2d647f681..000000000
--- a/openslides/users/static/js/users/pdf.js
+++ /dev/null
@@ -1,329 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.users.pdf', ['OpenSlidesApp.core.pdf'])
-
-.factory('UserListContentProvider', [
- 'gettextCatalog',
- 'PDFLayout',
- 'Group',
- function(gettextCatalog, PDFLayout, Group) {
-
- var createInstance = function(userList) {
- var groups = Group.getAll();
-
- //use the Predefined Functions to create the title
- var title = PDFLayout.createTitle(gettextCatalog.getString('List of participants'));
-
- //function to generate the user list
- var createUserList = function() {
- var userJsonList = [];
-
- angular.forEach(userList, function (user, counter) {
-
- //parse for the group names
- var userGroups = [];
- angular.forEach(user.groups_id, function (id) {
- if (id) {
- angular.forEach(groups, function(group) {
- if (id == group.id) {
- userGroups.push(gettextCatalog.getString(group.name));
- }
- });
- }
- });
-
- var userJsonObj = [
- {
- text: "" + (counter+1),
- style: PDFLayout.flipTableRowStyle(userJsonList.length)
- },
- {
- text: user.short_name,
- style: PDFLayout.flipTableRowStyle(userJsonList.length)
- },
- {
- text: user.structure_level,
- style: PDFLayout.flipTableRowStyle(userJsonList.length)
- },
- {
- text: userGroups.join(', '),
- style: PDFLayout.flipTableRowStyle(userJsonList.length)
- }
- ];
- userJsonList.push(userJsonObj);
- });
-
- var userTableBody = [
- [
- {
- text: '#',
- style: 'tableHeader'
- },
- {
- text: gettextCatalog.getString('Name'),
- style: 'tableHeader'
- },
- {
- text: gettextCatalog.getString('Structure level'),
- style: 'tableHeader'
- },
- {
- text: gettextCatalog.getString('Groups'),
- style: 'tableHeader'
- }
- ]
- ];
- userTableBody = userTableBody.concat((userJsonList));
-
- var userTableJsonString = {
- table: {
- widths: ['auto', '*', 'auto', 'auto'],
- headerRows: 1,
- body: userTableBody
- },
- layout: 'headerLineOnly'
- };
-
- return userTableJsonString;
- };
-
- var getContent = function() {
- return [
- title,
- createUserList()
- ];
- };
-
- return {
- getContent: getContent
- };
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('UserAccessDataListContentProvider', [
- 'gettextCatalog',
- 'PDFLayout',
- 'Config',
- function(gettextCatalog, PDFLayout, Config) {
-
- var createInstance = function(userList) {
-
- var createUserHeadLine = function(user) {
- var titleLine = [];
- titleLine.push({
- text: user.get_short_name(),
- style: 'userDataTitle'
- });
- if (user.structure_level) {
- titleLine.push({
- text: user.structure_level,
- style: 'userDataHeading'
- });
- }
- return titleLine;
- };
-
- var createAccessDataContent = function(user) {
- // wlan access data
- var columnWifi = [
- {
- text: gettextCatalog.getString('WLAN access data'),
- style: 'userDataHeading'
- },
- {
- text: gettextCatalog.getString('WLAN name (SSID)') + ':',
- style: 'userDataTopic'
- },
- {
- text: Config.get('users_pdf_wlan_ssid').value || '-',
- style: 'userDataValue'
- },
- {
- text: gettextCatalog.getString('WLAN password') + ':',
- style: 'userDataTopic'
- },
- {
- text: Config.get('users_pdf_wlan_password').value || '-',
- style: 'userDataValue'
- },
- {
- text: gettextCatalog.getString('WLAN encryption') + ':',
- style: 'userDataTopic'
- },
- {
- text: Config.get('users_pdf_wlan_encryption').value || '-',
- style: 'userDataValue'
- },
- {
- text: '\n'
- }
- ];
- // wifi qr code
- if (Config.get('users_pdf_wlan_ssid').value && Config.get('users_pdf_wlan_encryption').value) {
- var wifiQrCode = 'WIFI:S:' + Config.get('users_pdf_wlan_ssid').value +
- ';T:' + Config.get('users_pdf_wlan_encryption').value +
- ';P:' + Config.get('users_pdf_wlan_password').value + ';;';
- columnWifi.push(
- {
- qr: wifiQrCode,
- fit: 120,
- margin: [0, 0, 0, 8]
- },
- {
- text: gettextCatalog.getString('Scan this QR code to connect to WLAN.'),
- style: 'small'
- }
- );
- }
-
- // openslides access data
- var columnOpenSlides = [
- {
- text: gettextCatalog.getString('OpenSlides access data'),
- style: 'userDataHeading'
- },
- {
- text: gettextCatalog.getString('Username') + ':',
- style: 'userDataTopic'
- },
- {
- text: user.username,
- style: 'userDataValue'
- },
- {
- text: gettextCatalog.getString('Initial password') + ':',
- style: 'userDataTopic'
- },
- {
- text: user.default_password,
- style: 'userDataValue'
- },
- {
- text: 'URL:',
- style: 'userDataTopic'
- },
- {
- text: Config.get('users_pdf_url').value || '-',
- link: Config.get('users_pdf_url').value,
- style: 'userDataValue'
- },
- {
- text: '\n'
- }
- ];
- // url qr code
- if (Config.get('users_pdf_url').value) {
- columnOpenSlides.push(
- {
- qr: Config.get('users_pdf_url').value,
- fit: 120,
- margin: [0, 0, 0, 8]
- },
- {
- text: gettextCatalog.getString('Scan this QR code to open URL.'),
- style: 'small'
- }
- );
- }
-
- var accessDataColumns = {
- columns: [
- columnWifi,
- columnOpenSlides,
- ],
- margin: [0, 20]
- };
-
- return accessDataColumns;
- };
-
- var createWelcomeText = function() {
- return [
- {
- text: Config.translate(Config.get('users_pdf_welcometitle').value),
- style: 'userDataHeading'
- },
- {
- text: Config.translate(Config.get('users_pdf_welcometext').value),
- style: 'userDataTopic'
- }
- ];
- };
-
- var getContent = function() {
- var content = [];
- angular.forEach(userList, function (user, index) {
- content.push(createUserHeadLine(user));
- content.push(createAccessDataContent(user));
- content.push(createWelcomeText());
- // No pagebreak after the last user
- if (index !== userList.length - 1) {
- content.push({
- text: '',
- pageBreak: 'after'
- });
- }
- });
-
- return [
- content
- ];
- };
-
- return {
- getContent: getContent
- };
- };
-
- return {
- createInstance: createInstance
- };
- }
-])
-
-.factory('UserPdfExport', [
- 'gettextCatalog',
- 'UserListContentProvider',
- 'UserAccessDataListContentProvider',
- 'PdfMakeDocumentProvider',
- 'PdfCreate',
- 'Messaging',
- function (gettextCatalog, UserListContentProvider, UserAccessDataListContentProvider,
- PdfMakeDocumentProvider, PdfCreate, Messaging) {
- return {
- exportUserList: function (users) {
- var filename = gettextCatalog.getString('List of participants') + '.pdf';
- var userListContentProvider = UserListContentProvider.createInstance(users);
- PdfMakeDocumentProvider.createInstance(userListContentProvider).then(
- function (documentProvider) {
- PdfCreate.download(documentProvider, filename);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- }
- );
- },
- exportUserAccessDataList: function (users) {
- var filename = gettextCatalog.getString('List of access data') + '.pdf';
- var userAccessDataListContentProvider = UserAccessDataListContentProvider.createInstance(
- users);
- // no footer here
- PdfMakeDocumentProvider.createInstance(userAccessDataListContentProvider, true).then(
- function (documentProvider) {
- PdfCreate.download(documentProvider, filename, true);
- }, function (error) {
- Messaging.addMessage(error.msg, 'error');
- }
- );
- }
- };
- }
-]);
-
-}());
diff --git a/openslides/users/static/js/users/projector.js b/openslides/users/static/js/users/projector.js
deleted file mode 100644
index 49866fa30..000000000
--- a/openslides/users/static/js/users/projector.js
+++ /dev/null
@@ -1,28 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.users.projector', ['OpenSlidesApp.users'])
-
-.config([
- 'slidesProvider',
- function(slidesProvider) {
- slidesProvider.registerSlide('users/user', {
- template: 'static/templates/users/slide_user.html',
- });
- }
-])
-
-.controller('SlideUserCtrl', [
- '$scope',
- 'User',
- function($scope, User) {
- // Attention! Each object that is used here has to be dealt on server side.
- // Add it to the coresponding get_requirements method of the ProjectorElement
- // class.
- var id = $scope.element.id;
- User.bindOne(id, $scope, 'user');
- }
-]);
-
-}());
diff --git a/openslides/users/static/js/users/site.js b/openslides/users/static/js/users/site.js
deleted file mode 100644
index e9a3df953..000000000
--- a/openslides/users/static/js/users/site.js
+++ /dev/null
@@ -1,1898 +0,0 @@
-(function () {
-
-'use strict';
-
-angular.module('OpenSlidesApp.users.site', [
- 'OpenSlidesApp.users',
- 'OpenSlidesApp.core.pdf',
- 'OpenSlidesApp.users.pdf',
- 'OpenSlidesApp.users.csv',
-])
-
-.config([
- 'mainMenuProvider',
- 'gettext',
- function (mainMenuProvider, gettext) {
- mainMenuProvider.register({
- 'ui_sref': 'users.user.list',
- 'img_class': 'user',
- 'title': gettext('Participants'),
- 'weight': 500,
- 'perm': 'users.can_see_name',
- });
- }
-])
-.config([
- 'SearchProvider',
- 'gettext',
- function (SearchProvider, gettext) {
- SearchProvider.register({
- 'verboseName': gettext('Participants'),
- 'collectionName': 'users/user',
- 'urlDetailState': 'users.user.detail',
- 'weight': 500,
- });
- }
-])
-
-.config([
- '$stateProvider',
- 'gettext',
- function($stateProvider, gettext) {
- $stateProvider
- .state('users', {
- url: '/users',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Participants'),
- basePerm: 'users.can_see_name',
- },
- })
- .state('users.user', {
- abstract: true,
- template: " ",
- })
- .state('users.user.list', {})
- .state('users.user.create', {})
- .state('users.user.detail', {
- resolve: {
- userId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }]
- }
- })
- .state('users.user.change-password', {
- url: '/change-password/{id}',
- controller: 'UserChangePasswordCtrl',
- templateUrl: 'static/templates/users/user-change-password.html',
- resolve: {
- userId: ['$stateParams', function($stateParams) {
- return $stateParams.id;
- }]
- }
- })
- .state('users.user.import', {
- url: '/import',
- controller: 'UserImportCtrl',
- })
- .state('users.user.presence', {
- url: '/presence',
- controller: 'UserPresenceCtrl',
- })
- // groups
- .state('users.group', {
- url: '/groups',
- abstract: true,
- template: " ",
- data: {
- title: gettext('Groups'),
- },
- })
- .state('users.group.list', {})
- .state('login', {
- template: null,
- url: '/login',
- params: {
- guest_enabled: false,
- msg: null,
- },
- onEnter: ['$state', '$stateParams', 'ngDialog', 'LoginDialog', function($state, $stateParams, ngDialog, LoginDialog) {
- LoginDialog.id = ngDialog.open({
- template: 'static/templates/core/login-form.html',
- controller: 'LoginFormCtrl',
- showClose: $stateParams.guest_enabled,
- closeByEscape: $stateParams.guest_enabled,
- closeByDocument: $stateParams.guest_enabled,
- }).id;
- }],
- data: {
- title: 'Login',
- },
- });
- }
-])
-
-.value('LoginDialog', {})
-
-/*
- * Directive to check for permissions
- *
- * This is the Code from angular.js ngIf.
- *
- * TODO: find a way not to copy the code.
-*/
-.directive('osPerms', [
- '$animate',
- function($animate) {
- return {
- multiElement: true,
- transclude: 'element',
- priority: 600,
- terminal: true,
- restrict: 'A',
- $$tlb: true,
- link: function($scope, $element, $attr, ctrl, $transclude) {
- var block, childScope, previousElements, perms;
- if ($attr.osPerms[0] === '!') {
- perms = _.trimStart($attr.osPerms, '!');
- } else {
- perms = $attr.osPerms;
- }
- $scope.$watch(
- function (scope) {
- return scope.operator && scope.operator.hasPerms(perms);
- },
- function (value) {
- if ($attr.osPerms[0] === '!') {
- value = !value;
- }
- if (value) {
- if (!childScope) {
- $transclude(function(clone, newScope) {
- childScope = newScope;
- clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
- // Note: We only need the first/last node of the cloned nodes.
- // However, we need to keep the reference to the jqlite wrapper as it might be changed later
- // by a directive with templateUrl when its template arrives.
- block = {
- clone: clone
- };
- $animate.enter(clone, $element.parent(), $element);
- });
- }
- } else {
- if (previousElements) {
- previousElements.remove();
- previousElements = null;
- }
- if (childScope) {
- childScope.$destroy();
- childScope = null;
- }
- if (block) {
- previousElements = getBlockNodes(block.clone);
- $animate.leave(previousElements).then(function() {
- previousElements = null;
- });
- block = null;
- }
- }
- }
- );
- }
- };
- }
-])
-
-.factory('PasswordGenerator', [
- function () {
- return {
- generate: function (length) {
- if (!length) {
- length = 8;
- }
- var chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789',
- pw = '';
- for (var i = 0; i < length; ++i) {
- pw += chars.charAt(Math.floor(Math.random() * chars.length));
- }
- return pw;
- }
- };
- }
-])
-
-.factory('PersonalNoteManager', [
- 'PersonalNote',
- 'operator',
- function (PersonalNote, operator) {
- var _getPersonalNoteObject = function (resourceName) {
- var personalNote = _.find(PersonalNote.getAll(), function (pn) {
- return pn.user_id === operator.user.id;
- });
- if (!personalNote) {
- personalNote = {
- notes: {},
- };
- }
- if (!personalNote.notes[resourceName]) {
- personalNote.notes[resourceName] = {};
- }
- return personalNote;
- };
- var get = function (resourceName, id) {
- return _getPersonalNoteObject(resourceName).notes[resourceName][id];
- };
- var save = function (resourceName, id, note) {
- var personalNote = _getPersonalNoteObject(resourceName);
- personalNote.notes[resourceName][id] = note;
- if (personalNote.id) {
- return PersonalNote.save(personalNote);
- } else {
- return PersonalNote.create(personalNote);
- }
- };
- return {
- getNote: function (obj) {
- if (typeof obj.getResourceName === 'undefined') {
- throw 'The Object has to be a js data model!';
- }
- return get(obj.getResourceName(), obj.id);
- },
- saveNote: function (obj, note) {
- if (typeof obj.getResourceName === 'undefined') {
- throw 'The Object has to be a js data model!';
- }
- return save(obj.getResourceName(), obj.id, note);
- },
- };
- }
-])
-
-// Service for generic assignment form (create and update)
-.factory('UserForm', [
- '$http',
- 'gettextCatalog',
- 'Editor',
- 'Group',
- 'Mediafile',
- 'PasswordGenerator',
- function ($http, gettextCatalog, Editor, Group, Mediafile, PasswordGenerator) {
- return {
- // ngDialog for user form
- getDialog: function (user) {
- return {
- template: 'static/templates/users/user-form.html',
- controller: (user) ? 'UserUpdateCtrl' : 'UserCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- userId: function () {return user ? user.id : void 0;},
- }
- };
- },
- // angular-formly fields for user form
- getFormFields: function (hideOnCreateForm) {
- var images = Mediafile.getAllImages();
- return [
- {
- className: "row",
- fieldGroup: [
- {
- key: 'title',
- type: 'input',
- className: "col-xs-2 no-padding-left",
- templateOptions: {
- label: gettextCatalog.getString('Title')
- }
- },
- {
- key: 'first_name',
- type: 'input',
- className: "col-xs-5 no-padding",
- templateOptions: {
- label: gettextCatalog.getString('Given name')
- }
- },
- {
- key: 'last_name',
- type: 'input',
- className: "col-xs-5 no-padding-right",
- templateOptions: {
- label: gettextCatalog.getString('Surname')
- }
- }
- ]
- },
- {
- key: 'email',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Email')
- },
- },
- {
- className: "row",
- fieldGroup: [
- {
- key: 'structure_level',
- type: 'input',
- className: "col-xs-9 no-padding-left",
- templateOptions: {
- label: gettextCatalog.getString('Structure level'),
- }
- },
- { key: 'number',
- type: 'input',
- className: "col-xs-3 no-padding-left no-padding-right",
- templateOptions: {
- label:gettextCatalog.getString('Participant number')
- }
- }
- ]
- },
- {
- key: 'username',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Username')
- },
- hide: hideOnCreateForm
- },
- {
- key: 'groups_id',
- type: 'select-multiple',
- templateOptions: {
- label: gettextCatalog.getString('Groups'),
- options: Group.filter({where: {id: {'>': 1}}}),
- ngOptions: "option.id as option.name | translate for option in to.options | orderBy: 'id'",
- placeholder: gettextCatalog.getString('Select or search a group ...')
- }
- },
- {
- key: 'default_password',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Initial password'),
- description: gettextCatalog.getString('Initial password can not be changed.'),
- addonRight: {
- text: gettextCatalog.getString('Generate'),
- class: 'fa fa-magic',
- onClick:function (options, scope) {
- scope.$parent.model.default_password = PasswordGenerator.generate();
- }
- }
- },
- hide: !hideOnCreateForm
- },
- {
- key: 'comment',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Comment'),
- description: gettextCatalog.getString('Only for internal notes.')
- }
- },
- {
- key: 'more',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Show extended fields')
- }
- },
- {
- template: ' ',
- hideExpression: '!model.more'
- },
- {
- key: 'is_present',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Is present'),
- description: gettextCatalog.getString('Designates whether this user is in the room or not.')
- },
- defaultValue: true,
- hideExpression: '!model.more'
- },
- {
- key: 'is_active',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Is active'),
- description: gettextCatalog.getString(
- 'Designates whether this user should be treated as ' +
- 'active. Unselect this instead of deleting the account.')
- },
- defaultValue: true,
- hideExpression: '!model.more'
- },
- {
- key: 'is_committee',
- type: 'checkbox',
- templateOptions: {
- label: gettextCatalog.getString('Is a committee'),
- description: gettextCatalog.getString(
- 'Designates whether this user should be treated as a committee.')
- },
- defaultValue: false,
- hideExpression: '!model.more'
- },
- {
- key: 'about_me',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('About me'),
- },
- data: {
- ckeditorOptions: Editor.getOptions(images)
- },
- hideExpression: '!model.more'
- }
- ];
- }
- };
- }
-])
-
-.factory('UserProfileForm', [
- 'gettextCatalog',
- 'Editor',
- 'Mediafile',
- function (gettextCatalog, Editor, Mediafile) {
- return {
- // ngDialog for user form
- getDialog: function () {
- return {
- template: 'static/templates/users/profile-password-form.html',
- controller: 'UserProfileCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- };
- },
- // angular-formly fields for user form
- getFormFields: function (hideOnCreateForm) {
- var images = Mediafile.getAllImages();
- return [
- {
- key: 'username',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Username'),
- required: true
- },
- },
- {
- key: 'email',
- type: 'input',
- templateOptions: {
- label: gettextCatalog.getString('Email')
- },
- },
- {
- key: 'about_me',
- type: 'editor',
- templateOptions: {
- label: gettextCatalog.getString('About me'),
- },
- data: {
- ckeditorOptions: Editor.getOptions(images)
- },
- }
- ];
- }
- };
- }
-])
-
-.factory('UserPasswordForm', [
- 'gettextCatalog',
- function (gettextCatalog) {
- return {
- // ngDialog for user form
- getDialog: function () {
- return {
- template: 'static/templates/users/profile-password-form.html',
- controller: 'UserPasswordCtrl',
- className: 'ngdialog-theme-default',
- closeByEscape: false,
- closeByDocument: false,
- };
- },
- // angular-formly fields for user form
- getFormFields: function (hideOnCreateForm) {
- return [
- {
- key: 'oldPassword',
- type: 'password',
- templateOptions: {
- label: gettextCatalog.getString('Old password'),
- required: true
- },
- },
- {
- key: 'newPassword',
- type: 'password',
- templateOptions: {
- label: gettextCatalog.getString('New password'),
- required: true
- },
- },
- {
- key: 'newPassword2',
- type: 'password',
- templateOptions: {
- label: gettextCatalog.getString('Confirm new password'),
- required: true
- },
- },
- ];
- }
- };
- }
-])
-
-.controller('UserListCtrl', [
- '$scope',
- '$http',
- 'ngDialog',
- 'UserForm',
- 'User',
- 'Group',
- 'PasswordGenerator',
- 'Projector',
- 'ProjectionDefault',
- 'Config',
- 'UserCsvExport',
- 'osTableFilter',
- 'osTableSort',
- 'osTablePagination',
- 'gettext',
- 'UserPdfExport',
- 'InvitationEmails',
- 'ErrorMessage',
- function($scope, $http, ngDialog, UserForm, User, Group, PasswordGenerator,
- Projector, ProjectionDefault, Config, UserCsvExport, osTableFilter, osTableSort,
- osTablePagination, gettext, UserPdfExport, InvitationEmails, ErrorMessage) {
- $scope.$watch(function () {
- return User.lastModified();
- }, function () {
- $scope.users = _.orderBy(User.getAll(), ['first_name']);
- _.forEach($scope.users, function (user) {
- user.has_last_email_send = !!user.last_email_send;
- });
- if ($scope.updateUsers) {
- $scope.updateUsers();
- }
- });
- Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'users'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
- $scope.alert = {};
-
- // Filtering
- $scope.filter = osTableFilter.createInstance('UserTableFilter');
-
- if (!$scope.filter.existsStorageEntry()) {
- $scope.filter.multiselectFilters = {
- group: [],
- };
- $scope.filter.booleanFilters = {
- isPresent: {
- value: undefined,
- displayName: gettext('Present'),
- choiceYes: gettext('Is present'),
- choiceNo: gettext('Is not present'),
- needExtraPermission: true,
- },
- isActive: {
- value: undefined,
- displayName: gettext('Active'),
- choiceYes: gettext('Is active'),
- choiceNo: gettext('Is not active'),
- needExtraPermission: true,
- },
- isCommittee: {
- value: undefined,
- displayName: gettext('Committee'),
- choiceYes: gettext('Is a committee'),
- choiceNo: gettext('Is not a committee'),
- },
- hasLastEmailSend: {
- value: undefined,
- displayName: gettext('Last email send'),
- choiceYes: gettext('Got an email'),
- choiceNo: gettext("Didn't get an email"),
- },
- };
- }
- $scope.filter.propertyList = ['first_name', 'last_name', 'username', 'title',
- 'number', 'comment', 'structure_level'];
- $scope.filter.propertyDict = {
- 'groups_id' : function (group_id) {
- return Group.get(group_id).name;
- },
- };
- $scope.getItemId = {
- group: function (user) {return user.groups_id;},
- };
- // Sorting
- $scope.sort = osTableSort.createInstance('UserTableSort');
- if (!$scope.sort.column) {
- $scope.sort.column = $scope.config('users_sort_by');
- }
- $scope.sortOptions = [
- {name: 'first_name',
- display_name: gettext('Given name')},
- {name: 'last_name',
- display_name: gettext('Surname')},
- {name: 'is_present',
- display_name: gettext('Present')},
- {name: 'is_active',
- display_name: gettext('Active')},
- {name: 'is_committee',
- display_name: gettext('Committee')},
- {name: 'number',
- display_name: gettext('Number')},
- {name: 'structure_level',
- display_name: gettext('Structure level')},
- {name: 'comment',
- display_name: gettext('Comment')},
- {name: 'last_email_send',
- display_name: gettext('Last email send')},
- ];
-
- // pagination
- $scope.pagination = osTablePagination.createInstance('UserTablePagination');
-
- // Toggle group from user
- $scope.toggleGroup = function (user, group) {
- if (_.indexOf(user.groups_id, group.id) > -1) {
- user.groups_id = _.filter(user.groups_id, function (group_id) {
- return group_id != group.id;
- });
- } else {
- user.groups_id.push(group.id);
- }
- $scope.save(user);
- };
- // open new/edit dialog
- $scope.openDialog = function (user) {
- ngDialog.open(UserForm.getDialog(user));
- };
- // save changed user
- $scope.save = function (user) {
- User.save(user).then(
- function(success) {
- //user.quickEdit = false;
- $scope.alert.show = false;
- },
- function(error){
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
- // delete single user
- $scope.delete = function (user) {
- User.destroy(user.id);
- };
- // *** select mode functions ***
- $scope.isSelectMode = false;
- // check all checkboxes
- $scope.checkAll = function () {
- $scope.selectedAll = !$scope.selectedAll;
- _.forEach($scope.usersFiltered, function (user) {
- user.selected = $scope.selectedAll;
- });
- };
- // uncheck all checkboxes if isSelectMode is closed
- $scope.uncheckAll = function () {
- if (!$scope.isSelectMode) {
- $scope.selectedAll = false;
- angular.forEach($scope.users, function (user) {
- user.selected = false;
- });
- }
- };
- var selectModeAction = function (predicate) {
- angular.forEach($scope.usersFiltered, function (user) {
- if (user.selected) {
- predicate(user);
- }
- });
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- };
- // delete all selected users
- $scope.deleteMultiple = function () {
- selectModeAction(function (user) {
- $scope.delete(user);
- });
- };
- // add group for selected users
- $scope.addGroupMultiple = function (group) {
- if (group) {
- selectModeAction(function (user) {
- user.groups_id.push(group);
- User.save(user);
- });
- }
- };
- // remove group for selected users
- $scope.removeGroupMultiple = function (group) {
- if (group) {
- selectModeAction(function (user) {
- var groupIndex = _.indexOf(user.groups_id, parseInt(group));
- if (groupIndex > -1) {
- user.groups_id.splice(groupIndex, 1);
- User.save(user);
- }
- });
- }
- };
- // generate new passwords
- $scope.generateNewPasswordsMultiple = function () {
- selectModeAction(function (user) {
- var newPassword = PasswordGenerator.generate();
- user.default_password = newPassword;
- User.save(user);
- $http.post(
- '/rest/users/user/' + user.id + '/reset_password/',
- {'password': newPassword}
- );
- });
- };
- // set boolean properties (is_active, is_present, is_committee)
- $scope.setBoolPropertyMultiple = function (property, value) {
- selectModeAction(function (user) {
- user[property] = value;
- User.save(user);
- });
- };
- // Send invitation emails
- $scope.sendInvitationEmails = function () {
- InvitationEmails.send($scope.usersFiltered).then(function (success) {
- $scope.alert = success;
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- $scope.isSelectMode = false;
- $scope.uncheckAll();
- });
- };
-
- // Export as PDF
- $scope.pdfExportUserList = function () {
- UserPdfExport.exportUserList($scope.usersFiltered);
- };
- $scope.pdfExportUserAccessDataList = function () {
- UserPdfExport.exportUserAccessDataList($scope.usersFiltered);
- };
- // Export as a csv file
- $scope.csvExport = function () {
- UserCsvExport.export($scope.usersFiltered);
- };
- }
-])
-
-.factory('InvitationEmails', [
- '$http',
- 'User',
- 'Config',
- 'gettextCatalog',
- function ($http, User, Config, gettextCatalog) {
- return {
- // Returns the request promise. If it was successfull, a nice message for
- // an alert is generated and the alert-object is returned.
- send: function (users) {
- var user_ids = _
- .chain(users)
- .filter(function (user) {
- return user.selected;
- })
- .map(function (user) {
- return user.id;
- })
- .value();
- var subject = gettextCatalog.getString(Config.get('users_email_subject').value);
- var message = gettextCatalog.getString(Config.get('users_email_body').value);
-
- return $http.post('/rest/users/user/mass_invite_email/', {
- user_ids: user_ids,
- subject: subject,
- message: message,
- }).then(function (success) {
- var numEmails = success.data.count;
- var noEmailIds = success.data.no_email_ids;
- var type = 'success', msg;
- if (numEmails === 0) {
- type = 'danger';
- msg = gettextCatalog.getString('No emails were send.');
- } else if (numEmails === 1) {
- msg = gettextCatalog.getString('One email was send sucessfully.');
- } else {
- msg = gettextCatalog.getString('%num% emails were send sucessfully.').replace('%num%', numEmails);
- }
-
- if (noEmailIds.length) {
- type = 'warning';
- msg += ' ';
-
- if (noEmailIds.length === 1) {
- msg += gettextCatalog.getString('The user %user% has no email, so the invitation email could not be send.');
- } else {
- msg += gettextCatalog.getString('The users %user% have no email, so the invitation emails could not be send.');
- }
-
- // This one builds a username string like "user1, user2 and user3" with the full names.
- var lastUsername, userString = _
- .chain(noEmailIds)
- .map(function (id) {
- var user = User.get(id);
- return user ? user.get_full_name() : '';
- })
- .filter(function (username) {
- return username;
- })
- .tap(function (names) {
- if (names.length !== 1) {
- lastUsername = names.pop();
- }
- })
- .join(', ')
- .thru(function (names) {
- return lastUsername ? names + ' ' + gettextCatalog.getString('and') + ' ' + lastUsername : names;
- })
- .value();
- msg = msg.replace('%user%', userString);
- }
-
- return {
- msg: msg,
- type: type,
- show: true,
- };
- });
- },
- };
- }
-])
-
-.controller('UserDetailCtrl', [
- '$scope',
- 'ngDialog',
- 'UserForm',
- 'User',
- 'userId',
- 'Group',
- 'Projector',
- 'ProjectionDefault',
- 'gettextCatalog',
- 'WebpageTitle',
- function($scope, ngDialog, UserForm, User, userId, Group, Projector, ProjectionDefault, gettextCatalog,
- WebpageTitle) {
- Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
- $scope.$watch(function () {
- return User.lastModified(userId);
- }, function () {
- $scope.user = User.get(userId);
- WebpageTitle.updateTitle(gettextCatalog.getString('Participant') + ' ' + $scope.user.get_short_name());
- });
- $scope.$watch(function () {
- return Projector.lastModified();
- }, function () {
- var projectiondefault = ProjectionDefault.filter({name: 'users'})[0];
- if (projectiondefault) {
- $scope.defaultProjectorId = projectiondefault.projector_id;
- }
- });
-
- // open edit dialog
- $scope.openDialog = function (user) {
- ngDialog.open(UserForm.getDialog(user));
- };
- }
-])
-
-.controller('UserCreateCtrl', [
- '$scope',
- '$state',
- 'User',
- 'UserForm',
- 'ErrorMessage',
- function($scope, $state, User, UserForm, ErrorMessage) {
- $scope.alert = {};
- // get all form fields
- $scope.formFields = UserForm.getFormFields(true);
-
- // save user
- $scope.save = function (user) {
- if (!user.groups_id) {
- user.groups_id = [];
- }
- User.create(user).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('UserUpdateCtrl', [
- '$scope',
- '$state',
- 'User',
- 'UserForm',
- 'userId',
- 'ErrorMessage',
- function($scope, $state, User, UserForm, userId, ErrorMessage) {
- $scope.alert = {};
- // set initial values for form model by create deep copy of user object
- // so list/detail view is not updated while editing
- $scope.model = angular.copy(User.get(userId));
-
- // get all form fields
- $scope.formFields = UserForm.getFormFields();
-
- // save user
- $scope.save = function (user) {
- if (!user.groups_id) {
- user.groups_id = [];
- }
- // inject the changed user (copy) object back into DS store
- User.inject(user);
- // save change user object on server
- User.save(user).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // save error: revert all changes by restore
- // (refresh) original user object from server
- User.refresh(user);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('UserProfileCtrl', [
- '$scope',
- 'Editor',
- 'User',
- 'operator',
- 'UserProfileForm',
- 'gettext',
- 'ErrorMessage',
- function($scope, Editor, User, operator, UserProfileForm, gettext, ErrorMessage) {
- $scope.model = angular.copy(operator.user);
- $scope.title = gettext('Edit profile');
- $scope.formFields = UserProfileForm.getFormFields();
- $scope.save = function (user) {
- User.inject(user);
- User.save(user).then(
- function(success) {
- $scope.closeThisDialog();
- },
- function(error) {
- // save error: revert all changes by restore
- // (refresh) original user object from server
- User.refresh(user);
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.controller('UserChangePasswordCtrl', [
- '$scope',
- '$state',
- '$http',
- 'User',
- 'userId',
- 'gettextCatalog',
- 'PasswordGenerator',
- 'ErrorMessage',
- function($scope, $state, $http, User, userId, gettextCatalog, PasswordGenerator, ErrorMessage) {
- User.bindOne(userId, $scope, 'user');
- $scope.alert = {};
- $scope.generatePassword = function () {
- $scope.new_password = PasswordGenerator.generate();
- };
- $scope.save = function (user) {
- if ($scope.new_password !== '') {
- $http.post(
- '/rest/users/user/' + user.id + '/reset_password/',
- {'password': $scope.new_password}
- ).then(
- function (success) {
- $scope.alert = {type: 'success', msg: success.data.detail, show: true};
- $scope.new_password = '';
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- }
- };
- }
-])
-
-.directive("showPassword", function() {
- return function linkFn(scope, elem, attrs) {
- scope.$watch(attrs.showPassword, function(value) {
- if (value) {
- elem.attr("type", "text");
- } else {
- elem.attr("type", "password");
- }
- });
- };
-})
-
-.controller('UserPasswordCtrl', [
- '$scope',
- '$state',
- '$http',
- 'gettext',
- 'UserPasswordForm',
- 'ErrorMessage',
- function($scope, $state, $http, gettext, UserPasswordForm, ErrorMessage) {
- $scope.title = 'Change password';
- $scope.alert = {};
- $scope.model = {};
- $scope.formFields = UserPasswordForm.getFormFields();
- $scope.save = function (data) {
- if (data.newPassword != data.newPassword2) {
- data.newPassword = data.newPassword2 = '';
- $scope.alert = {
- type: 'danger',
- msg: gettext('Password confirmation does not match.'),
- show: true,
- };
- } else {
- $http.post(
- '/users/setpassword/',
- {'old_password': data.oldPassword, 'new_password': data.newPassword}
- ).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- // Error, e. g. wrong old password.
- $scope.model = {};
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- }
- };
- }
-])
-
-.controller('UserPresenceCtrl', [
- '$scope',
- 'User',
- 'gettextCatalog',
- 'ErrorMessage',
- function ($scope, User, gettextCatalog, ErrorMessage) {
- $scope.alert = {};
- $('#userNumber').focus();
-
- $scope.changeState = function () {
- if (!$scope.number) {
- return;
- }
- var enteredNumber = $scope.number.trim();
- var user = _.find(User.getAll(), function (user) {
- return user.number === enteredNumber;
- });
- if (user) {
- user.is_present = !user.is_present;
- User.save(user).then(function (success) {
- var messageText = user.full_name + ' ' + gettextCatalog.getString('is now') + ' ';
- messageText += gettextCatalog.getString(user.is_present ? 'present' : 'not present') + '.';
- $scope.alert = {
- msg: messageText,
- show: true,
- type: 'success',
- };
- $scope.number = '';
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- } else {
- $scope.alert = {
- msg: gettextCatalog.getString('Cannot find the participant with the participant number') + ' "' + enteredNumber + '".',
- show: true,
- type: 'danger',
- };
- }
- $('#userNumber').focus();
- };
- }
-])
-
-.controller('UserImportCtrl', [
- '$scope',
- '$http',
- '$q',
- 'gettext',
- 'gettextCatalog',
- 'User',
- 'Group',
- 'UserCsvExport',
- 'osTablePagination',
- 'ErrorMessage',
- function($scope, $http, $q, gettext, gettextCatalog, User, Group, UserCsvExport,
- osTablePagination, ErrorMessage) {
- // import from textarea
- $scope.importByLine = function () {
- var usernames = $scope.userlist[0].split("\n");
- var users = _.map(usernames, function (name) {
- // Split each full name in first and last name.
- // The last word is set as last name, rest is the first name(s).
- // (e.g.: "Max Martin Mustermann" -> last_name = "Mustermann")
- var names = name.split(" ");
- var last_name = names.slice(-1)[0];
- var first_name = names.slice(0, -1).join(" ");
- return {
- first_name: first_name,
- last_name: last_name,
- groups_id: [],
- };
- });
- $http.post('/rest/users/user/mass_import/', {
- users: users
- }).then(function (success) {
- $scope.alert = {
- show: true,
- type: 'success',
- msg: success.data.detail,
- };
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- };
-
- // pagination
- $scope.pagination = osTablePagination.createInstance('UserImportTablePagination', 100);
-
- // Duplicates
- $scope.duplicateActions = [
- gettext('keep original'),
- gettext('override new'),
- gettext('create duplicate')
- ];
-
- // *** csv import ***
- $scope.csvConfig = {
- accept: '.csv, .txt',
- encodingOptions: ['UTF-8', 'ISO-8859-1'],
- parseConfig: {
- skipEmptyLines: true,
- },
- };
-
- var FIELDS = ['title', 'first_name', 'last_name', 'structure_level', 'number',
- 'groups', 'comment', 'is_active', 'is_present', 'is_committee', 'default_password', 'email'];
- $scope.users = [];
- $scope.onCsvChange = function (csv) {
- $scope.csvImporting = false;
- // All user objects are already loaded via the resolve statement from ui-router.
- var users = User.getAll();
- $scope.users = [];
-
- var csvUsers = [];
- _.forEach(csv.data, function (row) {
- if (row.length >= 2) {
- var filledRow = _.zipObject(FIELDS, row);
- csvUsers.push(filledRow);
- }
- });
- $scope.duplicates = 0;
- _.forEach(csvUsers, function (user, index) {
- user.importTrackId = index;
- user.selected = true;
- if (!user.first_name && !user.last_name) {
- user.importerror = true;
- user.name_error = gettext('Error: Given name or surname is required.');
- }
- // number
- if (!user.number) {
- user.number = "";
- }
- // groups
- user.groups_id = []; // will be overwritten if there are groups
- if (user.groups) {
- user.groups = user.groups.split(',');
- user.groups = _.map(user.groups, function (group) {
- return _.trim(group); // remove whitespaces on start or end
- });
-
- // All group objects are already loaded via the resolve statement from ui-router.
- var allGroups = Group.getAll();
- // in allGroupsNames ar all original group names and translated names if a
- // translation exists (e.g. for default group Delegates)
- var allGroupsNames = [];
- _.forEach(allGroups, function (group) {
- var groupTranslation = gettextCatalog.getString(group.name);
- if (group.name !== groupTranslation) {
- allGroupsNames.push(groupTranslation);
- }
- allGroupsNames.push(group.name);
- });
- user.groupsToCreate = _.difference(user.groups, allGroupsNames);
-
- // for template:
- user.groupsNotToCreate = _.difference(user.groups, user.groupsToCreate);
- } else {
- user.groups = [];
- }
- user.is_active = (user.is_active !== undefined && user.is_active === '1');
- user.is_present = (user.is_present !== undefined && user.is_present === '1');
- user.is_committee = (user.is_committee !== undefined && user.is_committee === '1');
-
- // Check for duplicates
- user.duplicate = false;
- users.forEach(function(user_) {
- user_.fullname = [
- user_.title,
- user_.first_name,
- user_.last_name,
- user_.structure_level].join(' ').trim();
- user.fullname = [
- user.title,
- user.first_name,
- user.last_name,
- user.structure_level].join(' ').trim();
- if (user_.fullname === user.fullname) {
- if (user.duplicate) {
- // there are multiple duplicates!
- user.duplicate_info += '\n' + gettextCatalog.getString('There are more than one duplicates of this user!');
- } else {
- user.duplicate = true;
- user.duplicateAction = $scope.duplicateActions[1];
- user.duplicate_info = '';
- if (user_.title)
- user.duplicate_info += user_.title + ' ';
- if (user_.first_name)
- user.duplicate_info += user_.first_name;
- if (user_.first_name && user_.last_name)
- user.duplicate_info += ' ';
- if (user_.last_name)
- user.duplicate_info += user_.last_name;
- user.duplicate_info += ' (';
- if (user_.number)
- user.duplicate_info += gettextCatalog.getString('Number') + ': ' + user_.number + ', ';
- if (user_.structure_level)
- user.duplicate_info += gettextCatalog.getString('Structure level') + ': ' + user_.structure_level + ', ';
- user.duplicate_info += gettextCatalog.getString('Username') + ': ' + user_.username + ') '+
- gettextCatalog.getString('already exists.');
-
- $scope.duplicates++;
- }
- }
- });
- $scope.users.push(user);
- });
- $scope.calcStats();
- };
-
- // Stats
- $scope.calcStats = function() {
- // not imported: if importerror or duplicate->keep original
- $scope.usersWillNotBeImported = 0;
- // imported: all others
- $scope.usersWillBeImported = 0;
-
- $scope.users.forEach(function(user) {
- if (!user.selected || user.importerror || (user.duplicate && user.duplicateAction == $scope.duplicateActions[0])) {
- $scope.usersWillNotBeImported++;
- } else {
- $scope.usersWillBeImported++;
- }
- });
- };
-
- $scope.setGlobalAction = function (action) {
- $scope.users.forEach(function (user) {
- if (user.duplicate)
- user.duplicateAction = action;
- });
- $scope.calcStats();
- };
-
- // import from csv file
- $scope.import = function () {
- $scope.csvImporting = true;
-
- // collect all needed groups and create non existing groups
- var groupsToCreate = [];
- _.forEach($scope.users, function (user) {
- if (user.selected && !user.importerror && user.groups.length) {
- _.forEach(user.groupsToCreate, function (group) { // Just append groups, that are not listed yet.
- if (_.indexOf(groupsToCreate, group) == -1) {
- groupsToCreate.push(group);
- }
- });
- }
- });
- var createPromises = [];
- $scope.groupsCreated = 0;
- _.forEach(groupsToCreate, function (groupname) {
- var group = {
- name: groupname,
- permissions: []
- };
- createPromises.push(Group.create(group).then( function (success) {
- $scope.groupsCreated++;
- }));
- });
-
- $q.all(createPromises).then(function () {
- // reload allGroups, now all new groups are created
- var allGroups = Group.getAll();
- var existingUsers = User.getAll();
-
- // For option 'delete existing user' on duplicates
- var deletePromises = [];
- // Array of users for mass import
- var usersToBeImported = [];
-
- _.forEach($scope.users, function (user) {
- if (user.selected && !user.importerror) {
- // Assign all groups
- _.forEach(user.groups, function(csvGroup) {
- allGroups.forEach(function (allGroup) {
- // check with and without translation
- if (csvGroup === allGroup.name ||
- csvGroup === gettextCatalog.getString(allGroup.name)) {
- user.groups_id.push(allGroup.id);
- }
- });
- });
-
- // Do nothing on duplicateAction==duplicateActions[0] (keep original)
- if (user.duplicate && (user.duplicateAction == $scope.duplicateActions[1])) {
- // delete existing user
- existingUsers.forEach(function(user_) {
- user_.fullname = [
- user_.title,
- user_.first_name,
- user_.last_name,
- user_.structure_level].join(' ').trim();
- user.fullname = [
- user.title,
- user.first_name,
- user.last_name,
- user.structure_level].join(' ').trim();
- if (user_.fullname === user.fullname) {
- deletePromises.push(User.destroy(user_.id));
- }
- });
- usersToBeImported.push(user);
- } else if (!user.duplicate ||
- (user.duplicateAction == $scope.duplicateActions[2])) {
- // create user
- usersToBeImported.push(user);
- }
- }
- });
- $q.all(deletePromises).then(function () {
- $http.post('/rest/users/user/mass_import/', {
- users: usersToBeImported
- }).then(function (success) {
- _.forEach(success.data.importedTrackIds, function (trackId) {
- _.find($scope.users, function (user) {
- return user.importTrackId === trackId;
- }).imported = true;
- });
- $scope.csvimported = true;
- }, function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- });
- });
- });
- };
- $scope.clear = function () {
- $scope.users = null;
- };
- $scope.excludeImportedUsers = function () {
- $scope.users = _.filter($scope.users, function (user) {
- return !user.imported;
- });
- $scope.csvImporting = false;
- $scope.calcStats();
- };
- $scope.someImportedUsers = function () {
- return _.some($scope.users, function (user) {
- return user.imported;
- });
- };
- // download CSV example file
- $scope.downloadCSVExample = function () {
- UserCsvExport.downloadExample();
- };
- }
-])
-
-.controller('GroupListCtrl', [
- '$scope',
- '$http',
- '$filter',
- 'operator',
- 'Group',
- 'permissions',
- 'gettext',
- 'Agenda',
- 'Assignment',
- 'Mediafile',
- 'Motion',
- 'User',
- 'ngDialog',
- 'OpenSlidesPlugins',
- function($scope, $http, $filter, operator, Group, permissions, gettext, Agenda,
- Assignment, Mediafile, Motion, User, ngDialog, OpenSlidesPlugins) {
- $scope.permissions = permissions;
-
- $scope.$watch(function() {
- return Group.lastModified();
- }, function() {
- $scope.groups = $filter('orderBy')(Group.getAll(), 'id');
-
- // find all groups with the 2 dangerous permissions
- var groups_danger = [];
- $scope.groups.forEach(function (group) {
- if ((_.indexOf(group.permissions, 'users.can_see_name') > -1) &&
- (_.indexOf(group.permissions, 'users.can_manage') > -1)){
- if (operator.isInGroup(group)){
- groups_danger.push(group);
- }
- }
- });
- // if there is only one dangerous group, block it.
- $scope.group_danger = groups_danger.length == 1 ? groups_danger[0] : null;
- });
-
- // Dict to map plugin name -> display_name
- var pluginTranslation = {};
- _.forEach(OpenSlidesPlugins.getAll(), function (plugin) {
- pluginTranslation[plugin.name] = plugin.display_name;
- });
- $scope.apps = [];
- // Create the main clustering with appname->permissions
- angular.forEach(permissions, function(perm) {
- var permissionApp = perm.value.split('.')[0]; // get appname
-
- // To insert perm in the right spot in $scope.apps
- var insert = function (id, perm, verboseName) {
- if (!$scope.apps[id]) {
- $scope.apps[id] = {
- app_name: verboseName,
- app_visible: true,
- permissions: []
- };
- }
- $scope.apps[id].permissions.push(perm);
- };
-
- switch(permissionApp) {
- case 'core': // id 0 (projector) and id 6 (general)
- if (perm.value.indexOf('projector') > -1) {
- insert(0, perm, gettext('Projector'));
- } else {
- insert(6, perm, gettext('General'));
- }
- break;
- case 'agenda': // id 1
- insert(1, perm, Agenda.verboseName);
- break;
- case 'motions': // id 2
- insert(2, perm, Motion.verboseNamePlural);
- break;
- case 'assignments': // id 3
- insert(3, perm, Assignment.verboseNamePlural);
- break;
- case 'mediafiles': // id 4
- insert(4, perm, Mediafile.verboseNamePlural);
- break;
- case 'users': // id 5
- insert(5, perm, User.verboseNamePlural);
- break;
- default: // plugins: id>5
- var display_name = pluginTranslation[permissionApp] || permissionApp.charAt(0).toUpperCase() +
- permissionApp.slice(1);
- // does the app exists?
- var result = -1;
- angular.forEach($scope.apps, function (app, index) {
- if (app.app_name === display_name)
- result = index;
- });
- var id = result == -1 ? $scope.apps.length : result;
- insert(id, perm, display_name);
- break;
- }
- });
-
- // sort each app: first all permission with 'see', then 'manage', then the rest
- // save the permissions in different lists an concat them in the right order together
- // Special Users: the two "see"-permissions are normally swapped. To create the right
- // order, we could simply reverse the whole permissions.
- angular.forEach($scope.apps, function (app, index) {
- if(index == 5) { // users
- app.permissions.reverse();
- } else { // rest
- var see = [];
- var manage = [];
- var others = [];
- angular.forEach(app.permissions, function (perm) {
- if (perm.value.indexOf('see') > -1) {
- see.push(perm);
- } else if (perm.value.indexOf('manage') > -1) {
- manage.push(perm);
- } else {
- others.push(perm);
- }
- });
- app.permissions = see.concat(manage.concat(others));
- }
- });
-
- // check if the given group has the given permission
- $scope.hasPerm = function (group, permission) {
- return _.indexOf(group.permissions, permission.value) > -1;
- };
-
- // The current user is not allowed to lock himself out of the configuration:
- // - if the permission is 'users.can_manage' or 'users.can_see'
- // - if the user is in only one group with these permissions (group_danger is set)
- $scope.danger = function (group, permission){
- if ($scope.group_danger){
- if (permission.value == 'users.can_see_name' ||
- permission.value == 'users.can_manage'){
- return $scope.group_danger == group;
- }
- }
- return false;
- };
-
- // delete selected group
- $scope.delete = function (group) {
- Group.destroy(group.id);
- };
-
- // save changed permission
- $scope.changePermission = function (group, perm) {
- if (!$scope.danger(group, perm)) {
- if (!$scope.hasPerm(group, perm)) { // activate perm
- group.permissions.push(perm.value);
- } else {
- // delete perm in group.permissions
- group.permissions = _.filter(group.permissions, function(value) {
- return value != perm.value; // remove perm
- });
- }
- Group.save(group);
- }
- };
-
- $scope.openDialog = function (group) {
- ngDialog.open({
- template: 'static/templates/users/group-edit.html',
- controller: group ? 'GroupRenameCtrl' : 'GroupCreateCtrl',
- className: 'ngdialog-theme-default wide-form',
- closeByEscape: false,
- closeByDocument: false,
- resolve: {
- group: function () {return group;},
- }
- });
- };
- }
-])
-
-.controller('GroupRenameCtrl', [
- '$scope',
- 'Group',
- 'group',
- 'gettextCatalog',
- 'ErrorMessage',
- function($scope, Group, group, gettextCatalog, ErrorMessage) {
- $scope.group = group;
- $scope.new_name = gettextCatalog.getString(group.name);
-
- $scope.alert = {};
- $scope.save = function() {
- var old_name = gettextCatalog.getString($scope.group.name);
- $scope.group.name = $scope.new_name;
- Group.save($scope.group).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- $scope.group.name = old_name;
- }
- );
- };
- }
-])
-
-.controller('GroupCreateCtrl', [
- '$scope',
- 'Group',
- 'ErrorMessage',
- function($scope, Group, ErrorMessage) {
- $scope.new_name = '';
- $scope.alert = {};
-
- $scope.save = function() {
- var group = {
- name: $scope.new_name,
- permissions: []
- };
-
- Group.create(group).then(
- function (success) {
- $scope.closeThisDialog();
- },
- function (error) {
- $scope.alert = ErrorMessage.forAlert(error);
- }
- );
- };
- }
-])
-
-.factory('UserMenu', [
- '$http',
- 'OpenSlides',
- 'ngDialog',
- 'UserProfileForm',
- 'UserPasswordForm',
- function ($http, OpenSlides, ngDialog, UserProfileForm, UserPasswordForm) {
- return {
- logout: function () {
- $http.post('/users/logout/').then(function (response) {
- // Success: User logged out, so reboot OpenSlides.
- OpenSlides.reboot();
- });
- },
- editProfile: function () {
- ngDialog.open(UserProfileForm.getDialog());
- },
- changePassword: function () {
- ngDialog.open(UserPasswordForm.getDialog());
- },
- };
- }
-])
-
-.controller('userMenu', [
- '$scope',
- 'UserMenu',
- function($scope, UserMenu) {
- $scope.logout = UserMenu.logout;
- $scope.editProfile = UserMenu.editProfile;
- $scope.changePassword = UserMenu.changePassword;
-
- }
-])
-
-.controller('LoginFormCtrl', [
- '$rootScope',
- '$scope',
- '$http',
- '$state',
- '$stateParams',
- '$q',
- 'operator',
- 'gettext',
- 'autoupdate',
- 'mainMenu',
- 'DS',
- 'ngDialog',
- function ($rootScope, $scope, $http, $state, $stateParams, $q, operator, gettext,
- autoupdate, mainMenu, DS, ngDialog) {
- $scope.alerts = [];
-
- if ($stateParams.msg) {
- $scope.alerts.push({
- type: 'danger',
- msg: $stateParams.msg,
- });
- }
-
- // check if guest login is allowed
- $scope.guestAllowed = $rootScope.guest_enabled;
-
- // get login info-text from server
- $http.get('/users/login/').then(function (success) {
- if(success.data.info_text) {
- $scope.alerts.push({
- type: 'success',
- msg: success.data.info_text
- });
- }
- });
- // check if cookies are enabled
- if (!navigator.cookieEnabled) {
- $scope.alerts.push({
- type: 'danger',
- msg: gettext('You have to enable cookies to use OpenSlides.'),
- });
- }
-
- // close alert function
- $scope.closeAlert = function(index) {
- $scope.alerts.splice(index, 1);
- };
- // login
- $scope.login = function () {
- $scope.closeThisDialog();
- $scope.alerts = [];
- var data = { 'username': $scope.username, 'password': $scope.password };
- if (!navigator.cookieEnabled) {
- data.cookies = false;
- }
- $http.post('/users/login/', data).then(
- function (response) {
- // Success: User logged in.
- // Clear store and reset deferred first message, if guests was enabled before.
- DS.clear();
- autoupdate.firstMessageDeferred = $q.defer();
- // The next lines are partly the same lines as in core/start.js
- autoupdate.newConnect();
- autoupdate.firstMessageDeferred.promise.then(function () {
- operator.setUser(response.data.user_id, response.data.user);
- $rootScope.operator = operator;
- mainMenu.updateMainMenu();
- $state.go('home');
- $rootScope.openslidesBootstrapDone = true;
- });
- },
- function (error) {
- // Error: Username or password is not correct.
- $state.transitionTo($state.current, {msg: error.data.detail}, {
- reload: true, inherit: false, notify: true
- });
- }
- );
- };
- // guest login
- $scope.guestLogin = function () {
- $scope.closeThisDialog();
- $state.go('home');
- };
- // quick fix, that we cannot change the state to the main privacy
- // policy view. Display it in a dialog..
- $scope.openPrivacyPolicyDialog = function () {
- ngDialog.open({
- template: 'static/templates/privacypolicydialog.html',
- className: 'ngdialog-theme-default wide-form',
- controller: 'PrivacyPolicyDialogCtrl',
- showClose: true,
- closeByEscape: true,
- closeByDocument: true,
- });
- };
- }
-])
-
-.controller('PrivacyPolicyDialogCtrl', [
- '$scope',
- 'PrivacyPolicy',
- function ($scope, PrivacyPolicy) {
- $scope.privacyPolicy = PrivacyPolicy;
- }
-])
-
-// Mark all users strings for translation in JavaScript.
-.config([
- 'gettext',
- function (gettext) {
- // permission strings (see models.py of each Django app)
- // agenda
- gettext('Can see agenda');
- gettext('Can manage agenda');
- gettext('Can manage list of speakers');
- gettext('Can see internal items and time scheduling of agenda');
- gettext('Can put oneself on the list of speakers');
- // assignments
- gettext('Can see elections');
- gettext('Can nominate another participant');
- gettext('Can nominate oneself');
- gettext('Can manage elections');
- // core
- gettext('Can see the projector');
- gettext('Can manage the projector');
- gettext('Can see the front page');
- gettext('Can manage tags');
- gettext('Can manage configuration');
- gettext('Can use the chat');
- gettext('Can manage the chat');
- gettext('Can manage logos and fonts');
- // mediafiles
- gettext('Can see the list of files');
- gettext('Can upload files');
- gettext('Can manage files');
- gettext('Can see hidden files');
- // motions
- gettext('Can see motions');
- gettext('Can create motions');
- gettext('Can support motions');
- gettext('Can manage motions');
- gettext('Can see comments');
- gettext('Can manage comments');
- // users
- gettext('Can see names of users');
- gettext('Can see extra data of users (e.g. present and comment)');
- gettext('Can manage users');
-
- // config strings in users/config_variables.py
- gettext('General');
- gettext('Sort name of participants by');
- gettext('Enable participant presence view');
- gettext('Participants');
- gettext('Given name');
- gettext('Surname');
- gettext('PDF');
- gettext('Welcome to OpenSlides');
- gettext('Title for access data and welcome PDF');
- gettext('[Place for your welcome and help text.]');
- gettext('Help text for access data and welcome PDF');
- gettext('System URL');
- gettext('Used for QRCode in PDF of access data.');
- gettext('WLAN name (SSID)');
- gettext('Used for WLAN QRCode in PDF of access data.');
- gettext('WLAN password');
- gettext('Used for WLAN QRCode in PDF of access data.');
- gettext('WLAN encryption');
- gettext('Used for WLAN QRCode in PDF of access data.');
- gettext('WEP');
- gettext('WPA/WPA2');
- gettext('No encryption');
- gettext('Email');
- gettext('Email sender');
- gettext('Email subject');
- gettext('Your login for {event_name}');
- gettext('You can use {event_name} as a placeholder.');
- gettext('Email body');
- gettext('Dear {name},\n\nthis is your OpenSlides login for the event {event_name}:\n\n {url}\n username: {username}\n password: {password}\n\nThis email was generated automatically.');
- gettext('Use these placeholders: {name}, {event_name}, {url}, {username}, {password}. The url referrs to the system url.');
- }
-]);
-
-
-// this is code from angular.js. Find a way to call this function from this file
-function getBlockNodes(nodes) {
- // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
- // collection, otherwise update the original collection.
- var node = nodes[0];
- var endNode = nodes[nodes.length - 1];
- var blockNodes = [node];
-
- do {
- node = node.nextSibling;
- if (!node) break;
- blockNodes.push(node);
- } while (node !== endNode);
-
- return $(blockNodes);
-}
-
-}());
diff --git a/openslides/users/static/templates/users/group-edit.html b/openslides/users/static/templates/users/group-edit.html
deleted file mode 100644
index 57d4e8342..000000000
--- a/openslides/users/static/templates/users/group-edit.html
+++ /dev/null
@@ -1,29 +0,0 @@
-Edit name
-Create new group
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/users/static/templates/users/group-list.html b/openslides/users/static/templates/users/group-list.html
deleted file mode 100644
index 79f86cf38..000000000
--- a/openslides/users/static/templates/users/group-list.html
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
- All your changes are saved immediately. Changes you make are only effective once you (or the users concerned) reload the page.
-
-
-
-
-
- Permissions
-
-
- {{ group.name | translate }}
-
-
- {{ group.name | translate | limitTo: 1 }}...
-
-
-
-
-
-
- {{ app.app_name | translate}}
-
-
-
-
-
- {{ permission.display_name | translate }}
-
-
-
-
-
-
-
-
-
diff --git a/openslides/users/static/templates/users/profile-password-form.html b/openslides/users/static/templates/users/profile-password-form.html
deleted file mode 100644
index 0150a84ba..000000000
--- a/openslides/users/static/templates/users/profile-password-form.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{{ title | translate }}
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/users/static/templates/users/slide_user.html b/openslides/users/static/templates/users/slide_user.html
deleted file mode 100644
index 41cfbc009..000000000
--- a/openslides/users/static/templates/users/slide_user.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
{{ user.get_full_name() }}
-
diff --git a/openslides/users/static/templates/users/user-change-password.html b/openslides/users/static/templates/users/user-change-password.html
deleted file mode 100644
index 09f824686..000000000
--- a/openslides/users/static/templates/users/user-change-password.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
diff --git a/openslides/users/static/templates/users/user-detail.html b/openslides/users/static/templates/users/user-detail.html
deleted file mode 100644
index 39a257341..000000000
--- a/openslides/users/static/templates/users/user-detail.html
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
diff --git a/openslides/users/static/templates/users/user-form.html b/openslides/users/static/templates/users/user-form.html
deleted file mode 100644
index 7f8f16619..000000000
--- a/openslides/users/static/templates/users/user-form.html
+++ /dev/null
@@ -1,17 +0,0 @@
-Edit participant
-New participant
-
-
- {{ alert.msg }}
-
-
-
diff --git a/openslides/users/static/templates/users/user-import.html b/openslides/users/static/templates/users/user-import.html
deleted file mode 100644
index 1b7c25a94..000000000
--- a/openslides/users/static/templates/users/user-import.html
+++ /dev/null
@@ -1,248 +0,0 @@
-
-
-
-
- {{ alert.msg }}
-
-
-
Import by copy/paste
-
Copy and paste your participant names in this textbox.
- Keep each person in a single line.
-
-
-
-
- Import
-
-
-
-
-
-
Import by CSV file
-
-
Select a CSV file
-
-
-
Please note:
-
- Required comma or semicolon separated values with these column header names in the first row :
-
- Title ,
- Given name ,
- Surname ,
- Structure level ,
- Participant number ,
- Groups ,
- Comment ,
- Is active ,
- Is present ,
- Is committee ,
- Initial password
- Email
-
- At least given name or surname have to be filled in. All
- other fields are optional and may be empty.
- Only double quotes are accepted as text delimiter (no single quotes).
- Download CSV example file
-
-
-
-
Preview
-
-
- Page {{ pagination.currentPage }} /
- {{ Math.ceil(users.length/pagination.itemsPerPage) }}
-
-
-
-
-
-
-
-
- {{ usersWillNotBeImported }}
- participants will be not imported.
-
-
-
- {{ duplicates }}
- duplicates !
-
-
-
- {{ usersWillBeImported }}
- participants will be imported.
-
-
-
-
-
-
-
-
- {{ usersImported.length }}
- participants were successfully imported.
- (Groups created : {{ groupsCreated }})
-
-
-
-
-
- Clear preview
-
-
- Exclude already imported users
-
-
- Import {{ usersWillBeImported }} participants
-
-
-
-
-
diff --git a/openslides/users/static/templates/users/user-list.html b/openslides/users/static/templates/users/user-list.html
deleted file mode 100644
index 699e5a5a3..000000000
--- a/openslides/users/static/templates/users/user-list.html
+++ /dev/null
@@ -1,487 +0,0 @@
-
-
-
-
- {{ alert.msg }}
-
-
-
-
-
-
- Select ...
-
-
-
-
-
-
-
- Export all
-
-
- Export filtered
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ usersFiltered.length }} /
- {{ users.length }} {{ "participants" | translate }},
- {{(users|filter:{selected:true}).length}} {{ "selected" | translate }}
-
-
-
-
-
- Page {{ pagination.currentPage }} /
- {{ pagination.getPageCount(usersFiltered) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- No. {{ user.number }}
-
-
-
- No. {{ user.number }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ (groups | filter: {id: group}:true)[0].name | translate }}, ,
- ... [+{{ user.groups_id.length - 2}}]
-
-
-
-
-
-
-
-
-
-
- {{ (groups | filter: {id: group})[0].name | translate }}, ,
- ... [+{{ user.groups_id.length - 2}}]
-
-
-
-
-
-
-
- Set structure level ...
- {{ user.structure_level }}
-
-
-
-
-
-
- {{ user.structure_level }}
-
-
-
-
-
-
-
- Set comment ...
- {{ user.comment }}
-
-
-
-
-
-
- {{ user.comment | limitTo:25}}{{ user.comment.length > 25 ? '...' : '' }}
-
-
-
-
-
-
- {{ user.last_email_send | date: 'yyyy-MM-dd HH:mm:ss' }}
-
-
-
-
-
-
-
-
- Present
-
-
-
-
- Present
-
-
-
-
-
-
-
-
-
-
diff --git a/openslides/users/static/templates/users/user-presence.html b/openslides/users/static/templates/users/user-presence.html
deleted file mode 100644
index 1eeeac341..000000000
--- a/openslides/users/static/templates/users/user-presence.html
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
- {{ alert.msg }}
-
-
-
-
diff --git a/openslides/utils/views.py b/openslides/utils/views.py
index 02e4efd4f..dbc6178d6 100644
--- a/openslides/utils/views.py
+++ b/openslides/utils/views.py
@@ -1,27 +1,8 @@
-import base64
-from typing import Any, Dict, List, Optional
+from typing import Any, Dict, List
-from django.contrib.staticfiles import finders
-from django.core.exceptions import ImproperlyConfigured
-from django.http import HttpResponse
-from django.views.decorators.csrf import ensure_csrf_cookie
-from django.views.generic.base import View
from rest_framework.response import Response
from rest_framework.views import APIView as _APIView
-from .arguments import arguments
-
-
-class CSRFMixin:
- """
- Adds the csrf cookie to the response.
- """
-
- @classmethod
- def as_view(cls, *args: Any, **kwargs: Any) -> View:
- view = super().as_view(*args, **kwargs) # type: ignore
- return ensure_csrf_cookie(view)
-
class APIView(_APIView):
"""
@@ -51,40 +32,3 @@ class APIView(_APIView):
# Add the http-methods and delete the method "method_call"
get = post = put = patch = delete = head = options = trace = method_call
del method_call
-
-
-class TemplateView(View):
- """
- A view to serve a single cached template file. Subclasses have to provide 'template_name'.
- The state dict is used to cache the template. The state variable is static, but the object ID
- is not allowed to change. So the State has to be saved in this dict. Search for 'Borg design
- pattern' for more information.
- """
- template_name: Optional[str] = None
- state: Dict[str, str] = {}
-
- def __init__(self, *args: Any, **kwargs: Any) -> None:
- super().__init__(*args, **kwargs)
-
- if self.template_name is None:
- raise ImproperlyConfigured("'template_name' is not provided.")
-
- no_caching = arguments.get('no_template_caching', False)
- if self.template_name not in self.state or no_caching:
- self.state[self.template_name] = self.load_template()
-
- def load_template(self) -> str:
- with open(finders.find(self.template_name)) as template:
- return template.read()
-
- def get(self, *args: Any, **kwargs: Any) -> HttpResponse:
- return HttpResponse(self.state[self.template_name]) # type: ignore
-
-
-class BinaryTemplateView(TemplateView):
- """
- Loads the specified binary template and encode it with base64.
- """
- def load_template(self) -> str:
- with open(finders.find(self.template_name), 'rb') as template:
- return base64.b64encode(template.read()).decode()
diff --git a/package.json b/package.json
deleted file mode 100644
index 06cd01ae9..000000000
--- a/package.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "name": "openslides",
- "private": true,
- "scripts": {
- "prepublish": "bower install && gulp",
- "karma": "karma start tests/karma/karma.conf.js",
- "karma:watch": "karma start tests/karma/karma.conf.js --single-run=false"
- },
- "devDependencies": {
- "angular-mocks": "~1.5.11",
- "bower": "^1.8.0",
- "gulp": "~4.0.0",
- "gulp-angular-gettext": "^2.2.0",
- "gulp-angular-templatecache": "^2.0.0",
- "gulp-concat": "^2.6.1",
- "gulp-cssnano": "^2.1.2",
- "gulp-if": "^2.0.2",
- "gulp-inject-string": "^1.1.0",
- "gulp-jshint": "^2.0.4",
- "gulp-rename": "^1.2.2",
- "gulp-sass": "^3.1.0",
- "gulp-sourcemaps": "^2.6.0",
- "gulp-uglify": "^2.1.2",
- "jasmine-core": "^2.6.1",
- "jshint": "^2.9.4",
- "karma": "^1.5.0",
- "karma-chrome-launcher": "^2.0.0",
- "karma-jasmine": "^1.1.0",
- "karma-phantomjs-launcher": "^1.0.4",
- "main-bower-files": "^2.13.1",
- "sprintf-js": "^1.0.3",
- "through2": "^2.0.3",
- "yargs": "^7.1.0"
- }
-}
diff --git a/tests/integration/core/test_views.py b/tests/integration/core/test_views.py
index cb4eda5e8..ebc6af9ec 100644
--- a/tests/integration/core/test_views.py
+++ b/tests/integration/core/test_views.py
@@ -1,6 +1,5 @@
import json
-from django.apps import apps
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
@@ -85,29 +84,6 @@ class VersionView(TestCase):
'url': ''}]})
-class WebclientJavaScriptView(TestCase):
- """
- Tests the generation of the JavaScript startup code.
- """
- def test_angular_constants(self):
- self.client.login(username='admin', password='admin')
- response = self.client.get(reverse('core_webclient_javascript', args=['site']))
- content = response.content.decode()
- constants = self.get_angular_constants_from_apps()
- for key, constant in constants.items():
- self.assertTrue(json.dumps(constant) in content)
-
- def get_angular_constants_from_apps(self):
- constants = {}
- for app in apps.get_app_configs():
- try:
- get_angular_constants = app.get_angular_constants
- except AttributeError:
- continue
- constants.update(get_angular_constants())
- return constants
-
-
class ConfigViewSet(TestCase):
"""
Tests requests to deal with config variables.
diff --git a/tests/unit/utils/test_views.py b/tests/unit/utils/test_views.py
index a47e2914e..21424bc0b 100644
--- a/tests/unit/utils/test_views.py
+++ b/tests/unit/utils/test_views.py
@@ -1,5 +1,4 @@
from unittest import TestCase
-from unittest.mock import patch
from openslides.utils import views
@@ -17,16 +16,3 @@ class TestAPIView(TestCase):
self.assertFalse(
hasattr(views.APIView, 'method_call'),
"The APIView should not have the method 'method_call'")
-
-
-class TestCSRFMixin(TestCase):
- @patch('builtins.super')
- def test_as_view(self, mock_super):
- """
- Tests, that ensure_csrf_cookie is called.
- """
- mock_super().as_view.return_value = 'super_view'
- with patch('openslides.utils.views.ensure_csrf_cookie') as ensure_csrf_cookie:
- views.CSRFMixin.as_view()
-
- ensure_csrf_cookie.assert_called_once_with('super_view')
diff --git a/yarn.lock b/yarn.lock
deleted file mode 100644
index 6a53663fa..000000000
--- a/yarn.lock
+++ /dev/null
@@ -1,5135 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@gulp-sourcemaps/identity-map@1.X":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9"
- dependencies:
- acorn "^5.0.3"
- css "^2.2.1"
- normalize-path "^2.1.1"
- source-map "^0.6.0"
- through2 "^2.0.3"
-
-"@gulp-sourcemaps/map-sources@1.X":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda"
- dependencies:
- normalize-path "^2.0.1"
- through2 "^2.0.3"
-
-abbrev@1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
-
-accepts@1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
- dependencies:
- mime-types "~2.1.11"
- negotiator "0.6.1"
-
-acorn@5.X, acorn@^5.0.3:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
-
-after@0.8.2:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
-
-ajv@^4.9.1:
- version "4.11.8"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
- dependencies:
- co "^4.6.0"
- json-stable-stringify "^1.0.1"
-
-ajv@^5.1.0:
- version "5.5.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
- dependencies:
- co "^4.6.0"
- fast-deep-equal "^1.0.0"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
-
-align-text@^0.1.1, align-text@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
- dependencies:
- kind-of "^3.0.2"
- longest "^1.0.1"
- repeat-string "^1.5.2"
-
-alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
-
-amdefine@>=0.0.4:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
-
-angular-gettext-tools@^2.2.0:
- version "2.3.11"
- resolved "https://registry.yarnpkg.com/angular-gettext-tools/-/angular-gettext-tools-2.3.11.tgz#61920670eb3e34ee8f958dd8a4a3c327ee4e5de4"
- dependencies:
- babylon "^6.11.4"
- binary-search "^1.2.0"
- cheerio "~0.19.0"
- lodash "^4.0.0"
- pofile "~1.0.0"
- typescript "~2.3.2"
- typescript-eslint-parser "^3.0.0"
-
-angular-mocks@~1.5.11:
- version "1.5.11"
- resolved "https://registry.yarnpkg.com/angular-mocks/-/angular-mocks-1.5.11.tgz#a0e1dd0ea55fd77ee7a757d75536c5e964c86f81"
-
-ansi-colors@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
- dependencies:
- ansi-wrap "^0.1.0"
-
-ansi-cyan@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873"
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-gray@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-red@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c"
- dependencies:
- ansi-wrap "0.1.0"
-
-ansi-regex@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
-
-ansi-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
-
-ansi-styles@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-
-ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
-
-anymatch@^1.3.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
- dependencies:
- micromatch "^2.1.5"
- normalize-path "^2.0.0"
-
-anymatch@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
- dependencies:
- micromatch "^3.1.4"
- normalize-path "^2.1.1"
-
-append-buffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1"
- dependencies:
- buffer-equal "^1.0.0"
-
-aproba@^1.0.3:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
-
-archy@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
-
-are-we-there-yet@~1.1.2:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
- dependencies:
- delegates "^1.0.0"
- readable-stream "^2.0.6"
-
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- dependencies:
- sprintf-js "~1.0.2"
-
-arr-diff@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a"
- dependencies:
- arr-flatten "^1.0.1"
- array-slice "^0.2.3"
-
-arr-diff@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
- dependencies:
- arr-flatten "^1.0.1"
-
-arr-diff@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
-
-arr-filter@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee"
- dependencies:
- make-iterator "^1.0.0"
-
-arr-flatten@^1.0.1, arr-flatten@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
-
-arr-map@^2.0.0, arr-map@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4"
- dependencies:
- make-iterator "^1.0.0"
-
-arr-union@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d"
-
-arr-union@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
-
-array-differ@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
-
-array-each@^1.0.0, array-each@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
-
-array-find-index@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
-
-array-initial@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795"
- dependencies:
- array-slice "^1.0.0"
- is-number "^4.0.0"
-
-array-last@^1.1.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336"
- dependencies:
- is-number "^4.0.0"
-
-array-slice@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
-
-array-slice@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
-
-array-sort@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a"
- dependencies:
- default-compare "^1.0.0"
- get-value "^2.0.6"
- kind-of "^5.0.2"
-
-array-union@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
- dependencies:
- array-uniq "^1.0.1"
-
-array-uniq@^1.0.1, array-uniq@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
-
-array-unique@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
-
-array-unique@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
-
-arraybuffer.slice@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca"
-
-arrify@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
-
-asn1@~0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
-
-assert-plus@1.0.0, assert-plus@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
-
-assert-plus@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
-
-assign-symbols@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
-
-async-done@^1.2.0, async-done@^1.2.2:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.1.tgz#14b7b73667b864c8f02b5b253fc9c6eddb777f3e"
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.2"
- process-nextick-args "^1.0.7"
- stream-exhaust "^1.0.1"
-
-async-each@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
-
-async-foreach@^0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
-
-async-settle@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b"
- dependencies:
- async-done "^1.2.2"
-
-async@^1.2.1:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
-
-asynckit@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-
-atob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a"
-
-autoprefixer@^6.3.1:
- version "6.7.7"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
- dependencies:
- browserslist "^1.7.6"
- caniuse-db "^1.0.30000634"
- normalize-range "^0.1.2"
- num2fraction "^1.2.2"
- postcss "^5.2.16"
- postcss-value-parser "^3.2.3"
-
-aws-sign2@~0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
-
-aws-sign2@~0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
-
-aws4@^1.2.1, aws4@^1.6.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
-
-babylon@^6.11.4:
- version "6.18.0"
- resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
-
-bach@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
- dependencies:
- arr-filter "^1.1.1"
- arr-flatten "^1.0.1"
- arr-map "^2.0.0"
- array-each "^1.0.0"
- array-initial "^1.0.0"
- array-last "^1.1.1"
- async-done "^1.2.2"
- async-settle "^1.0.0"
- now-and-later "^2.0.0"
-
-backo2@1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
-
-balanced-match@^0.4.2:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
-
-balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
-
-base64-arraybuffer@0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
-
-base64id@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
-
-base@^0.11.1:
- version "0.11.2"
- resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
- dependencies:
- cache-base "^1.0.1"
- class-utils "^0.3.5"
- component-emitter "^1.2.1"
- define-property "^1.0.0"
- isobject "^3.0.1"
- mixin-deep "^1.2.0"
- pascalcase "^0.1.1"
-
-bcrypt-pbkdf@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
- dependencies:
- tweetnacl "^0.14.3"
-
-beeper@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
-
-better-assert@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
- dependencies:
- callsite "1.0.0"
-
-binary-extensions@^1.0.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
-
-binary-search@^1.2.0:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.4.tgz#d15f44ff9226ef309d85247fa0dbfbf659955f56"
-
-blob@0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
-
-block-stream@*:
- version "0.0.9"
- resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
- dependencies:
- inherits "~2.0.0"
-
-bluebird@^3.3.0:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
-
-body-parser@^1.16.1:
- version "1.18.3"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
- dependencies:
- bytes "3.0.0"
- content-type "~1.0.4"
- debug "2.6.9"
- depd "~1.1.2"
- http-errors "~1.6.3"
- iconv-lite "0.4.23"
- on-finished "~2.3.0"
- qs "6.5.2"
- raw-body "2.3.3"
- type-is "~1.6.16"
-
-boolbase@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
-
-boom@2.x.x:
- version "2.10.1"
- resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
- dependencies:
- hoek "2.x.x"
-
-bower@^1.8.0:
- version "1.8.4"
- resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.4.tgz#e7876a076deb8137f7d06525dc5e8c66db82f28a"
-
-brace-expansion@^1.1.7:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-braces@^0.1.2:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6"
- dependencies:
- expand-range "^0.1.0"
-
-braces@^1.8.2:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
- dependencies:
- expand-range "^1.8.1"
- preserve "^0.2.0"
- repeat-element "^1.1.2"
-
-braces@^2.3.0, braces@^2.3.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
- dependencies:
- arr-flatten "^1.1.0"
- array-unique "^0.3.2"
- extend-shallow "^2.0.1"
- fill-range "^4.0.0"
- isobject "^3.0.1"
- repeat-element "^1.1.2"
- snapdragon "^0.8.1"
- snapdragon-node "^2.0.1"
- split-string "^3.0.2"
- to-regex "^3.0.1"
-
-browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
- version "1.7.7"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
- dependencies:
- caniuse-db "^1.0.30000639"
- electron-to-chromium "^1.2.7"
-
-buffer-equal@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
-
-buffer-from@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04"
-
-builtin-modules@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
-
-bytes@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
-
-cache-base@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
- dependencies:
- collection-visit "^1.0.0"
- component-emitter "^1.2.1"
- get-value "^2.0.6"
- has-value "^1.0.0"
- isobject "^3.0.1"
- set-value "^2.0.0"
- to-object-path "^0.3.0"
- union-value "^1.0.0"
- unset-value "^1.0.0"
-
-callsite@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
-
-camelcase-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
- dependencies:
- camelcase "^2.0.0"
- map-obj "^1.0.0"
-
-camelcase@^1.0.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
-
-camelcase@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
-
-camelcase@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
-
-caniuse-api@^1.5.2:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
- dependencies:
- browserslist "^1.3.6"
- caniuse-db "^1.0.30000529"
- lodash.memoize "^4.1.2"
- lodash.uniq "^4.5.0"
-
-caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000871"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000871.tgz#f1995c1fe31892649a7605957a80c92518423d4d"
-
-caseless@~0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
-
-center-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
- dependencies:
- align-text "^0.1.3"
- lazy-cache "^1.0.3"
-
-chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
- dependencies:
- ansi-styles "^2.2.1"
- escape-string-regexp "^1.0.2"
- has-ansi "^2.0.0"
- strip-ansi "^3.0.0"
- supports-color "^2.0.0"
-
-cheerio@~0.19.0:
- version "0.19.0"
- resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.19.0.tgz#772e7015f2ee29965096d71ea4175b75ab354925"
- dependencies:
- css-select "~1.0.0"
- dom-serializer "~0.1.0"
- entities "~1.1.1"
- htmlparser2 "~3.8.1"
- lodash "^3.2.0"
-
-chokidar@^1.4.1:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
- dependencies:
- anymatch "^1.3.0"
- async-each "^1.0.0"
- glob-parent "^2.0.0"
- inherits "^2.0.1"
- is-binary-path "^1.0.0"
- is-glob "^2.0.0"
- path-is-absolute "^1.0.0"
- readdirp "^2.0.0"
- optionalDependencies:
- fsevents "^1.0.0"
-
-chokidar@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
- dependencies:
- anymatch "^2.0.0"
- async-each "^1.0.0"
- braces "^2.3.0"
- glob-parent "^3.1.0"
- inherits "^2.0.1"
- is-binary-path "^1.0.0"
- is-glob "^4.0.0"
- lodash.debounce "^4.0.8"
- normalize-path "^2.1.1"
- path-is-absolute "^1.0.0"
- readdirp "^2.0.0"
- upath "^1.0.5"
- optionalDependencies:
- fsevents "^1.2.2"
-
-chownr@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
-
-clap@^1.0.9:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
- dependencies:
- chalk "^1.1.3"
-
-class-utils@^0.3.5:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
- dependencies:
- arr-union "^3.1.0"
- define-property "^0.2.5"
- isobject "^3.0.0"
- static-extend "^0.1.1"
-
-cli@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14"
- dependencies:
- exit "0.1.2"
- glob "^7.1.1"
-
-cliui@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
- dependencies:
- center-align "^0.1.1"
- right-align "^0.1.1"
- wordwrap "0.0.2"
-
-cliui@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
- dependencies:
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wrap-ansi "^2.0.0"
-
-clone-buffer@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
-
-clone-stats@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
-
-clone-stats@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
-
-clone@^1.0.0, clone@^1.0.2:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
-
-clone@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb"
-
-cloneable-readable@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65"
- dependencies:
- inherits "^2.0.1"
- process-nextick-args "^2.0.0"
- readable-stream "^2.3.5"
-
-co@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
-
-coa@~1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
- dependencies:
- q "^1.1.2"
-
-code-point-at@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
-
-collection-map@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c"
- dependencies:
- arr-map "^2.0.2"
- for-own "^1.0.0"
- make-iterator "^1.0.0"
-
-collection-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
- dependencies:
- map-visit "^1.0.0"
- object-visit "^1.0.0"
-
-color-convert@^1.3.0:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
- dependencies:
- color-name "1.1.1"
-
-color-name@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
-
-color-name@^1.0.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
-
-color-string@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
- dependencies:
- color-name "^1.0.0"
-
-color-support@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
-
-color@^0.11.0:
- version "0.11.4"
- resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
- dependencies:
- clone "^1.0.2"
- color-convert "^1.3.0"
- color-string "^0.3.0"
-
-colormin@^1.0.5:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
- dependencies:
- color "^0.11.0"
- css-color-names "0.0.4"
- has "^1.0.1"
-
-colors@^1.1.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d"
-
-colors@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
-
-combine-lists@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6"
- dependencies:
- lodash "^4.5.0"
-
-combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
- dependencies:
- delayed-stream "~1.0.0"
-
-component-bind@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
-
-component-emitter@1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"
-
-component-emitter@1.2.1, component-emitter@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
-
-component-inherit@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-
-concat-stream@1.6.2, concat-stream@^1.6.0:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
- dependencies:
- buffer-from "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^2.2.2"
- typedarray "^0.0.6"
-
-concat-with-sourcemaps@*, concat-with-sourcemaps@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e"
- dependencies:
- source-map "^0.6.1"
-
-connect@^3.6.0:
- version "3.6.6"
- resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524"
- dependencies:
- debug "2.6.9"
- finalhandler "1.1.0"
- parseurl "~1.3.2"
- utils-merge "1.0.1"
-
-console-browserify@1.1.x:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
- dependencies:
- date-now "^0.1.4"
-
-console-control-strings@^1.0.0, console-control-strings@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
-
-content-type@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
-
-convert-source-map@1.X, convert-source-map@^1.1.1, convert-source-map@^1.5.0:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
-
-cookie@0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
-
-copy-descriptor@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
-
-copy-props@^2.0.1:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.4.tgz#93bb1cadfafd31da5bb8a9d4b41f471ec3a72dfe"
- dependencies:
- each-props "^1.3.0"
- is-plain-object "^2.0.1"
-
-core-js@^2.2.0:
- version "2.5.7"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
-
-core-util-is@1.0.2, core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
-
-cross-spawn@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
- dependencies:
- lru-cache "^4.0.1"
- which "^1.2.9"
-
-cryptiles@2.x.x:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
- dependencies:
- boom "2.x.x"
-
-css-color-names@0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
-
-css-select@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.0.0.tgz#b1121ca51848dd264e2244d058cee254deeb44b0"
- dependencies:
- boolbase "~1.0.0"
- css-what "1.0"
- domutils "1.4"
- nth-check "~1.0.0"
-
-css-what@1.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/css-what/-/css-what-1.0.0.tgz#d7cc2df45180666f99d2b14462639469e00f736c"
-
-css@2.X, css@^2.2.1:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/css/-/css-2.2.3.tgz#f861f4ba61e79bedc962aa548e5780fd95cbc6be"
- dependencies:
- inherits "^2.0.1"
- source-map "^0.1.38"
- source-map-resolve "^0.5.1"
- urix "^0.1.0"
-
-cssnano@^3.0.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
- dependencies:
- autoprefixer "^6.3.1"
- decamelize "^1.1.2"
- defined "^1.0.0"
- has "^1.0.1"
- object-assign "^4.0.1"
- postcss "^5.0.14"
- postcss-calc "^5.2.0"
- postcss-colormin "^2.1.8"
- postcss-convert-values "^2.3.4"
- postcss-discard-comments "^2.0.4"
- postcss-discard-duplicates "^2.0.1"
- postcss-discard-empty "^2.0.1"
- postcss-discard-overridden "^0.1.1"
- postcss-discard-unused "^2.2.1"
- postcss-filter-plugins "^2.0.0"
- postcss-merge-idents "^2.1.5"
- postcss-merge-longhand "^2.0.1"
- postcss-merge-rules "^2.0.3"
- postcss-minify-font-values "^1.0.2"
- postcss-minify-gradients "^1.0.1"
- postcss-minify-params "^1.0.4"
- postcss-minify-selectors "^2.0.4"
- postcss-normalize-charset "^1.1.0"
- postcss-normalize-url "^3.0.7"
- postcss-ordered-values "^2.1.0"
- postcss-reduce-idents "^2.2.2"
- postcss-reduce-initial "^1.0.0"
- postcss-reduce-transforms "^1.0.3"
- postcss-svgo "^2.1.1"
- postcss-unique-selectors "^2.0.2"
- postcss-value-parser "^3.2.3"
- postcss-zindex "^2.0.1"
-
-csso@~2.3.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
- dependencies:
- clap "^1.0.9"
- source-map "^0.5.3"
-
-currently-unhandled@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
- dependencies:
- array-find-index "^1.0.1"
-
-custom-event@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
-
-d@1:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
- dependencies:
- es5-ext "^0.10.9"
-
-dashdash@^1.12.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
- dependencies:
- assert-plus "^1.0.0"
-
-date-now@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
-
-dateformat@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
-
-debug-fabulous@1.X:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e"
- dependencies:
- debug "3.X"
- memoizee "0.4.X"
- object-assign "4.X"
-
-debug@2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
- dependencies:
- ms "0.7.1"
-
-debug@2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c"
- dependencies:
- ms "0.7.2"
-
-debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- dependencies:
- ms "2.0.0"
-
-debug@3.X, debug@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
- dependencies:
- ms "2.0.0"
-
-decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
-
-decode-uri-component@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
-
-deep-extend@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
-
-default-compare@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f"
- dependencies:
- kind-of "^5.0.2"
-
-default-resolution@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684"
-
-define-properties@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
- dependencies:
- foreach "^2.0.5"
- object-keys "^1.0.8"
-
-define-property@^0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
- dependencies:
- is-descriptor "^0.1.0"
-
-define-property@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
- dependencies:
- is-descriptor "^1.0.0"
-
-define-property@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
- dependencies:
- is-descriptor "^1.0.2"
- isobject "^3.0.1"
-
-defined@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
-
-delayed-stream@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
-
-delegates@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-
-depd@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
-
-detect-file@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
-
-detect-libc@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
-
-detect-newline@2.X:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
-
-di@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
-
-dom-serialize@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b"
- dependencies:
- custom-event "~1.0.0"
- ent "~2.2.0"
- extend "^3.0.0"
- void-elements "^2.0.0"
-
-dom-serializer@0, dom-serializer@~0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
- dependencies:
- domelementtype "~1.1.1"
- entities "~1.1.1"
-
-domelementtype@1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
-
-domelementtype@~1.1.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
-
-domhandler@2.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738"
- dependencies:
- domelementtype "1"
-
-domutils@1.4:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.4.3.tgz#0865513796c6b306031850e175516baf80b72a6f"
- dependencies:
- domelementtype "1"
-
-domutils@1.5:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
- dependencies:
- dom-serializer "0"
- domelementtype "1"
-
-duplexer2@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
- dependencies:
- readable-stream "~1.1.9"
-
-duplexer@~0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
-
-duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410"
- dependencies:
- end-of-stream "^1.0.0"
- inherits "^2.0.1"
- readable-stream "^2.0.0"
- stream-shift "^1.0.0"
-
-each-props@^1.3.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333"
- dependencies:
- is-plain-object "^2.0.1"
- object.defaults "^1.1.0"
-
-ecc-jsbn@~0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
- dependencies:
- jsbn "~0.1.0"
-
-ee-first@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
-
-electron-to-chromium@^1.2.7:
- version "1.3.52"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0"
-
-encodeurl@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
-
-end-of-stream@^1.0.0, end-of-stream@^1.1.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
- dependencies:
- once "^1.4.0"
-
-engine.io-client@1.8.3:
- version "1.8.3"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab"
- dependencies:
- component-emitter "1.2.1"
- component-inherit "0.0.3"
- debug "2.3.3"
- engine.io-parser "1.3.2"
- has-cors "1.1.0"
- indexof "0.0.1"
- parsejson "0.0.3"
- parseqs "0.0.5"
- parseuri "0.0.5"
- ws "1.1.2"
- xmlhttprequest-ssl "1.5.3"
- yeast "0.1.2"
-
-engine.io-parser@1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.2.tgz#937b079f0007d0893ec56d46cb220b8cb435220a"
- dependencies:
- after "0.8.2"
- arraybuffer.slice "0.0.6"
- base64-arraybuffer "0.1.5"
- blob "0.0.4"
- has-binary "0.1.7"
- wtf-8 "1.0.0"
-
-engine.io@1.8.3:
- version "1.8.3"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.3.tgz#8de7f97895d20d39b85f88eeee777b2bd42b13d4"
- dependencies:
- accepts "1.3.3"
- base64id "1.0.0"
- cookie "0.3.1"
- debug "2.3.3"
- engine.io-parser "1.3.2"
- ws "1.1.2"
-
-ent@~2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
-
-entities@1.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26"
-
-entities@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
-
-error-ex@^1.2.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
- dependencies:
- is-arrayish "^0.2.1"
-
-es5-ext@^0.10.14, es5-ext@^0.10.30, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2:
- version "0.10.45"
- resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653"
- dependencies:
- es6-iterator "~2.0.3"
- es6-symbol "~3.1.1"
- next-tick "1"
-
-es6-iterator@^2.0.1, es6-iterator@~2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
- dependencies:
- d "1"
- es5-ext "^0.10.35"
- es6-symbol "^3.1.1"
-
-es6-promise@^4.0.3:
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
-
-es6-symbol@^3.1.1, es6-symbol@~3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
- dependencies:
- d "1"
- es5-ext "~0.10.14"
-
-es6-weak-map@^2.0.1, es6-weak-map@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
- dependencies:
- d "1"
- es5-ext "^0.10.14"
- es6-iterator "^2.0.1"
- es6-symbol "^3.1.1"
-
-escape-html@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
-
-escape-string-regexp@^1.0.2:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
-
-esprima@^2.6.0:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
-
-event-emitter@^0.3.5:
- version "0.3.5"
- resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
- dependencies:
- d "1"
- es5-ext "~0.10.14"
-
-event-stream@*, event-stream@3.3.4, event-stream@^3.1.7:
- version "3.3.4"
- resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
- dependencies:
- duplexer "~0.1.1"
- from "~0"
- map-stream "~0.1.0"
- pause-stream "0.0.11"
- split "0.3"
- stream-combiner "~0.0.4"
- through "~2.3.1"
-
-eventemitter3@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
-
-exit@0.1.2, exit@0.1.x:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
-
-expand-braces@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea"
- dependencies:
- array-slice "^0.2.3"
- array-unique "^0.2.1"
- braces "^0.1.2"
-
-expand-brackets@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
- dependencies:
- is-posix-bracket "^0.1.0"
-
-expand-brackets@^2.1.4:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
- dependencies:
- debug "^2.3.3"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- posix-character-classes "^0.1.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-expand-range@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044"
- dependencies:
- is-number "^0.1.1"
- repeat-string "^0.2.2"
-
-expand-range@^1.8.1:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
- dependencies:
- fill-range "^2.1.0"
-
-expand-tilde@^2.0.0, expand-tilde@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- dependencies:
- homedir-polyfill "^1.0.1"
-
-extend-shallow@^1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071"
- dependencies:
- kind-of "^1.1.0"
-
-extend-shallow@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
- dependencies:
- is-extendable "^0.1.0"
-
-extend-shallow@^3.0.0, extend-shallow@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
- dependencies:
- assign-symbols "^1.0.0"
- is-extendable "^1.0.1"
-
-extend@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/extend/-/extend-2.0.2.tgz#1b74985400171b85554894459c978de6ef453ab7"
-
-extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
-
-extglob@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
- dependencies:
- is-extglob "^1.0.0"
-
-extglob@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
- dependencies:
- array-unique "^0.3.2"
- define-property "^1.0.0"
- expand-brackets "^2.1.4"
- extend-shallow "^2.0.1"
- fragment-cache "^0.2.1"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-extract-zip@^1.6.5:
- version "1.6.7"
- resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
- dependencies:
- concat-stream "1.6.2"
- debug "2.6.9"
- mkdirp "0.5.1"
- yauzl "2.4.1"
-
-extsprintf@1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
-
-extsprintf@^1.2.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
-
-fancy-log@^1.1.0, fancy-log@^1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1"
- dependencies:
- ansi-gray "^0.1.1"
- color-support "^1.1.3"
- time-stamp "^1.0.0"
-
-fast-deep-equal@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
-
-fast-json-stable-stringify@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
-
-fd-slicer@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
- dependencies:
- pend "~1.2.0"
-
-filename-regex@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
-
-fill-range@^2.1.0:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
- dependencies:
- is-number "^2.1.0"
- isobject "^2.0.0"
- randomatic "^3.0.0"
- repeat-element "^1.1.2"
- repeat-string "^1.5.2"
-
-fill-range@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
- dependencies:
- extend-shallow "^2.0.1"
- is-number "^3.0.0"
- repeat-string "^1.6.1"
- to-regex-range "^2.1.0"
-
-finalhandler@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.1"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- parseurl "~1.3.2"
- statuses "~1.3.1"
- unpipe "~1.0.0"
-
-find-up@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
- dependencies:
- path-exists "^2.0.0"
- pinkie-promise "^2.0.0"
-
-findup-sync@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
- dependencies:
- detect-file "^1.0.0"
- is-glob "^3.1.0"
- micromatch "^3.0.4"
- resolve-dir "^1.0.1"
-
-fined@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476"
- dependencies:
- expand-tilde "^2.0.2"
- is-plain-object "^2.0.3"
- object.defaults "^1.1.0"
- object.pick "^1.2.0"
- parse-filepath "^1.0.1"
-
-first-chunk-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
-
-flagged-respawn@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.0.tgz#4e79ae9b2eb38bf86b3bb56bf3e0a56aa5fcabd7"
-
-flatten@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
-
-flush-write-stream@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
- dependencies:
- inherits "^2.0.1"
- readable-stream "^2.0.4"
-
-follow-redirects@^1.0.0:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291"
- dependencies:
- debug "^3.1.0"
-
-for-in@^1.0.1, for-in@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
-
-for-own@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
- dependencies:
- for-in "^1.0.1"
-
-for-own@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
- dependencies:
- for-in "^1.0.1"
-
-foreach@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
-
-forever-agent@~0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
-
-fork-stream@^0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
-
-form-data@~2.1.1:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.5"
- mime-types "^2.1.12"
-
-form-data@~2.3.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
- dependencies:
- asynckit "^0.4.0"
- combined-stream "1.0.6"
- mime-types "^2.1.12"
-
-fragment-cache@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
- dependencies:
- map-cache "^0.2.2"
-
-from@~0:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
-
-fs-access@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a"
- dependencies:
- null-check "^1.0.0"
-
-fs-extra@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950"
- dependencies:
- graceful-fs "^4.1.2"
- jsonfile "^2.1.0"
- klaw "^1.0.0"
-
-fs-minipass@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
- dependencies:
- minipass "^2.2.1"
-
-fs-mkdirp-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb"
- dependencies:
- graceful-fs "^4.1.11"
- through2 "^2.0.3"
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-
-fsevents@^1.0.0, fsevents@^1.2.2:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
- dependencies:
- nan "^2.9.2"
- node-pre-gyp "^0.10.0"
-
-fstream@^1.0.0, fstream@^1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
- dependencies:
- graceful-fs "^4.1.2"
- inherits "~2.0.0"
- mkdirp ">=0.5 0"
- rimraf "2"
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-
-gauge@~2.7.3:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
- dependencies:
- aproba "^1.0.3"
- console-control-strings "^1.0.0"
- has-unicode "^2.0.0"
- object-assign "^4.1.0"
- signal-exit "^3.0.0"
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wide-align "^1.1.0"
-
-gaze@^1.0.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
- dependencies:
- globule "^1.0.0"
-
-get-caller-file@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
-
-get-stdin@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
-
-get-value@^2.0.3, get-value@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
-
-getpass@^0.1.1:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
- dependencies:
- assert-plus "^1.0.0"
-
-glob-base@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
- dependencies:
- glob-parent "^2.0.0"
- is-glob "^2.0.0"
-
-glob-parent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
- dependencies:
- is-glob "^2.0.0"
-
-glob-parent@^3.0.0, glob-parent@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
- dependencies:
- is-glob "^3.1.0"
- path-dirname "^1.0.0"
-
-glob-stream@^5.3.2:
- version "5.3.5"
- resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
- dependencies:
- extend "^3.0.0"
- glob "^5.0.3"
- glob-parent "^3.0.0"
- micromatch "^2.3.7"
- ordered-read-streams "^0.3.0"
- through2 "^0.6.0"
- to-absolute-glob "^0.1.1"
- unique-stream "^2.0.2"
-
-glob-stream@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
- dependencies:
- extend "^3.0.0"
- glob "^7.1.1"
- glob-parent "^3.1.0"
- is-negated-glob "^1.0.0"
- ordered-read-streams "^1.0.0"
- pumpify "^1.3.5"
- readable-stream "^2.1.5"
- remove-trailing-separator "^1.0.1"
- to-absolute-glob "^2.0.0"
- unique-stream "^2.0.2"
-
-glob-watcher@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.1.tgz#239aaa621b6bd843b288fdf6b155f50963c7d7ea"
- dependencies:
- async-done "^1.2.0"
- chokidar "^2.0.0"
- just-debounce "^1.0.0"
- object.defaults "^1.1.0"
-
-glob@^5.0.3:
- version "5.0.15"
- resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^6.0.4:
- version "6.0.4"
- resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-global-modules@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
- dependencies:
- global-prefix "^1.0.1"
- is-windows "^1.0.1"
- resolve-dir "^1.0.0"
-
-global-prefix@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
- dependencies:
- expand-tilde "^2.0.2"
- homedir-polyfill "^1.0.1"
- ini "^1.3.4"
- is-windows "^1.0.1"
- which "^1.2.14"
-
-globby@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-2.1.0.tgz#9e9192bcd33f4ab6a4f894e5e7ea8b713213c482"
- dependencies:
- array-union "^1.0.1"
- async "^1.2.1"
- glob "^5.0.3"
- object-assign "^3.0.0"
-
-globule@^1.0.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
- dependencies:
- glob "~7.1.1"
- lodash "~4.17.10"
- minimatch "~3.0.2"
-
-glogg@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
- dependencies:
- sparkles "^1.0.0"
-
-graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
- version "4.1.11"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
-
-gulp-angular-gettext@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/gulp-angular-gettext/-/gulp-angular-gettext-2.2.0.tgz#90b5f38e89b4be491e8bb5cabaf69b0a71ddf95f"
- dependencies:
- angular-gettext-tools "^2.2.0"
- gulp-util "^3.0.7"
- lodash.isstring "^4.0.1"
- through2 "^2.0.1"
-
-gulp-angular-templatecache@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/gulp-angular-templatecache/-/gulp-angular-templatecache-2.2.1.tgz#f08088fd4b1a80733d627c4ba24728d4e9cca8a9"
- dependencies:
- event-stream "3.3.4"
- gulp-concat "2.6.1"
- gulp-footer "2.0.1"
- gulp-header "2.0.5"
- jsesc "2.5.1"
- lodash.template "^4.4.0"
- through2 "^2.0.3"
-
-gulp-cli@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.0.1.tgz#7847e220cb3662f2be8a6d572bf14e17be5a994b"
- dependencies:
- ansi-colors "^1.0.1"
- archy "^1.0.0"
- array-sort "^1.0.0"
- color-support "^1.1.3"
- concat-stream "^1.6.0"
- copy-props "^2.0.1"
- fancy-log "^1.3.2"
- gulplog "^1.0.0"
- interpret "^1.1.0"
- isobject "^3.0.1"
- liftoff "^2.5.0"
- matchdep "^2.0.0"
- mute-stdout "^1.0.0"
- pretty-hrtime "^1.0.0"
- replace-homedir "^1.0.0"
- semver-greatest-satisfied-range "^1.1.0"
- v8flags "^3.0.1"
- yargs "^7.1.0"
-
-gulp-concat@2.6.1, gulp-concat@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353"
- dependencies:
- concat-with-sourcemaps "^1.0.0"
- through2 "^2.0.0"
- vinyl "^2.0.0"
-
-gulp-cssnano@^2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/gulp-cssnano/-/gulp-cssnano-2.1.3.tgz#02007e2817af09b3688482b430ad7db807aebf72"
- dependencies:
- buffer-from "^1.0.0"
- cssnano "^3.0.0"
- object-assign "^4.0.1"
- plugin-error "^1.0.1"
- vinyl-sourcemaps-apply "^0.2.1"
-
-gulp-footer@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/gulp-footer/-/gulp-footer-2.0.1.tgz#76578359feb72aa280a97cb980bcfbe0e6216f3e"
- dependencies:
- event-stream "*"
- lodash._reescape "^3.0.0"
- lodash._reevaluate "^3.0.0"
- lodash._reinterpolate "^3.0.0"
- lodash.template "^3.6.2"
-
-gulp-header@2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-2.0.5.tgz#16e229c73593ade301168024fea68dab75d9d38c"
- dependencies:
- concat-with-sourcemaps "*"
- lodash.template "^4.4.0"
- through2 "^2.0.0"
-
-gulp-if@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
- dependencies:
- gulp-match "^1.0.3"
- ternary-stream "^2.0.1"
- through2 "^2.0.1"
-
-gulp-inject-string@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/gulp-inject-string/-/gulp-inject-string-1.1.1.tgz#94e7a1b5d4102720edbc7491652a2c3d6e8c5bb8"
- dependencies:
- event-stream "^3.1.7"
- plugin-error "^0.1.2"
-
-gulp-jshint@^2.0.4:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/gulp-jshint/-/gulp-jshint-2.1.0.tgz#bfaf927f78eee263c5bbac5f63e314d44a7bd41e"
- dependencies:
- lodash "^4.12.0"
- minimatch "^3.0.3"
- plugin-error "^0.1.2"
- rcloader "^0.2.2"
- through2 "^2.0.0"
-
-gulp-match@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e"
- dependencies:
- minimatch "^3.0.3"
-
-gulp-rename@^1.2.2:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.4.0.tgz#de1c718e7c4095ae861f7296ef4f3248648240bd"
-
-gulp-sass@^3.1.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/gulp-sass/-/gulp-sass-3.2.1.tgz#2e3688a96fd8be1c0c01340750c191b2e79fab94"
- dependencies:
- gulp-util "^3.0"
- lodash.clonedeep "^4.3.2"
- node-sass "^4.8.3"
- through2 "^2.0.0"
- vinyl-sourcemaps-apply "^0.2.0"
-
-gulp-sourcemaps@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
- dependencies:
- convert-source-map "^1.1.1"
- graceful-fs "^4.1.2"
- strip-bom "^2.0.0"
- through2 "^2.0.0"
- vinyl "^1.0.0"
-
-gulp-sourcemaps@^2.6.0:
- version "2.6.4"
- resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.6.4.tgz#cbb2008450b1bcce6cd23bf98337be751bf6e30a"
- dependencies:
- "@gulp-sourcemaps/identity-map" "1.X"
- "@gulp-sourcemaps/map-sources" "1.X"
- acorn "5.X"
- convert-source-map "1.X"
- css "2.X"
- debug-fabulous "1.X"
- detect-newline "2.X"
- graceful-fs "4.X"
- source-map "~0.6.0"
- strip-bom-string "1.X"
- through2 "2.X"
-
-gulp-uglify@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-2.1.2.tgz#6db85b1d0ee63d18058592b658649d65c2ec4541"
- dependencies:
- gulplog "^1.0.0"
- has-gulplog "^0.1.0"
- lodash "^4.13.1"
- make-error-cause "^1.1.1"
- through2 "^2.0.0"
- uglify-js "~2.8.10"
- uglify-save-license "^0.4.1"
- vinyl-sourcemaps-apply "^0.2.0"
-
-gulp-util@^3.0, gulp-util@^3.0.7:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
- dependencies:
- array-differ "^1.0.0"
- array-uniq "^1.0.2"
- beeper "^1.0.0"
- chalk "^1.0.0"
- dateformat "^2.0.0"
- fancy-log "^1.1.0"
- gulplog "^1.0.0"
- has-gulplog "^0.1.0"
- lodash._reescape "^3.0.0"
- lodash._reevaluate "^3.0.0"
- lodash._reinterpolate "^3.0.0"
- lodash.template "^3.0.0"
- minimist "^1.1.0"
- multipipe "^0.1.2"
- object-assign "^3.0.0"
- replace-ext "0.0.1"
- through2 "^2.0.0"
- vinyl "^0.5.0"
-
-gulp@~4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.0.tgz#95766c601dade4a77ed3e7b2b6dc03881b596366"
- dependencies:
- glob-watcher "^5.0.0"
- gulp-cli "^2.0.0"
- undertaker "^1.0.0"
- vinyl-fs "^3.0.0"
-
-gulplog@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
- dependencies:
- glogg "^1.0.0"
-
-har-schema@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
-
-har-schema@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
-
-har-validator@~4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
- dependencies:
- ajv "^4.9.1"
- har-schema "^1.0.5"
-
-har-validator@~5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
- dependencies:
- ajv "^5.1.0"
- har-schema "^2.0.0"
-
-has-ansi@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
- dependencies:
- ansi-regex "^2.0.0"
-
-has-binary@0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c"
- dependencies:
- isarray "0.0.1"
-
-has-cors@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
-
-has-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
-
-has-gulplog@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
- dependencies:
- sparkles "^1.0.0"
-
-has-symbols@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
-
-has-unicode@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
-
-has-value@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
- dependencies:
- get-value "^2.0.3"
- has-values "^0.1.4"
- isobject "^2.0.0"
-
-has-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
- dependencies:
- get-value "^2.0.6"
- has-values "^1.0.0"
- isobject "^3.0.0"
-
-has-values@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
-
-has-values@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
- dependencies:
- is-number "^3.0.0"
- kind-of "^4.0.0"
-
-has@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- dependencies:
- function-bind "^1.1.1"
-
-hasha@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1"
- dependencies:
- is-stream "^1.0.1"
- pinkie-promise "^2.0.0"
-
-hawk@~3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
- dependencies:
- boom "2.x.x"
- cryptiles "2.x.x"
- hoek "2.x.x"
- sntp "1.x.x"
-
-hoek@2.x.x:
- version "2.16.3"
- resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
-
-homedir-polyfill@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
- dependencies:
- parse-passwd "^1.0.0"
-
-hosted-git-info@^2.1.4:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
-
-html-comment-regex@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
-
-htmlparser2@3.8.x, htmlparser2@~3.8.1:
- version "3.8.3"
- resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068"
- dependencies:
- domelementtype "1"
- domhandler "2.3"
- domutils "1.5"
- entities "1.0"
- readable-stream "1.1"
-
-http-errors@1.6.3, http-errors@~1.6.3:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.0"
- statuses ">= 1.4.0 < 2"
-
-http-proxy@^1.13.0:
- version "1.17.0"
- resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
- dependencies:
- eventemitter3 "^3.0.0"
- follow-redirects "^1.0.0"
- requires-port "^1.0.0"
-
-http-signature@~1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
- dependencies:
- assert-plus "^0.2.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
-
-http-signature@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
- dependencies:
- assert-plus "^1.0.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
-
-iconv-lite@0.4.23, iconv-lite@^0.4.4:
- version "0.4.23"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
- dependencies:
- safer-buffer ">= 2.1.2 < 3"
-
-ignore-walk@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
- dependencies:
- minimatch "^3.0.4"
-
-in-publish@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
-
-indent-string@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
- dependencies:
- repeating "^2.0.0"
-
-indexes-of@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
-
-indexof@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-
-ini@^1.3.4, ini@~1.3.0:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
-
-interpret@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
-
-invert-kv@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
-
-is-absolute-url@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
-
-is-absolute@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
- dependencies:
- is-relative "^1.0.0"
- is-windows "^1.0.1"
-
-is-accessor-descriptor@^0.1.6:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
- dependencies:
- kind-of "^3.0.2"
-
-is-accessor-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
- dependencies:
- kind-of "^6.0.0"
-
-is-arrayish@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
-
-is-binary-path@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
- dependencies:
- binary-extensions "^1.0.0"
-
-is-buffer@^1.1.5:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
-
-is-builtin-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
- dependencies:
- builtin-modules "^1.0.0"
-
-is-data-descriptor@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
- dependencies:
- kind-of "^3.0.2"
-
-is-data-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
- dependencies:
- kind-of "^6.0.0"
-
-is-descriptor@^0.1.0:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
- dependencies:
- is-accessor-descriptor "^0.1.6"
- is-data-descriptor "^0.1.4"
- kind-of "^5.0.0"
-
-is-descriptor@^1.0.0, is-descriptor@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
- dependencies:
- is-accessor-descriptor "^1.0.0"
- is-data-descriptor "^1.0.0"
- kind-of "^6.0.2"
-
-is-dotfile@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
-
-is-equal-shallow@^0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
- dependencies:
- is-primitive "^2.0.0"
-
-is-extendable@^0.1.0, is-extendable@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
-
-is-extendable@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
- dependencies:
- is-plain-object "^2.0.4"
-
-is-extglob@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
-
-is-extglob@^2.1.0, is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
-
-is-finite@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
- dependencies:
- number-is-nan "^1.0.0"
-
-is-fullwidth-code-point@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
- dependencies:
- number-is-nan "^1.0.0"
-
-is-fullwidth-code-point@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
-
-is-glob@^2.0.0, is-glob@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
- dependencies:
- is-extglob "^1.0.0"
-
-is-glob@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
- dependencies:
- is-extglob "^2.1.0"
-
-is-glob@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
- dependencies:
- is-extglob "^2.1.1"
-
-is-negated-glob@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
-
-is-number@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806"
-
-is-number@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
- dependencies:
- kind-of "^3.0.2"
-
-is-number@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
- dependencies:
- kind-of "^3.0.2"
-
-is-number@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
-
-is-plain-obj@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
-
-is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
- dependencies:
- isobject "^3.0.1"
-
-is-posix-bracket@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
-
-is-primitive@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
-
-is-promise@^2.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
-
-is-relative@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
- dependencies:
- is-unc-path "^1.0.0"
-
-is-stream@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
-
-is-svg@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
- dependencies:
- html-comment-regex "^1.1.0"
-
-is-typedarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
-
-is-unc-path@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
- dependencies:
- unc-path-regex "^0.1.2"
-
-is-utf8@^0.2.0, is-utf8@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
-
-is-valid-glob@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
-
-is-valid-glob@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
-
-is-windows@^1.0.1, is-windows@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
-
-isarray@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
-
-isarray@1.0.0, isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
-
-isbinaryfile@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621"
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
-
-isobject@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
- dependencies:
- isarray "1.0.0"
-
-isobject@^3.0.0, isobject@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
-
-isstream@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
-
-jasmine-core@^2.6.1:
- version "2.99.1"
- resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"
-
-js-base64@^2.1.8, js-base64@^2.1.9:
- version "2.4.8"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033"
-
-js-yaml@~3.7.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
- dependencies:
- argparse "^1.0.7"
- esprima "^2.6.0"
-
-jsbn@~0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
-
-jsesc@2.5.1:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe"
-
-jshint@^2.9.4:
- version "2.9.5"
- resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.9.5.tgz#1e7252915ce681b40827ee14248c46d34e9aa62c"
- dependencies:
- cli "~1.0.0"
- console-browserify "1.1.x"
- exit "0.1.x"
- htmlparser2 "3.8.x"
- lodash "3.7.x"
- minimatch "~3.0.2"
- shelljs "0.3.x"
- strip-json-comments "1.0.x"
-
-json-schema-traverse@^0.3.0:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
-
-json-schema@0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
-
-json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
- dependencies:
- jsonify "~0.0.0"
-
-json-stringify-safe@~5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
-
-json3@3.3.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
-
-jsonfile@^2.1.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
- optionalDependencies:
- graceful-fs "^4.1.6"
-
-jsonify@~0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
-
-jsprim@^1.2.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
- dependencies:
- assert-plus "1.0.0"
- extsprintf "1.3.0"
- json-schema "0.2.3"
- verror "1.10.0"
-
-just-debounce@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea"
-
-karma-chrome-launcher@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf"
- dependencies:
- fs-access "^1.0.0"
- which "^1.2.1"
-
-karma-jasmine@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.2.tgz#394f2b25ffb4a644b9ada6f22d443e2fd08886c3"
-
-karma-phantomjs-launcher@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz#d23ca34801bda9863ad318e3bb4bd4062b13acd2"
- dependencies:
- lodash "^4.0.1"
- phantomjs-prebuilt "^2.1.7"
-
-karma@^1.5.0:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/karma/-/karma-1.7.1.tgz#85cc08e9e0a22d7ce9cca37c4a1be824f6a2b1ae"
- dependencies:
- bluebird "^3.3.0"
- body-parser "^1.16.1"
- chokidar "^1.4.1"
- colors "^1.1.0"
- combine-lists "^1.0.0"
- connect "^3.6.0"
- core-js "^2.2.0"
- di "^0.0.1"
- dom-serialize "^2.2.0"
- expand-braces "^0.1.1"
- glob "^7.1.1"
- graceful-fs "^4.1.2"
- http-proxy "^1.13.0"
- isbinaryfile "^3.0.0"
- lodash "^3.8.0"
- log4js "^0.6.31"
- mime "^1.3.4"
- minimatch "^3.0.2"
- optimist "^0.6.1"
- qjobs "^1.1.4"
- range-parser "^1.2.0"
- rimraf "^2.6.0"
- safe-buffer "^5.0.1"
- socket.io "1.7.3"
- source-map "^0.5.3"
- tmp "0.0.31"
- useragent "^2.1.12"
-
-kew@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b"
-
-kind-of@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44"
-
-kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^5.0.0, kind-of@^5.0.2:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
-
-kind-of@^6.0.0, kind-of@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
-
-klaw@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439"
- optionalDependencies:
- graceful-fs "^4.1.9"
-
-last-run@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
- dependencies:
- default-resolution "^2.0.0"
- es6-weak-map "^2.0.1"
-
-lazy-cache@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
-
-lazystream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
- dependencies:
- readable-stream "^2.0.5"
-
-lcid@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
- dependencies:
- invert-kv "^1.0.0"
-
-lead@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42"
- dependencies:
- flush-write-stream "^1.0.2"
-
-liftoff@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec"
- dependencies:
- extend "^3.0.0"
- findup-sync "^2.0.0"
- fined "^1.0.1"
- flagged-respawn "^1.0.0"
- is-plain-object "^2.0.4"
- object.map "^1.0.0"
- rechoir "^0.6.2"
- resolve "^1.1.7"
-
-load-json-file@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
-
-lodash._basecopy@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
-
-lodash._basetostring@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
-
-lodash._basevalues@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
-
-lodash._getnative@^3.0.0:
- version "3.9.1"
- resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
-
-lodash._isiterateecall@^3.0.0:
- version "3.0.9"
- resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
-
-lodash._reescape@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
-
-lodash._reevaluate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
-
-lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
-
-lodash._root@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
-
-lodash.assign@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-
-lodash.clonedeep@^4.3.2:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
-
-lodash.debounce@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
-
-lodash.escape@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
- dependencies:
- lodash._root "^3.0.0"
-
-lodash.isarguments@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
-
-lodash.isarray@^3.0.0:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
-
-lodash.isequal@^4.0.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
-
-lodash.isobject@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d"
-
-lodash.isstring@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
-
-lodash.keys@^3.0.0:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
- dependencies:
- lodash._getnative "^3.0.0"
- lodash.isarguments "^3.0.0"
- lodash.isarray "^3.0.0"
-
-lodash.memoize@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
-
-lodash.merge@^4.6.0:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
-
-lodash.mergewith@^4.6.0:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
-
-lodash.restparam@^3.0.0:
- version "3.6.1"
- resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
-
-lodash.template@^3.0.0, lodash.template@^3.6.2:
- version "3.6.2"
- resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
- dependencies:
- lodash._basecopy "^3.0.0"
- lodash._basetostring "^3.0.0"
- lodash._basevalues "^3.0.0"
- lodash._isiterateecall "^3.0.0"
- lodash._reinterpolate "^3.0.0"
- lodash.escape "^3.0.0"
- lodash.keys "^3.0.0"
- lodash.restparam "^3.0.0"
- lodash.templatesettings "^3.0.0"
-
-lodash.template@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
- dependencies:
- lodash._reinterpolate "~3.0.0"
- lodash.templatesettings "^4.0.0"
-
-lodash.templatesettings@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
- dependencies:
- lodash._reinterpolate "^3.0.0"
- lodash.escape "^3.0.0"
-
-lodash.templatesettings@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
- dependencies:
- lodash._reinterpolate "~3.0.0"
-
-lodash.unescape@4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
-
-lodash.uniq@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
-
-lodash@3.7.x:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.7.0.tgz#3678bd8ab995057c07ade836ed2ef087da811d45"
-
-lodash@^3.2.0, lodash@^3.8.0:
- version "3.10.1"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.5.0, lodash@~4.17.10:
- version "4.17.10"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
-
-log4js@^0.6.31:
- version "0.6.38"
- resolved "https://registry.yarnpkg.com/log4js/-/log4js-0.6.38.tgz#2c494116695d6fb25480943d3fc872e662a522fd"
- dependencies:
- readable-stream "~1.0.2"
- semver "~4.3.3"
-
-longest@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-
-loud-rejection@^1.0.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
- dependencies:
- currently-unhandled "^0.4.1"
- signal-exit "^3.0.0"
-
-lru-cache@4.1.x, lru-cache@^4.0.1:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
- dependencies:
- pseudomap "^1.0.2"
- yallist "^2.1.2"
-
-lru-queue@0.1:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
- dependencies:
- es5-ext "~0.10.2"
-
-main-bower-files@^2.13.1:
- version "2.13.1"
- resolved "https://registry.yarnpkg.com/main-bower-files/-/main-bower-files-2.13.1.tgz#7e1bc5c498352ccecd5df087f13d5f31bc057d3e"
- dependencies:
- chalk "^1.0.0"
- extend "^2.0.1"
- globby "^2.0.0"
- multimatch "^2.0.0"
- path-exists "^1.0.0"
- strip-json-comments "^1.0.2"
- vinyl-fs "^2.4.3"
-
-make-error-cause@^1.1.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d"
- dependencies:
- make-error "^1.2.0"
-
-make-error@^1.2.0:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535"
-
-make-iterator@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
- dependencies:
- kind-of "^6.0.2"
-
-map-cache@^0.2.0, map-cache@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
-
-map-obj@^1.0.0, map-obj@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
-
-map-stream@~0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
-
-map-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
- dependencies:
- object-visit "^1.0.0"
-
-matchdep@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e"
- dependencies:
- findup-sync "^2.0.0"
- micromatch "^3.0.4"
- resolve "^1.4.0"
- stack-trace "0.0.10"
-
-math-expression-evaluator@^1.2.14:
- version "1.2.17"
- resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
-
-math-random@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac"
-
-media-typer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
-
-memoizee@0.4.X:
- version "0.4.12"
- resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.12.tgz#780e99a219c50c549be6d0fc61765080975c58fb"
- dependencies:
- d "1"
- es5-ext "^0.10.30"
- es6-weak-map "^2.0.2"
- event-emitter "^0.3.5"
- is-promise "^2.1"
- lru-queue "0.1"
- next-tick "1"
- timers-ext "^0.1.2"
-
-meow@^3.7.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
- dependencies:
- camelcase-keys "^2.0.0"
- decamelize "^1.1.2"
- loud-rejection "^1.0.0"
- map-obj "^1.0.1"
- minimist "^1.1.3"
- normalize-package-data "^2.3.4"
- object-assign "^4.0.1"
- read-pkg-up "^1.0.1"
- redent "^1.0.0"
- trim-newlines "^1.0.0"
-
-merge-stream@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
- dependencies:
- readable-stream "^2.0.1"
-
-micromatch@^2.1.5, micromatch@^2.3.7:
- version "2.3.11"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
- dependencies:
- arr-diff "^2.0.0"
- array-unique "^0.2.1"
- braces "^1.8.2"
- expand-brackets "^0.1.4"
- extglob "^0.3.1"
- filename-regex "^2.0.0"
- is-extglob "^1.0.0"
- is-glob "^2.0.1"
- kind-of "^3.0.2"
- normalize-path "^2.0.1"
- object.omit "^2.0.0"
- parse-glob "^3.0.4"
- regex-cache "^0.4.2"
-
-micromatch@^3.0.4, micromatch@^3.1.4:
- version "3.1.10"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.1"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- extglob "^2.0.4"
- fragment-cache "^0.2.1"
- kind-of "^6.0.2"
- nanomatch "^1.2.9"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.2"
-
-mime-db@~1.35.0:
- version "1.35.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47"
-
-mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7:
- version "2.1.19"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0"
- dependencies:
- mime-db "~1.35.0"
-
-mime@^1.3.4:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-
-minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-
-minimist@~0.0.1:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
-
-minipass@^2.2.1, minipass@^2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
- dependencies:
- safe-buffer "^5.1.2"
- yallist "^3.0.0"
-
-minizlib@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
- dependencies:
- minipass "^2.2.1"
-
-mixin-deep@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
- dependencies:
- for-in "^1.0.2"
- is-extendable "^1.0.1"
-
-mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
- dependencies:
- minimist "0.0.8"
-
-ms@0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
-
-ms@0.7.2:
- version "0.7.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
-
-multimatch@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b"
- dependencies:
- array-differ "^1.0.0"
- array-union "^1.0.1"
- arrify "^1.0.0"
- minimatch "^3.0.0"
-
-multipipe@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
- dependencies:
- duplexer2 "0.0.2"
-
-mute-stdout@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.0.tgz#5b32ea07eb43c9ded6130434cf926f46b2a7fd4d"
-
-nan@^2.10.0, nan@^2.9.2:
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
-
-nanomatch@^1.2.9:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- fragment-cache "^0.2.1"
- is-windows "^1.0.2"
- kind-of "^6.0.2"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-needle@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
- dependencies:
- debug "^2.1.2"
- iconv-lite "^0.4.4"
- sax "^1.2.4"
-
-negotiator@0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
-
-next-tick@1:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
-
-node-gyp@^3.3.1:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203"
- dependencies:
- fstream "^1.0.0"
- glob "^7.0.3"
- graceful-fs "^4.1.2"
- mkdirp "^0.5.0"
- nopt "2 || 3"
- npmlog "0 || 1 || 2 || 3 || 4"
- osenv "0"
- request ">=2.9.0 <2.82.0"
- rimraf "2"
- semver "~5.3.0"
- tar "^2.0.0"
- which "1"
-
-node-pre-gyp@^0.10.0:
- version "0.10.3"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
- dependencies:
- detect-libc "^1.0.2"
- mkdirp "^0.5.1"
- needle "^2.2.1"
- nopt "^4.0.1"
- npm-packlist "^1.1.6"
- npmlog "^4.0.2"
- rc "^1.2.7"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar "^4"
-
-node-sass@^4.8.3:
- version "4.9.2"
- resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.2.tgz#5e63fe6bd0f2ae3ac9d6c14ede8620e2b8bdb437"
- dependencies:
- async-foreach "^0.1.3"
- chalk "^1.1.1"
- cross-spawn "^3.0.0"
- gaze "^1.0.0"
- get-stdin "^4.0.1"
- glob "^7.0.3"
- in-publish "^2.0.0"
- lodash.assign "^4.2.0"
- lodash.clonedeep "^4.3.2"
- lodash.mergewith "^4.6.0"
- meow "^3.7.0"
- mkdirp "^0.5.1"
- nan "^2.10.0"
- node-gyp "^3.3.1"
- npmlog "^4.0.0"
- request "2.87.0"
- sass-graph "^2.2.4"
- stdout-stream "^1.4.0"
- "true-case-path" "^1.0.2"
-
-"nopt@2 || 3":
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
- dependencies:
- abbrev "1"
-
-nopt@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
- dependencies:
- abbrev "1"
- osenv "^0.1.4"
-
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
- dependencies:
- hosted-git-info "^2.1.4"
- is-builtin-module "^1.0.0"
- semver "2 || 3 || 4 || 5"
- validate-npm-package-license "^3.0.1"
-
-normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
- dependencies:
- remove-trailing-separator "^1.0.1"
-
-normalize-range@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
-
-normalize-url@^1.4.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
- dependencies:
- object-assign "^4.0.1"
- prepend-http "^1.0.0"
- query-string "^4.1.0"
- sort-keys "^1.0.0"
-
-now-and-later@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.0.tgz#bc61cbb456d79cb32207ce47ca05136ff2e7d6ee"
- dependencies:
- once "^1.3.2"
-
-npm-bundled@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308"
-
-npm-packlist@^1.1.6:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de"
- dependencies:
- ignore-walk "^3.0.1"
- npm-bundled "^1.0.1"
-
-"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
- dependencies:
- are-we-there-yet "~1.1.2"
- console-control-strings "~1.1.0"
- gauge "~2.7.3"
- set-blocking "~2.0.0"
-
-nth-check@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4"
- dependencies:
- boolbase "~1.0.0"
-
-null-check@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd"
-
-num2fraction@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
-
-number-is-nan@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-
-oauth-sign@~0.8.1, oauth-sign@~0.8.2:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
-
-object-assign@4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
-
-object-assign@4.X, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
-
-object-assign@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
-
-object-component@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
-
-object-copy@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
- dependencies:
- copy-descriptor "^0.1.0"
- define-property "^0.2.5"
- kind-of "^3.0.3"
-
-object-keys@^1.0.11, object-keys@^1.0.8:
- version "1.0.12"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
-
-object-visit@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
- dependencies:
- isobject "^3.0.0"
-
-object.assign@^4.0.4:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
-
-object.defaults@^1.0.0, object.defaults@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
- dependencies:
- array-each "^1.0.1"
- array-slice "^1.0.0"
- for-own "^1.0.0"
- isobject "^3.0.0"
-
-object.map@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
- dependencies:
- for-own "^1.0.0"
- make-iterator "^1.0.0"
-
-object.omit@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
- dependencies:
- for-own "^0.1.4"
- is-extendable "^0.1.1"
-
-object.pick@^1.2.0, object.pick@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
- dependencies:
- isobject "^3.0.1"
-
-object.reduce@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad"
- dependencies:
- for-own "^1.0.0"
- make-iterator "^1.0.0"
-
-on-finished@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
- dependencies:
- ee-first "1.1.1"
-
-once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- dependencies:
- wrappy "1"
-
-optimist@^0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
- dependencies:
- minimist "~0.0.1"
- wordwrap "~0.0.2"
-
-options@>=0.0.5:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
-
-ordered-read-streams@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
- dependencies:
- is-stream "^1.0.1"
- readable-stream "^2.0.1"
-
-ordered-read-streams@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
- dependencies:
- readable-stream "^2.0.1"
-
-os-homedir@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
-
-os-locale@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
- dependencies:
- lcid "^1.0.0"
-
-os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-
-osenv@0, osenv@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
- dependencies:
- os-homedir "^1.0.0"
- os-tmpdir "^1.0.0"
-
-parse-filepath@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
- dependencies:
- is-absolute "^1.0.0"
- map-cache "^0.2.0"
- path-root "^0.1.1"
-
-parse-glob@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
- dependencies:
- glob-base "^0.3.0"
- is-dotfile "^1.0.0"
- is-extglob "^1.0.0"
- is-glob "^2.0.0"
-
-parse-json@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
- dependencies:
- error-ex "^1.2.0"
-
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
-
-parsejson@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab"
- dependencies:
- better-assert "~1.0.0"
-
-parseqs@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
- dependencies:
- better-assert "~1.0.0"
-
-parseuri@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
- dependencies:
- better-assert "~1.0.0"
-
-parseurl@~1.3.2:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
-
-pascalcase@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
-
-path-dirname@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
-
-path-exists@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081"
-
-path-exists@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
- dependencies:
- pinkie-promise "^2.0.0"
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-
-path-parse@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
-
-path-root-regex@^0.1.0:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
-
-path-root@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
- dependencies:
- path-root-regex "^0.1.0"
-
-path-type@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-pause-stream@0.0.11:
- version "0.0.11"
- resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
- dependencies:
- through "~2.3"
-
-pend@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
-
-performance-now@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
-
-performance-now@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
-
-phantomjs-prebuilt@^2.1.7:
- version "2.1.16"
- resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz#efd212a4a3966d3647684ea8ba788549be2aefef"
- dependencies:
- es6-promise "^4.0.3"
- extract-zip "^1.6.5"
- fs-extra "^1.0.0"
- hasha "^2.2.0"
- kew "^0.7.0"
- progress "^1.1.8"
- request "^2.81.0"
- request-progress "^2.0.1"
- which "^1.2.10"
-
-pify@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
-
-pinkie-promise@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
- dependencies:
- pinkie "^2.0.0"
-
-pinkie@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
-
-plugin-error@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace"
- dependencies:
- ansi-cyan "^0.1.1"
- ansi-red "^0.1.1"
- arr-diff "^1.0.1"
- arr-union "^2.0.1"
- extend-shallow "^1.1.2"
-
-plugin-error@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c"
- dependencies:
- ansi-colors "^1.0.1"
- arr-diff "^4.0.0"
- arr-union "^3.1.0"
- extend-shallow "^3.0.2"
-
-pofile@~1.0.0:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
-
-posix-character-classes@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
-
-postcss-calc@^5.2.0:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
- dependencies:
- postcss "^5.0.2"
- postcss-message-helpers "^2.0.0"
- reduce-css-calc "^1.2.6"
-
-postcss-colormin@^2.1.8:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
- dependencies:
- colormin "^1.0.5"
- postcss "^5.0.13"
- postcss-value-parser "^3.2.3"
-
-postcss-convert-values@^2.3.4:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
- dependencies:
- postcss "^5.0.11"
- postcss-value-parser "^3.1.2"
-
-postcss-discard-comments@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
- dependencies:
- postcss "^5.0.14"
-
-postcss-discard-duplicates@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
- dependencies:
- postcss "^5.0.4"
-
-postcss-discard-empty@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
- dependencies:
- postcss "^5.0.14"
-
-postcss-discard-overridden@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
- dependencies:
- postcss "^5.0.16"
-
-postcss-discard-unused@^2.2.1:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
- dependencies:
- postcss "^5.0.14"
- uniqs "^2.0.0"
-
-postcss-filter-plugins@^2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec"
- dependencies:
- postcss "^5.0.4"
-
-postcss-merge-idents@^2.1.5:
- version "2.1.7"
- resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
- dependencies:
- has "^1.0.1"
- postcss "^5.0.10"
- postcss-value-parser "^3.1.1"
-
-postcss-merge-longhand@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
- dependencies:
- postcss "^5.0.4"
-
-postcss-merge-rules@^2.0.3:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
- dependencies:
- browserslist "^1.5.2"
- caniuse-api "^1.5.2"
- postcss "^5.0.4"
- postcss-selector-parser "^2.2.2"
- vendors "^1.0.0"
-
-postcss-message-helpers@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
-
-postcss-minify-font-values@^1.0.2:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
- dependencies:
- object-assign "^4.0.1"
- postcss "^5.0.4"
- postcss-value-parser "^3.0.2"
-
-postcss-minify-gradients@^1.0.1:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
- dependencies:
- postcss "^5.0.12"
- postcss-value-parser "^3.3.0"
-
-postcss-minify-params@^1.0.4:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
- dependencies:
- alphanum-sort "^1.0.1"
- postcss "^5.0.2"
- postcss-value-parser "^3.0.2"
- uniqs "^2.0.0"
-
-postcss-minify-selectors@^2.0.4:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
- dependencies:
- alphanum-sort "^1.0.2"
- has "^1.0.1"
- postcss "^5.0.14"
- postcss-selector-parser "^2.0.0"
-
-postcss-normalize-charset@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
- dependencies:
- postcss "^5.0.5"
-
-postcss-normalize-url@^3.0.7:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
- dependencies:
- is-absolute-url "^2.0.0"
- normalize-url "^1.4.0"
- postcss "^5.0.14"
- postcss-value-parser "^3.2.3"
-
-postcss-ordered-values@^2.1.0:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
- dependencies:
- postcss "^5.0.4"
- postcss-value-parser "^3.0.1"
-
-postcss-reduce-idents@^2.2.2:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
- dependencies:
- postcss "^5.0.4"
- postcss-value-parser "^3.0.2"
-
-postcss-reduce-initial@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
- dependencies:
- postcss "^5.0.4"
-
-postcss-reduce-transforms@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
- dependencies:
- has "^1.0.1"
- postcss "^5.0.8"
- postcss-value-parser "^3.0.1"
-
-postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
- dependencies:
- flatten "^1.0.2"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
-
-postcss-svgo@^2.1.1:
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
- dependencies:
- is-svg "^2.0.0"
- postcss "^5.0.14"
- postcss-value-parser "^3.2.3"
- svgo "^0.7.0"
-
-postcss-unique-selectors@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
- dependencies:
- alphanum-sort "^1.0.1"
- postcss "^5.0.4"
- uniqs "^2.0.0"
-
-postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
-
-postcss-zindex@^2.0.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
- dependencies:
- has "^1.0.1"
- postcss "^5.0.4"
- uniqs "^2.0.0"
-
-postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.2.16:
- version "5.2.18"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
- dependencies:
- chalk "^1.1.3"
- js-base64 "^2.1.9"
- source-map "^0.5.6"
- supports-color "^3.2.3"
-
-prepend-http@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
-
-preserve@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
-
-pretty-hrtime@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
-
-process-nextick-args@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
-
-process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
-
-progress@^1.1.8:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
-
-pseudomap@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
-
-pump@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pumpify@^1.3.5:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
- dependencies:
- duplexify "^3.6.0"
- inherits "^2.0.3"
- pump "^2.0.0"
-
-punycode@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
-
-q@^1.1.2:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
-
-qjobs@^1.1.4:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071"
-
-qs@6.5.2, qs@~6.5.1:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
-
-qs@~6.4.0:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
-
-query-string@^4.1.0:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
- dependencies:
- object-assign "^4.1.0"
- strict-uri-encode "^1.0.0"
-
-randomatic@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923"
- dependencies:
- is-number "^4.0.0"
- kind-of "^6.0.0"
- math-random "^1.0.1"
-
-range-parser@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
-
-raw-body@2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
- dependencies:
- bytes "3.0.0"
- http-errors "1.6.3"
- iconv-lite "0.4.23"
- unpipe "1.0.0"
-
-rc@^1.2.7:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
- dependencies:
- deep-extend "^0.6.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
-
-rcfinder@^0.1.6:
- version "0.1.9"
- resolved "https://registry.yarnpkg.com/rcfinder/-/rcfinder-0.1.9.tgz#f3e80f387ddf9ae80ae30a4100329642eae81115"
- dependencies:
- lodash.clonedeep "^4.3.2"
-
-rcloader@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/rcloader/-/rcloader-0.2.2.tgz#58d2298b462d0b9bfd2133d2a1ec74fbd705c717"
- dependencies:
- lodash.assign "^4.2.0"
- lodash.isobject "^3.0.2"
- lodash.merge "^4.6.0"
- rcfinder "^0.1.6"
-
-read-pkg-up@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
- dependencies:
- find-up "^1.0.0"
- read-pkg "^1.0.0"
-
-read-pkg@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
- dependencies:
- load-json-file "^1.0.0"
- normalize-package-data "^2.3.2"
- path-type "^1.0.0"
-
-readable-stream@1.1:
- version "1.1.13"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.2:
- version "1.0.34"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@~1.1.9:
- version "1.1.14"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-readdirp@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
- dependencies:
- graceful-fs "^4.1.2"
- minimatch "^3.0.2"
- readable-stream "^2.0.2"
- set-immediate-shim "^1.0.1"
-
-rechoir@^0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
- dependencies:
- resolve "^1.1.6"
-
-redent@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
- dependencies:
- indent-string "^2.1.0"
- strip-indent "^1.0.1"
-
-reduce-css-calc@^1.2.6:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
- dependencies:
- balanced-match "^0.4.2"
- math-expression-evaluator "^1.2.14"
- reduce-function-call "^1.0.1"
-
-reduce-function-call@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
- dependencies:
- balanced-match "^0.4.2"
-
-regex-cache@^0.4.2:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
- dependencies:
- is-equal-shallow "^0.1.3"
-
-regex-not@^1.0.0, regex-not@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
- dependencies:
- extend-shallow "^3.0.2"
- safe-regex "^1.1.0"
-
-remove-bom-buffer@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
- dependencies:
- is-buffer "^1.1.5"
- is-utf8 "^0.2.1"
-
-remove-bom-stream@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523"
- dependencies:
- remove-bom-buffer "^3.0.0"
- safe-buffer "^5.1.0"
- through2 "^2.0.3"
-
-remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
-
-repeat-element@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
-
-repeat-string@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae"
-
-repeat-string@^1.5.2, repeat-string@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
-
-repeating@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
- dependencies:
- is-finite "^1.0.0"
-
-replace-ext@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
-
-replace-ext@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
-
-replace-homedir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c"
- dependencies:
- homedir-polyfill "^1.0.1"
- is-absolute "^1.0.0"
- remove-trailing-separator "^1.1.0"
-
-request-progress@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08"
- dependencies:
- throttleit "^1.0.0"
-
-request@2.87.0, request@^2.81.0:
- version "2.87.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
- dependencies:
- aws-sign2 "~0.7.0"
- aws4 "^1.6.0"
- caseless "~0.12.0"
- combined-stream "~1.0.5"
- extend "~3.0.1"
- forever-agent "~0.6.1"
- form-data "~2.3.1"
- har-validator "~5.0.3"
- http-signature "~1.2.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.17"
- oauth-sign "~0.8.2"
- performance-now "^2.1.0"
- qs "~6.5.1"
- safe-buffer "^5.1.1"
- tough-cookie "~2.3.3"
- tunnel-agent "^0.6.0"
- uuid "^3.1.0"
-
-"request@>=2.9.0 <2.82.0":
- version "2.81.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
- dependencies:
- aws-sign2 "~0.6.0"
- aws4 "^1.2.1"
- caseless "~0.12.0"
- combined-stream "~1.0.5"
- extend "~3.0.0"
- forever-agent "~0.6.1"
- form-data "~2.1.1"
- har-validator "~4.2.1"
- hawk "~3.1.3"
- http-signature "~1.1.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.7"
- oauth-sign "~0.8.1"
- performance-now "^0.2.0"
- qs "~6.4.0"
- safe-buffer "^5.0.1"
- stringstream "~0.0.4"
- tough-cookie "~2.3.0"
- tunnel-agent "^0.6.0"
- uuid "^3.0.0"
-
-require-directory@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
-
-require-main-filename@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
-
-requires-port@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
-
-resolve-dir@^1.0.0, resolve-dir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
- dependencies:
- expand-tilde "^2.0.0"
- global-modules "^1.0.0"
-
-resolve-options@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131"
- dependencies:
- value-or-function "^3.0.0"
-
-resolve-url@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
-
-resolve@^1.1.6, resolve@^1.1.7, resolve@^1.4.0:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
- dependencies:
- path-parse "^1.0.5"
-
-ret@~0.1.10:
- version "0.1.15"
- resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
-
-right-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
- dependencies:
- align-text "^0.1.1"
-
-rimraf@2, rimraf@^2.6.0, rimraf@^2.6.1:
- version "2.6.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
- dependencies:
- glob "^7.0.5"
-
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
-
-safe-regex@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
- dependencies:
- ret "~0.1.10"
-
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
-
-sass-graph@^2.2.4:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
- dependencies:
- glob "^7.0.0"
- lodash "^4.0.0"
- scss-tokenizer "^0.2.3"
- yargs "^7.0.0"
-
-sax@^1.2.4, sax@~1.2.1:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
-
-scss-tokenizer@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
- dependencies:
- js-base64 "^2.1.8"
- source-map "^0.4.2"
-
-semver-greatest-satisfied-range@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b"
- dependencies:
- sver-compat "^1.5.0"
-
-"semver@2 || 3 || 4 || 5", semver@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
-
-semver@5.3.0, semver@~5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
-
-semver@~4.3.3:
- version "4.3.6"
- resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
-
-set-blocking@^2.0.0, set-blocking@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
-
-set-immediate-shim@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
-
-set-value@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
- dependencies:
- extend-shallow "^2.0.1"
- is-extendable "^0.1.1"
- is-plain-object "^2.0.1"
- to-object-path "^0.3.0"
-
-set-value@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
- dependencies:
- extend-shallow "^2.0.1"
- is-extendable "^0.1.1"
- is-plain-object "^2.0.3"
- split-string "^3.0.1"
-
-setprototypeof@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
-
-shelljs@0.3.x:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
-
-signal-exit@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
-
-snapdragon-node@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
- dependencies:
- define-property "^1.0.0"
- isobject "^3.0.0"
- snapdragon-util "^3.0.1"
-
-snapdragon-util@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
- dependencies:
- kind-of "^3.2.0"
-
-snapdragon@^0.8.1:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
- dependencies:
- base "^0.11.1"
- debug "^2.2.0"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- map-cache "^0.2.2"
- source-map "^0.5.6"
- source-map-resolve "^0.5.0"
- use "^3.1.0"
-
-sntp@1.x.x:
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
- dependencies:
- hoek "2.x.x"
-
-socket.io-adapter@0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b"
- dependencies:
- debug "2.3.3"
- socket.io-parser "2.3.1"
-
-socket.io-client@1.7.3:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.3.tgz#b30e86aa10d5ef3546601c09cde4765e381da377"
- dependencies:
- backo2 "1.0.2"
- component-bind "1.0.0"
- component-emitter "1.2.1"
- debug "2.3.3"
- engine.io-client "1.8.3"
- has-binary "0.1.7"
- indexof "0.0.1"
- object-component "0.0.3"
- parseuri "0.0.5"
- socket.io-parser "2.3.1"
- to-array "0.1.4"
-
-socket.io-parser@2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0"
- dependencies:
- component-emitter "1.1.2"
- debug "2.2.0"
- isarray "0.0.1"
- json3 "3.3.2"
-
-socket.io@1.7.3:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b"
- dependencies:
- debug "2.3.3"
- engine.io "1.8.3"
- has-binary "0.1.7"
- object-assign "4.1.0"
- socket.io-adapter "0.5.0"
- socket.io-client "1.7.3"
- socket.io-parser "2.3.1"
-
-sort-keys@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
- dependencies:
- is-plain-obj "^1.0.0"
-
-source-map-resolve@^0.5.0, source-map-resolve@^0.5.1:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
- dependencies:
- atob "^2.1.1"
- decode-uri-component "^0.2.0"
- resolve-url "^0.2.1"
- source-map-url "^0.4.0"
- urix "^0.1.0"
-
-source-map-url@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
-
-source-map@^0.1.38:
- version "0.1.43"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
- dependencies:
- amdefine ">=0.0.4"
-
-source-map@^0.4.2:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
- dependencies:
- amdefine ">=0.0.4"
-
-source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
-
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
-
-sparkles@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
-
-spdx-correct@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82"
- dependencies:
- spdx-expression-parse "^3.0.0"
- spdx-license-ids "^3.0.0"
-
-spdx-exceptions@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9"
-
-spdx-expression-parse@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
- dependencies:
- spdx-exceptions "^2.1.0"
- spdx-license-ids "^3.0.0"
-
-spdx-license-ids@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87"
-
-split-string@^3.0.1, split-string@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
- dependencies:
- extend-shallow "^3.0.0"
-
-split@0.3:
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
- dependencies:
- through "2"
-
-sprintf-js@^1.0.3:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
-
-sshpk@^1.7.0:
- version "1.14.2"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
- dependencies:
- asn1 "~0.2.3"
- assert-plus "^1.0.0"
- dashdash "^1.12.0"
- getpass "^0.1.1"
- safer-buffer "^2.0.2"
- optionalDependencies:
- bcrypt-pbkdf "^1.0.0"
- ecc-jsbn "~0.1.1"
- jsbn "~0.1.0"
- tweetnacl "~0.14.0"
-
-stack-trace@0.0.10:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
-
-static-extend@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
- dependencies:
- define-property "^0.2.5"
- object-copy "^0.1.0"
-
-"statuses@>= 1.4.0 < 2":
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
-
-statuses@~1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
-
-stdout-stream@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b"
- dependencies:
- readable-stream "^2.0.1"
-
-stream-combiner@~0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
- dependencies:
- duplexer "~0.1.1"
-
-stream-exhaust@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d"
-
-stream-shift@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
-
-strict-uri-encode@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
-
-string-width@^1.0.1, string-width@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
- dependencies:
- code-point-at "^1.0.0"
- is-fullwidth-code-point "^1.0.0"
- strip-ansi "^3.0.0"
-
-"string-width@^1.0.2 || 2":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
- dependencies:
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^4.0.0"
-
-string_decoder@~0.10.x:
- version "0.10.31"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
- dependencies:
- safe-buffer "~5.1.0"
-
-stringstream@~0.0.4:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
-
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- dependencies:
- ansi-regex "^2.0.0"
-
-strip-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
- dependencies:
- ansi-regex "^3.0.0"
-
-strip-bom-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
- dependencies:
- first-chunk-stream "^1.0.0"
- strip-bom "^2.0.0"
-
-strip-bom-string@1.X:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
-
-strip-bom@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
- dependencies:
- is-utf8 "^0.2.0"
-
-strip-indent@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
- dependencies:
- get-stdin "^4.0.1"
-
-strip-json-comments@1.0.x, strip-json-comments@^1.0.2:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
-
-strip-json-comments@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
-
-supports-color@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-
-supports-color@^3.2.3:
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
- dependencies:
- has-flag "^1.0.0"
-
-sver-compat@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8"
- dependencies:
- es6-iterator "^2.0.1"
- es6-symbol "^3.1.1"
-
-svgo@^0.7.0:
- version "0.7.2"
- resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
- dependencies:
- coa "~1.0.1"
- colors "~1.1.2"
- csso "~2.3.1"
- js-yaml "~3.7.0"
- mkdirp "~0.5.1"
- sax "~1.2.1"
- whet.extend "~0.9.9"
-
-tar@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
- dependencies:
- block-stream "*"
- fstream "^1.0.2"
- inherits "2"
-
-tar@^4:
- version "4.4.4"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd"
- dependencies:
- chownr "^1.0.1"
- fs-minipass "^1.2.5"
- minipass "^2.3.3"
- minizlib "^1.1.0"
- mkdirp "^0.5.0"
- safe-buffer "^5.1.2"
- yallist "^3.0.2"
-
-ternary-stream@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269"
- dependencies:
- duplexify "^3.5.0"
- fork-stream "^0.0.4"
- merge-stream "^1.0.0"
- through2 "^2.0.1"
-
-throttleit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"
-
-through2-filter@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
- dependencies:
- through2 "~2.0.0"
- xtend "~4.0.0"
-
-through2@2.X, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
- dependencies:
- readable-stream "^2.1.5"
- xtend "~4.0.1"
-
-through2@^0.6.0:
- version "0.6.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
- dependencies:
- readable-stream ">=1.0.33-1 <1.1.0-0"
- xtend ">=4.0.0 <4.1.0-0"
-
-through@2, through@~2.3, through@~2.3.1:
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
-
-time-stamp@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
-
-timers-ext@^0.1.2:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.5.tgz#77147dd4e76b660c2abb8785db96574cbbd12922"
- dependencies:
- es5-ext "~0.10.14"
- next-tick "1"
-
-tmp@0.0.31:
- version "0.0.31"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
- dependencies:
- os-tmpdir "~1.0.1"
-
-tmp@0.0.x:
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
- dependencies:
- os-tmpdir "~1.0.2"
-
-to-absolute-glob@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
- dependencies:
- extend-shallow "^2.0.1"
-
-to-absolute-glob@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
- dependencies:
- is-absolute "^1.0.0"
- is-negated-glob "^1.0.0"
-
-to-array@0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
-
-to-object-path@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
- dependencies:
- kind-of "^3.0.2"
-
-to-regex-range@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
- dependencies:
- is-number "^3.0.0"
- repeat-string "^1.6.1"
-
-to-regex@^3.0.1, to-regex@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
- dependencies:
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- regex-not "^1.0.2"
- safe-regex "^1.1.0"
-
-to-through@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6"
- dependencies:
- through2 "^2.0.3"
-
-tough-cookie@~2.3.0, tough-cookie@~2.3.3:
- version "2.3.4"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
- dependencies:
- punycode "^1.4.1"
-
-trim-newlines@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
-
-"true-case-path@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62"
- dependencies:
- glob "^6.0.4"
-
-tunnel-agent@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
- dependencies:
- safe-buffer "^5.0.1"
-
-tweetnacl@^0.14.3, tweetnacl@~0.14.0:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
-
-type-is@~1.6.16:
- version "1.6.16"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
- dependencies:
- media-typer "0.3.0"
- mime-types "~2.1.18"
-
-typedarray@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
-
-typescript-eslint-parser@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-3.0.0.tgz#dd0435b303abc841464c02d00184d7b39bd488b5"
- dependencies:
- lodash.unescape "4.0.1"
- semver "5.3.0"
-
-typescript@~2.3.2:
- version "2.3.4"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"
-
-uglify-js@~2.8.10:
- version "2.8.29"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
- dependencies:
- source-map "~0.5.1"
- yargs "~3.10.0"
- optionalDependencies:
- uglify-to-browserify "~1.0.0"
-
-uglify-save-license@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/uglify-save-license/-/uglify-save-license-0.4.1.tgz#95726c17cc6fd171c3617e3bf4d8d82aa8c4cce1"
-
-uglify-to-browserify@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
-
-ultron@1.0.x:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
-
-unc-path-regex@^0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
-
-undertaker-registry@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
-
-undertaker@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.2.0.tgz#339da4646252d082dc378e708067299750e11b49"
- dependencies:
- arr-flatten "^1.0.1"
- arr-map "^2.0.0"
- bach "^1.0.0"
- collection-map "^1.0.0"
- es6-weak-map "^2.0.1"
- last-run "^1.1.0"
- object.defaults "^1.0.0"
- object.reduce "^1.0.0"
- undertaker-registry "^1.0.0"
-
-union-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
- dependencies:
- arr-union "^3.1.0"
- get-value "^2.0.6"
- is-extendable "^0.1.1"
- set-value "^0.4.3"
-
-uniq@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
-
-uniqs@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
-
-unique-stream@^2.0.2:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369"
- dependencies:
- json-stable-stringify "^1.0.0"
- through2-filter "^2.0.0"
-
-unpipe@1.0.0, unpipe@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
-
-unset-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
- dependencies:
- has-value "^0.3.1"
- isobject "^3.0.0"
-
-upath@^1.0.5:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
-
-urix@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
-
-use@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
-
-useragent@^2.1.12:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972"
- dependencies:
- lru-cache "4.1.x"
- tmp "0.0.x"
-
-util-deprecate@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
-
-utils-merge@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
-
-uuid@^3.0.0, uuid@^3.1.0:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
-
-v8flags@^3.0.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.1.1.tgz#42259a1461c08397e37fe1d4f1cfb59cad85a053"
- dependencies:
- homedir-polyfill "^1.0.1"
-
-vali-date@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
-
-validate-npm-package-license@^3.0.1:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338"
- dependencies:
- spdx-correct "^3.0.0"
- spdx-expression-parse "^3.0.0"
-
-value-or-function@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
-
-vendors@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801"
-
-verror@1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
- dependencies:
- assert-plus "^1.0.0"
- core-util-is "1.0.2"
- extsprintf "^1.2.0"
-
-vinyl-fs@^2.4.3:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
- dependencies:
- duplexify "^3.2.0"
- glob-stream "^5.3.2"
- graceful-fs "^4.0.0"
- gulp-sourcemaps "1.6.0"
- is-valid-glob "^0.3.0"
- lazystream "^1.0.0"
- lodash.isequal "^4.0.0"
- merge-stream "^1.0.0"
- mkdirp "^0.5.0"
- object-assign "^4.0.0"
- readable-stream "^2.0.4"
- strip-bom "^2.0.0"
- strip-bom-stream "^1.0.0"
- through2 "^2.0.0"
- through2-filter "^2.0.0"
- vali-date "^1.0.0"
- vinyl "^1.0.0"
-
-vinyl-fs@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7"
- dependencies:
- fs-mkdirp-stream "^1.0.0"
- glob-stream "^6.1.0"
- graceful-fs "^4.0.0"
- is-valid-glob "^1.0.0"
- lazystream "^1.0.0"
- lead "^1.0.0"
- object.assign "^4.0.4"
- pumpify "^1.3.5"
- readable-stream "^2.3.3"
- remove-bom-buffer "^3.0.0"
- remove-bom-stream "^1.2.0"
- resolve-options "^1.1.0"
- through2 "^2.0.0"
- to-through "^2.0.0"
- value-or-function "^3.0.0"
- vinyl "^2.0.0"
- vinyl-sourcemap "^1.1.0"
-
-vinyl-sourcemap@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16"
- dependencies:
- append-buffer "^1.0.2"
- convert-source-map "^1.5.0"
- graceful-fs "^4.1.6"
- normalize-path "^2.1.1"
- now-and-later "^2.0.0"
- remove-bom-buffer "^3.0.0"
- vinyl "^2.0.0"
-
-vinyl-sourcemaps-apply@^0.2.0, vinyl-sourcemaps-apply@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705"
- dependencies:
- source-map "^0.5.1"
-
-vinyl@^0.5.0:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
- dependencies:
- clone "^1.0.0"
- clone-stats "^0.0.1"
- replace-ext "0.0.1"
-
-vinyl@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
- dependencies:
- clone "^1.0.0"
- clone-stats "^0.0.1"
- replace-ext "0.0.1"
-
-vinyl@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
- dependencies:
- clone "^2.1.1"
- clone-buffer "^1.0.0"
- clone-stats "^1.0.0"
- cloneable-readable "^1.0.0"
- remove-trailing-separator "^1.0.1"
- replace-ext "^1.0.0"
-
-void-elements@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
-
-whet.extend@~0.9.9:
- version "0.9.9"
- resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
-
-which-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-
-which@1, which@^1.2.1, which@^1.2.10, which@^1.2.14, which@^1.2.9:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
- dependencies:
- isexe "^2.0.0"
-
-wide-align@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
- dependencies:
- string-width "^1.0.2 || 2"
-
-window-size@0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
-
-wordwrap@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
-
-wordwrap@~0.0.2:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
-
-wrap-ansi@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
- dependencies:
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-
-ws@1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f"
- dependencies:
- options ">=0.0.5"
- ultron "1.0.x"
-
-wtf-8@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a"
-
-xmlhttprequest-ssl@1.5.3:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d"
-
-"xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.0, xtend@~4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
-
-y18n@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
-
-yallist@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
-
-yallist@^3.0.0, yallist@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
-
-yargs-parser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
- dependencies:
- camelcase "^3.0.0"
-
-yargs@^7.0.0, yargs@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
- dependencies:
- camelcase "^3.0.0"
- cliui "^3.2.0"
- decamelize "^1.1.1"
- get-caller-file "^1.0.1"
- os-locale "^1.4.0"
- read-pkg-up "^1.0.1"
- require-directory "^2.1.1"
- require-main-filename "^1.0.1"
- set-blocking "^2.0.0"
- string-width "^1.0.2"
- which-module "^1.0.0"
- y18n "^3.2.1"
- yargs-parser "^5.0.0"
-
-yargs@~3.10.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
- dependencies:
- camelcase "^1.0.2"
- cliui "^2.1.0"
- decamelize "^1.0.0"
- window-size "0.1.0"
-
-yauzl@2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
- dependencies:
- fd-slicer "~1.0.1"
-
-yeast@0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"