Merge pull request #2374 from normanjaeckel/LoadJavaScript
Changed loading of JavaScript files.
This commit is contained in:
commit
f288cb4967
@ -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"
|
||||||
|
@ -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
|
||||||
--------------------------
|
--------------------------
|
||||||
|
41
gulpfile.js
41
gulpfile.js
@ -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 () {
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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([
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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()),
|
||||||
|
@ -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,72 +93,81 @@ 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
|
||||||
try:
|
# are delivered by an extra file js/openslides.js which can be
|
||||||
app_js_files = app_config.js_files
|
# created via gulp.
|
||||||
except AttributeError:
|
core_apps = (
|
||||||
# The app needs no js-files
|
'openslides.core',
|
||||||
pass
|
'openslides.agenda',
|
||||||
else:
|
'openslides.motions',
|
||||||
js_files += [
|
'openslides.assignments',
|
||||||
'{static}{path}'.format(
|
'openslides.users',
|
||||||
static=settings.STATIC_URL,
|
'openslides.mediafiles',
|
||||||
path=path)
|
)
|
||||||
for path in app_js_files]
|
if app_config.name not in core_apps:
|
||||||
# Use javascript loadScript function from
|
try:
|
||||||
|
app_js_files = app_config.js_files
|
||||||
|
except AttributeError:
|
||||||
|
# The app needs no JavaScript files.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
js_files.extend(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(
|
||||||
"""
|
"""
|
||||||
var loadScript = function (path) {
|
(function () {
|
||||||
var result = $.Deferred(),
|
var loadScript = function (path) {
|
||||||
script = document.createElement("script");
|
var result = $.Deferred(),
|
||||||
script.async = "async";
|
script = document.createElement("script");
|
||||||
script.type = "text/javascript";
|
script.async = "async";
|
||||||
script.src = path;
|
script.type = "text/javascript";
|
||||||
script.onload = script.onreadystatechange = function(_, isAbort) {
|
script.src = path;
|
||||||
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
|
script.onload = script.onreadystatechange = function(_, isAbort) {
|
||||||
if (isAbort)
|
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
|
||||||
result.reject();
|
if (isAbort)
|
||||||
else
|
result.reject();
|
||||||
result.resolve();
|
else
|
||||||
}
|
result.resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
script.onerror = function () { result.reject(); };
|
||||||
|
$("head")[0].appendChild(script);
|
||||||
|
return result.promise();
|
||||||
};
|
};
|
||||||
script.onerror = function () { result.reject(); };
|
|
||||||
$("head")[0].appendChild(script);
|
|
||||||
return result.promise();
|
|
||||||
};
|
|
||||||
""" +
|
""" +
|
||||||
"""
|
"""
|
||||||
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
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user