Move inline editing methods into a separate service

This commit is contained in:
Tobias Hößl 2016-09-07 21:42:53 +02:00
parent 2753af3585
commit 2605239244
4 changed files with 139 additions and 118 deletions

View File

@ -8,7 +8,7 @@ class MotionsAppConfig(AppConfig):
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_files = ['js/motions/base.js', 'js/motions/site.js', 'js/motions/projector.js',
'js/motions/linenumbering.js', 'js/motions/diff.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

@ -0,0 +1,121 @@
(function () {
"use strict";
angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.lineNumbering'])
.factory('MotionInlineEditing', [
'Editor',
'Motion',
'Config',
'$timeout',
function (Editor, Motion, Config, $timeout) {
var obj = {
active: false,
changed: false,
trivialChange: false,
editor: null,
lineBrokenText: null,
originalHtml: null
};
var $scope, motion;
obj.init = function (_scope, _motion) {
$scope = _scope;
motion = _motion;
obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
obj.originalHtml = obj.lineBrokenText;
if (motion.state.versioning && Config.get('motions_allow_disable_versioning').value) {
obj.trivialChange = true;
}
};
obj.tinymceOptions = Editor.getOptions(null, true);
obj.tinymceOptions.readonly = 1;
obj.tinymceOptions.setup = function (editor) {
obj.editor = editor;
editor.on("init", function () {
obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
obj.editor.setContent(obj.lineBrokenText);
obj.originalHtml = obj.editor.getContent();
obj.changed = false;
});
editor.on("change", function () {
obj.changed = (editor.getContent() != obj.originalHtml);
});
editor.on("undo", function () {
obj.changed = (editor.getContent() != obj.originalHtml);
});
};
obj.setVersion = function (_motion, versionId) {
motion = _motion; // If this is not updated,
console.log(versionId, motion.getTextWithLineBreaks(versionId));
obj.lineBrokenText = motion.getTextWithLineBreaks(versionId);
obj.changed = false;
obj.active = false;
if (obj.editor) {
obj.editor.setContent(obj.lineBrokenText);
obj.editor.setMode("readonly");
obj.originalHtml = obj.editor.getContent();
} else {
obj.originalHtml = obj.lineBrokenText;
}
};
obj.enable = function () {
obj.editor.setMode("design");
obj.active = true;
obj.changed = false;
obj.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
obj.editor.setContent(obj.lineBrokenText);
obj.originalHtml = obj.editor.getContent();
$timeout(function () {
obj.editor.focus();
}, 100);
};
obj.disable = function () {
obj.editor.setMode("readonly");
obj.active = false;
obj.changed = false;
obj.lineBrokenText = obj.originalHtml;
obj.editor.setContent(obj.originalHtml);
};
obj.save = function () {
if (!motion.isAllowed('update')) {
throw "No permission to update motion";
}
motion.setTextStrippingLineBreaks(motion.active_version, obj.editor.getContent());
motion.disable_versioning = (obj.trivialChange && Config.get('motions_allow_disable_versioning').value);
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};
}
);
};
return obj;
}
]);
}());

View File

@ -2,7 +2,7 @@
'use strict'; 'use strict';
angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.diff']) angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlidesApp.motions.diff', 'OpenSlidesApp.motions.motionservices'])
.factory('MotionContentProvider', ['gettextCatalog', function(gettextCatalog) { .factory('MotionContentProvider', ['gettextCatalog', function(gettextCatalog) {
/** /**
@ -1022,7 +1022,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
.controller('MotionDetailCtrl', [ .controller('MotionDetailCtrl', [
'$scope', '$scope',
'$http', '$http',
'$timeout',
'ngDialog', 'ngDialog',
'MotionComment', 'MotionComment',
'MotionForm', 'MotionForm',
@ -1032,7 +1031,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
'Tag', 'Tag',
'User', 'User',
'Workflow', 'Workflow',
'Editor',
'Config', 'Config',
'motion', 'motion',
'SingleMotionContentProvider', 'SingleMotionContentProvider',
@ -1040,11 +1038,11 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
'PollContentProvider', 'PollContentProvider',
'PdfMakeConverter', 'PdfMakeConverter',
'PdfMakeDocumentProvider', 'PdfMakeDocumentProvider',
'MotionInlineEditing',
'gettextCatalog', 'gettextCatalog',
'diffService', function($scope, $http, ngDialog, MotionComment, MotionForm, Motion, Category, Mediafile, Tag,
function($scope, $http, $timeout, ngDialog, MotionComment, MotionForm, Motion, Category, Mediafile, Tag, User, Workflow, Config, motion, SingleMotionContentProvider, MotionContentProvider,
User, Workflow, Editor, Config, motion, SingleMotionContentProvider, MotionContentProvider, PollContentProvider, PdfMakeConverter, PdfMakeDocumentProvider, MotionInlineEditing, gettextCatalog) {
PollContentProvider, PdfMakeConverter, PdfMakeDocumentProvider, gettextCatalog, diffService) {
Motion.bindOne(motion.id, $scope, 'motion'); Motion.bindOne(motion.id, $scope, 'motion');
Category.bindAll({}, $scope, 'categories'); Category.bindAll({}, $scope, 'categories');
Mediafile.bindAll({}, $scope, 'mediafiles'); Mediafile.bindAll({}, $scope, 'mediafiles');
@ -1056,7 +1054,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
$scope.isCollapsed = true; $scope.isCollapsed = true;
$scope.commentsFields = MotionComment.getFields(); $scope.commentsFields = MotionComment.getFields();
$scope.lineNumberMode = Config.get('motions_default_line_numbering').value; $scope.lineNumberMode = Config.get('motions_default_line_numbering').value;
$scope.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
if (motion.parent_id) { if (motion.parent_id) {
Motion.bindOne(motion.parent_id, $scope, 'parent'); Motion.bindOne(motion.parent_id, $scope, 'parent');
} }
@ -1167,17 +1164,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
// show specific version // show specific version
$scope.showVersion = function (version) { $scope.showVersion = function (version) {
$scope.version = version.id; $scope.version = version.id;
$scope.lineBrokenText = motion.getTextWithLineBreaks($scope.version); $scope.inlineEditing.setVersion(motion, version.id);
$scope.inlineEditing.allowed = (motion.isAllowed('update') && $scope.version == motion.getVersion(-1).id);
$scope.inlineEditing.changed = false;
$scope.inlineEditing.active = false;
if ($scope.inlineEditing.editor) {
$scope.inlineEditing.editor.setContent($scope.lineBrokenText);
$scope.inlineEditing.editor.setMode("readonly");
$scope.inlineEditing.originalHtml = $scope.inlineEditing.editor.getContent();
} else {
$scope.inlineEditing.originalHtml = $scope.lineBrokenText;
}
}; };
// permit specific version // permit specific version
$scope.permitVersion = function (version) { $scope.permitVersion = function (version) {
@ -1198,96 +1185,8 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
}; };
// Inline editing functions // Inline editing functions
$scope.inlineEditing = { $scope.inlineEditing = MotionInlineEditing;
allowed: (motion.isAllowed('update') && $scope.version == motion.getVersion(-1).id), $scope.inlineEditing.init($scope, motion);
active: false,
changed: false,
trivialChange: false,
trivialChangeAllowed: false,
editor: null,
originalHtml: $scope.lineBrokenText,
};
if (motion.state.versioning && Config.get('motions_allow_disable_versioning').value) {
$scope.inlineEditing.trivialChange = true;
$scope.inlineEditing.trivialChangeAllowed = true;
}
$scope.$watch(
function () {
return Motion.lastModified();
},
function () {
$scope.inlineEditing.trivialChangeAllowed =
(motion.state.versioning && Config.get('motions_allow_disable_versioning').value);
}
);
$scope.tinymceOptions = Editor.getOptions(null, true);
$scope.tinymceOptions.readonly = 1;
$scope.tinymceOptions.setup = function (editor) {
$scope.inlineEditing.editor = editor;
editor.on("init", function () {
$scope.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
$scope.inlineEditing.editor.setContent($scope.lineBrokenText);
$scope.inlineEditing.originalHtml = $scope.inlineEditing.editor.getContent();
$scope.inlineEditing.changed = false;
});
editor.on("change", function () {
$scope.inlineEditing.changed = (editor.getContent() != $scope.inlineEditing.originalHtml);
});
editor.on("undo", function() {
$scope.inlineEditing.changed = (editor.getContent() != $scope.inlineEditing.originalHtml);
});
};
$scope.enableInlineEditing = function() {
$scope.inlineEditing.editor.setMode("design");
$scope.inlineEditing.active = true;
$scope.inlineEditing.changed = false;
$scope.lineBrokenText = motion.getTextWithLineBreaks($scope.version);
$scope.inlineEditing.editor.setContent($scope.lineBrokenText);
$scope.inlineEditing.originalHtml = $scope.inlineEditing.editor.getContent();
$timeout(function() {
$scope.inlineEditing.editor.focus();
}, 100);
};
$scope.disableInlineEditing = function() {
$scope.inlineEditing.editor.setMode("readonly");
$scope.inlineEditing.active = false;
$scope.inlineEditing.changed = false;
$scope.lineBrokenText = $scope.inlineEditing.originalHtml;
$scope.inlineEditing.editor.setContent($scope.inlineEditing.originalHtml);
};
$scope.motionInlineSave = function () {
if (!$scope.inlineEditing.allowed) {
throw "No permission to update motion";
}
motion.setTextStrippingLineBreaks(motion.active_version, $scope.inlineEditing.editor.getContent());
motion.disable_versioning = $scope.inlineEditing.trivialChange;
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};
}
);
};
} }
]) ])

View File

@ -273,12 +273,13 @@
<div class="details"> <div class="details">
<div class="row"> <div class="row">
<div class="pull-right inline-editing-activator" ng-if="inlineEditing.allowed"> <div class="pull-right inline-editing-activator"
<button ng-if="!inlineEditing.active" ng-click="enableInlineEditing()" class="btn btn-sm btn-default"> ng-if="motion.isAllowed('update') && version == motion.getVersion(-1).id">
<button ng-if="!inlineEditing.active" ng-click="inlineEditing.enable()" class="btn btn-sm btn-default">
<i class="fa fa-toggle-off"></i> <i class="fa fa-toggle-off"></i>
<translate>Inline editing inactive</translate> <translate>Inline editing inactive</translate>
</button> </button>
<button ng-if="inlineEditing.active" ng-click="disableInlineEditing()" class="btn btn-sm btn-default"> <button ng-if="inlineEditing.active" ng-click="inlineEditing.disable()" class="btn btn-sm btn-default">
<i class="fa fa-toggle-on"></i> <i class="fa fa-toggle-on"></i>
<translate>Inline editing active</translate> <translate>Inline editing active</translate>
</button> </button>
@ -312,9 +313,9 @@
<div ng-class="{'col-sm-8': (lineNumberMode != 'outside'), 'col-sm-12': (lineNumberMode == 'outside')}"> <div ng-class="{'col-sm-8': (lineNumberMode != 'outside'), 'col-sm-12': (lineNumberMode == 'outside')}">
<div ng-if="inlineEditing.allowed"> <div ng-if="motion.isAllowed('update') && version == motion.getVersion(-1).id">
<div ng-show="inlineEditing.active"> <div ng-show="inlineEditing.active">
<div ui-tinymce="tinymceOptions" ng-model="lineBrokenText" <div ui-tinymce="inlineEditing.tinymceOptions" ng-model="inlineEditing.lineBrokenText"
class="motion-text line-numbers-{{ lineNumberMode }}"></div> class="motion-text line-numbers-{{ lineNumberMode }}"></div>
</div> </div>
<div ng-show="!inlineEditing.active" ng-bind-html="motion.getTextWithLineBreaks(version) | trusted" <div ng-show="!inlineEditing.active" ng-bind-html="motion.getTextWithLineBreaks(version) | trusted"
@ -322,14 +323,14 @@
<div class="motion-save-toolbar" ng-class="{ 'visible': (inlineEditing.changed && inlineEditing.active) }"> <div class="motion-save-toolbar" ng-class="{ 'visible': (inlineEditing.changed && inlineEditing.active) }">
<div class="changed-hint" translate>The text has been changed.</div> <div class="changed-hint" translate>The text has been changed.</div>
<button type="button" ng-click="motionInlineSave()" class="btn btn-primary">Save</button> <button type="button" ng-click="inlineEditing.save()" class="btn btn-primary">Save</button>
<label ng-if="inlineEditing.trivialChangeAllowed"> <label ng-if="motion.state.versioning && config('motions_allow_disable_versioning')">
<input type="checkbox" ng-model="inlineEditing.trivialChange" value="1"> <input type="checkbox" ng-model="inlineEditing.trivialChange" value="1">
<span translate>Trivial change</span> <span translate>Trivial change</span>
</label> </label>
</div> </div>
</div> </div>
<div ng-if="!inlineEditing.allowed"> <div ng-if="!(motion.isAllowed('update') && version == motion.getVersion(-1).id)">
<div ng-bind-html="motion.getTextWithLineBreaks(version) | trusted" <div ng-bind-html="motion.getTextWithLineBreaks(version) | trusted"
class="motion-text line-numbers-{{ lineNumberMode }}"></div> class="motion-text line-numbers-{{ lineNumberMode }}"></div>
</div> </div>