Merge pull request #2374 from normanjaeckel/LoadJavaScript

Changed loading of JavaScript files.
This commit is contained in:
Emanuel Schütze 2016-09-18 12:24:40 +02:00 committed by GitHub
commit f288cb4967
17 changed files with 130 additions and 71 deletions

View File

@ -8,6 +8,10 @@ cache:
python: python:
- "3.4" - "3.4"
- "3.5" - "3.5"
env:
- TRAVIS_NODE_VERSION="4"
before_install:
- "nvm install $TRAVIS_NODE_VERSION"
install: install:
- "pip install --upgrade setuptools" - "pip install --upgrade setuptools"
- "pip install --upgrade --requirement requirements.txt" - "pip install --upgrade --requirement requirements.txt"

View File

@ -74,6 +74,10 @@ avoid opening new browser windows::
$ python manage.py runserver $ python manage.py runserver
Use gulp watch in a second command-line interface::
$ node_modules/.bin/gulp watch
2. Installation on Windows 2. Installation on Windows
-------------------------- --------------------------

View File

@ -26,6 +26,8 @@ var argv = require('yargs').argv,
mainBowerFiles = require('main-bower-files'), mainBowerFiles = require('main-bower-files'),
path = require('path'), path = require('path'),
rename = require('gulp-rename'), rename = require('gulp-rename'),
sourcemaps = require('gulp-sourcemaps'),
templateCache = require('gulp-angular-templatecache'),
through = require('through2'), through = require('through2'),
uglify = require('gulp-uglify'), uglify = require('gulp-uglify'),
vsprintf = require('sprintf-js').vsprintf; vsprintf = require('sprintf-js').vsprintf;
@ -38,13 +40,44 @@ var output_directory = path.join('openslides', 'static');
* Default tasks to be run before start. * Default tasks to be run before start.
*/ */
// Catches all JavaScript files from all core apps and concats them to one
// file js/openslides.js. In production mode the file is uglified.
gulp.task('js', function () {
return gulp.src(path.join('openslides', '*', 'static', 'js', '**', '*.js'))
.pipe(sourcemaps.init())
.pipe(concat('openslides.js'))
.pipe(sourcemaps.write())
.pipe(gulpif(argv.production, uglify()))
.pipe(gulp.dest(path.join(output_directory, 'js')));
});
// Catches all JavaScript files from all bower components and concats them to // 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. // one file js/openslides-libs.js. In production mode the file is uglified.
gulp.task('js-libs', function () { gulp.task('js-libs', function () {
return gulp.src(mainBowerFiles({ return gulp.src(mainBowerFiles({
filter: /\.js$/ filter: /\.js$/
})) }))
.pipe(sourcemaps.init())
.pipe(concat('openslides-libs.js')) .pipe(concat('openslides-libs.js'))
.pipe(sourcemaps.write())
.pipe(gulpif(argv.production, uglify()))
.pipe(gulp.dest(path.join(output_directory, 'js')));
});
// 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.
gulp.task('templates', function () {
return gulp.src(path.join('openslides', '*', 'static', 'templates', '**', '*.html'))
.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(gulpif(argv.production, uglify()))
.pipe(gulp.dest(path.join(output_directory, 'js'))); .pipe(gulp.dest(path.join(output_directory, 'js')));
}); });
@ -117,13 +150,19 @@ gulp.task('translations', function () {
}); });
// Gulp default task. Runs all other tasks before. // Gulp default task. Runs all other tasks before.
gulp.task('default', ['js-libs', 'css-libs', 'fonts-libs', 'tinymce', 'angular-chosen-img', 'translations'], function () {}); gulp.task('default', ['js', 'js-libs', 'templates', 'css-libs', 'fonts-libs', 'tinymce', 'angular-chosen-img', 'translations'], function () {});
/** /**
* Extra tasks that have to be called manually. Useful for development. * Extra tasks that have to be called manually. Useful for development.
*/ */
// Watches changes in JavaScript and templates.
gulp.task('watch', ['js', 'templates'], function () {
gulp.watch(path.join('openslides', '*', 'static', 'js', '**', '*.js'), ['js']);
gulp.watch(path.join('openslides', '*', 'static', 'templates', '**', '*.html'), ['templates']);
});
// Extracts translatable strings using angular-gettext and saves them in file // Extracts translatable strings using angular-gettext and saves them in file
// openslides/locale/angular-gettext/template-en.pot. // openslides/locale/angular-gettext/template-en.pot.
gulp.task('pot', function () { gulp.task('pot', function () {

View File

@ -6,7 +6,6 @@ class AgendaAppConfig(AppConfig):
verbose_name = 'OpenSlides Agenda' verbose_name = 'OpenSlides Agenda'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/agenda/base.js', 'js/agenda/site.js', 'js/agenda/projector.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -6,7 +6,6 @@ class AssignmentsAppConfig(AppConfig):
verbose_name = 'OpenSlides Assignments' verbose_name = 'OpenSlides Assignments'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/assignments/base.js', 'js/assignments/site.js', 'js/assignments/projector.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -6,7 +6,6 @@ class CoreAppConfig(AppConfig):
verbose_name = 'OpenSlides Core' verbose_name = 'OpenSlides Core'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/core/base.js', 'js/core/site.js', 'js/core/projector.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -10,7 +10,8 @@ angular.module('OpenSlidesApp.core', [
'ngSanitize', // TODO: only use this in functions that need it. 'ngSanitize', // TODO: only use this in functions that need it.
'ui.bootstrap', 'ui.bootstrap',
'ui.tree', 'ui.tree',
'pdf' 'pdf',
'OpenSlidesApp-templates',
]) ])
.config([ .config([

View File

@ -869,7 +869,7 @@ angular.module('OpenSlidesApp.core.site', [
return { return {
restrict: 'E', restrict: 'E',
scope: true, scope: true,
templateUrl: '/static/templates/config-form-field.html', templateUrl: 'static/templates/config-form-field.html',
link: function ($scope, iElement, iAttrs, controller, transcludeFn) { link: function ($scope, iElement, iAttrs, controller, transcludeFn) {
var field = $parse(iAttrs.field)($scope); var field = $parse(iAttrs.field)($scope);
var config = Config.get(field.key); var config = Config.get(field.key);

View File

@ -10,6 +10,8 @@
<link rel="stylesheet" href="static/css/app.css"> <link rel="stylesheet" href="static/css/app.css">
<link rel="icon" href="/static/img/favicon.png"> <link rel="icon" href="/static/img/favicon.png">
<script src="static/js/openslides-libs.js"></script> <script src="static/js/openslides-libs.js"></script>
<script src="static/js/openslides.js"></script>
<script src="static/js/openslides-templates.js"></script>
<div id="wrapper" ng-cloak> <div id="wrapper" ng-cloak>
@ -199,5 +201,4 @@
</div><!--end wrapper--> </div><!--end wrapper-->
<script src="/webclient/site/"></script>
<script src="/angular_js/site/"></script>

View File

@ -9,6 +9,8 @@
<link rel="stylesheet" href="static/css/projector.css"> <link rel="stylesheet" href="static/css/projector.css">
<link rel="icon" href="/static/img/favicon.png"> <link rel="icon" href="/static/img/favicon.png">
<script src="static/js/openslides-libs.js"></script> <script src="static/js/openslides-libs.js"></script>
<script src="static/js/openslides.js"></script>
<script src="static/js/openslides-templates.js"></script>
<div ng-controller="ProjectorContainerCtrl" class="pContainer"> <div ng-controller="ProjectorContainerCtrl" class="pContainer">
<div> <div>
@ -42,4 +44,4 @@
</div> </div>
</div> </div>
<script src="/angular_js/projector/"></script> <script src="/webclient/projector/"></script>

View File

@ -8,6 +8,8 @@
<link rel="stylesheet" href="static/css/projector.css"> <link rel="stylesheet" href="static/css/projector.css">
<link rel="icon" href="/static/img/favicon.png"> <link rel="icon" href="/static/img/favicon.png">
<script src="static/js/openslides-libs.js"></script> <script src="static/js/openslides-libs.js"></script>
<script src="static/js/openslides.js"></script>
<script src="static/js/openslides-templates.js"></script>
<style type="text/css"> <style type="text/css">
#header, #footer { #header, #footer {
@ -55,4 +57,5 @@
{{ config('general_event_location') }} {{ config('general_event_location') }}
</span> </span>
</div> </div>
<script src="/angular_js/projector/"></script>
<script src="/webclient/projector/"></script>

View File

@ -23,9 +23,9 @@ urlpatterns = [
views.MediaEncoder.as_view(), views.MediaEncoder.as_view(),
name="core_mediaencoding"), name="core_mediaencoding"),
url(r'^angular_js/(?P<openslides_app>site|projector)/$', url(r'^webclient/(?P<realm>site|projector)/$',
views.AppsJsView.as_view(), views.WebclientJavaScriptView.as_view(),
name='core_apps_js'), name='core_webclient_javascript'),
# View for the projectors are handled by angular. # View for the projectors are handled by angular.
url(r'^projector.*$', views.ProjectorView.as_view()), url(r'^projector.*$', views.ProjectorView.as_view()),

View File

@ -5,6 +5,7 @@ import re
import uuid import uuid
from collections import OrderedDict from collections import OrderedDict
from operator import attrgetter from operator import attrgetter
from textwrap import dedent
from urllib.parse import unquote from urllib.parse import unquote
from django.apps import apps from django.apps import apps
@ -92,41 +93,49 @@ class RealProjectorView(utils_views.View):
return HttpResponse(content) return HttpResponse(content)
class AppsJsView(utils_views.View): class WebclientJavaScriptView(utils_views.View):
""" """
Returns javascript code to be called in the angular app. This view returns JavaScript code for the main entry point in the
AngularJS app for the requested realm (site or projector). Also code
The javascript code loads all js-files defined by the installed (django) for plugins is appended. The result is not uglified.
apps and creates the angular modules for each angular app.
""" """
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
angular_modules = [] angular_modules = []
js_files = [] js_files = []
realm = kwargs.get('realm') # Result is 'site' or 'projector'
for app_config in apps.get_app_configs(): for app_config in apps.get_app_configs():
# Add the angular app, if the module has one. # Add the angular app if the module has one.
if getattr(app_config, if getattr(app_config, 'angular_{}_module'.format(realm), False):
'angular_{}_module'.format(kwargs.get('openslides_app')), angular_modules.append('OpenSlidesApp.{app_name}.{realm}'.format(
False): app_name=app_config.label,
angular_modules.append('OpenSlidesApp.{app_name}.{app}'.format( realm=realm))
app=kwargs.get('openslides_app'),
app_name=app_config.label))
# Add all js files that the module needs # 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: try:
app_js_files = app_config.js_files app_js_files = app_config.js_files
except AttributeError: except AttributeError:
# The app needs no js-files # The app needs no JavaScript files.
pass pass
else: else:
js_files += [ js_files.extend(app_js_files)
'{static}{path}'.format(
static=settings.STATIC_URL, # Use JavaScript loadScript function from
path=path)
for path in app_js_files]
# Use javascript loadScript function from
# http://balpha.de/2011/10/jquery-script-insertion-and-its-consequences-for-debugging/ # http://balpha.de/2011/10/jquery-script-insertion-and-its-consequences-for-debugging/
return HttpResponse( # jQuery is required.
content = dedent(
""" """
(function () {
var loadScript = function (path) { var loadScript = function (path) {
var result = $.Deferred(), var result = $.Deferred(),
script = document.createElement("script"); script = document.createElement("script");
@ -147,17 +156,18 @@ class AppsJsView(utils_views.View):
}; };
""" + """ +
""" """
angular.module('OpenSlidesApp.{app}', {angular_modules}); angular.module('OpenSlidesApp.{realm}', {angular_modules});
var deferres = []; var deferres = [];
{js_files}.forEach( function(js_file) {{ deferres.push(loadScript(js_file)); }} ); {js_files}.forEach( function(js_file) {{ deferres.push(loadScript(js_file)); }} );
$.when.apply(this,deferres).done( function() {{ $.when.apply(this,deferres).done( function() {{
angular.bootstrap(document,['OpenSlidesApp.{app}']); angular.bootstrap(document,['OpenSlidesApp.{realm}']);
}} ); }} );
""".format(realm=realm, angular_modules=angular_modules, js_files=js_files) +
""" """
.format( }());
app=kwargs.get('openslides_app'), """)
angular_modules=angular_modules,
js_files=js_files)) return HttpResponse(content, content_type='application/javascript')
# Viewsets for the REST API # Viewsets for the REST API

View File

@ -6,7 +6,6 @@ class MediafilesAppConfig(AppConfig):
verbose_name = 'OpenSlides Mediafiles' verbose_name = 'OpenSlides Mediafiles'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/mediafiles/base.js', 'js/mediafiles/site.js', 'js/mediafiles/projector.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -7,8 +7,6 @@ class MotionsAppConfig(AppConfig):
verbose_name = 'OpenSlides Motion' verbose_name = 'OpenSlides Motion'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/motions/base.js', 'js/motions/site.js', 'js/motions/projector.js',
'js/motions/linenumbering.js', 'js/motions/diff.js', 'js/motions/motion-services.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -6,7 +6,6 @@ class UsersAppConfig(AppConfig):
verbose_name = 'OpenSlides Users' verbose_name = 'OpenSlides Users'
angular_site_module = True angular_site_module = True
angular_projector_module = True angular_projector_module = True
js_files = ['js/users/base.js', 'js/users/site.js', 'js/users/projector.js']
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.

View File

@ -10,17 +10,19 @@
"es6-promise": "~3.0.2", "es6-promise": "~3.0.2",
"gulp": "~3.9.0", "gulp": "~3.9.0",
"gulp-angular-gettext": "~2.1.0", "gulp-angular-gettext": "~2.1.0",
"gulp-angular-templatecache": "^2.0.0",
"gulp-concat": "~2.6.0", "gulp-concat": "~2.6.0",
"gulp-cssnano": "~2.1.0", "gulp-cssnano": "~2.1.0",
"gulp-if": "~2.0.0", "gulp-if": "~2.0.0",
"gulp-jshint": "~2.0.0", "gulp-jshint": "~2.0.0",
"gulp-rename": "~1.2.2", "gulp-rename": "~1.2.2",
"gulp-sourcemaps": "~1.6.0",
"gulp-uglify": "~1.5.2", "gulp-uglify": "~1.5.2",
"jasmine": "~2.4.1", "jasmine": "~2.4.1",
"jshint": "~2.9.2", "jshint": "~2.9.2",
"karma": "~1.1.0", "karma": "~1.1.0",
"karma-jasmine": "~1.0.2",
"karma-chrome-launcher": "~1.0.1", "karma-chrome-launcher": "~1.0.1",
"karma-jasmine": "~1.0.2",
"main-bower-files": "~2.11.1", "main-bower-files": "~2.11.1",
"po2json": "~0.4.1", "po2json": "~0.4.1",
"sprintf-js": "~1.0.3", "sprintf-js": "~1.0.3",