Commit 1f6a89c1 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge branch 'readOnly' into 'master'

View Only codecorrection

See merge request !128
parents 23126819 84c59be9
Pipeline #1676 passed with stage
in 2 minutes and 3 seconds
......@@ -3268,11 +3268,11 @@ Type: annotate
Annotate image or text. Typically the image or text has been uploaded during a previous step. The annotation will be
saved in *FormElement.name* column of the current record. The uploaded file itself will not be modified. The annotations
can be shown in edit or readonly mode and modified again.
can be shown in edit (and might be modified) or in readonly mode.
Two modes are available:
image
grafic
A simple grafic editor to paint on top of the image (best by a tablet with pen or grafic tablet). The uploaded image
is shown in the background. All drawings are saved as a JSON fabric.js data string. Supported file types:
**png, svg**. PDF files can be easily divided into per page SVG files during upload - see `split-pdf-upload`_
......@@ -3287,11 +3287,11 @@ text
Drawing with fabric.js might produce a lot data. Take care the column type/size is big enough (>=64kB).
Image
"""""
Grafic
""""""
An image, specified by `FormElement.parameter`: imageSource={{pathFileName}}, will be displayed in the background. On
form load, both, the image and an optional already given JSON fabric.js data string, will be displayed. The image is SIP
An image, specified by ``FormElement.parameter.imageSource={{pathFileName}}``, will be displayed in the background. On
form load, both, the image and an optional already given grafical annotations, will be displayed. The image is SIP
protected and will be loaded on demand.
**Form.parameter**
......@@ -3301,9 +3301,9 @@ protected and will be loaded on demand.
+===================+=======================+==================================================================================+
| annotateType | grafic | *grafic|text*. Default is *grafic*. Select mode. |
+-------------------+-----------------------+----------------------------------------------------------------------------------+
| imageSource | {{pathFileName2}} | Background image. E.g. `fileadmin/images/scan.png` |
| imageSource | <path filename> | Background image. E.g. `fileadmin/images/scan.png` |
+-------------------+-----------------------+----------------------------------------------------------------------------------+
| defaultPenColor | <rgb hex value> | Pen default color, after loading the fabric element. Default is '0000FF' (blue). |
| defaultPenColor | <rgb hex value> | Pen default color, after loading the fabric element. Default is '0000FF' (blue). |
+-------------------+----------------------------------------------------------------------------------------------------------+
.. note::
......@@ -3321,7 +3321,7 @@ Code
+====================+=======================+==================================================================================+
| annotateType | text | *grafic|text*. Default is *grafic*. Select mode. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| textSource | <fileadmin/code.m> | Text file to annotate. |
| textSource | <path filename> | Text file to annotate. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
| annotateUserName | <john doe> | Will be shown at annotation line. |
+--------------------+-----------------------+----------------------------------------------------------------------------------+
......
......@@ -3192,7 +3192,7 @@ abstract class AbstractBuildForm {
Support::setIfNotSet($formElement, FE_ANNOTATE_USER_NAME);
Support::setIfNotSet($formElement, FE_ANNOTATE_USER_AVATAR);
$dataHighlight=HelperFile::getFileTypeHighlight($formElement[FE_HIGHLIGHT]??'',$formElement[FE_TEXT_SOURCE] );
$dataHighlight = HelperFile::getFileTypeHighlight($formElement[FE_HIGHLIGHT] ?? '', $formElement[FE_TEXT_SOURCE]);
// <div class="codeCorrection" data-uid='{"uid": 1, "name": "Reginald Commenter", "avatar": "http://www"}' data-file="../javascript/src/CodeCorrection.js" data-target="codeCorrection-output1">
......@@ -3210,7 +3210,11 @@ abstract class AbstractBuildForm {
$attributeDiv .= Support::doAttribute('data-target', $formElement[FE_HTML_ID]);
$attributeDiv .= Support::doAttribute('data-highlight', $dataHighlight);
$attributeDiv .= $this->getAttributeFeMode($formElement[FE_MODE]);
$htmlAnnotate = Support::wrapTag('<div ' . $attributeDiv . ' data-uid=\''. $jsonDataUid . '\' >', '', false);
if ($formElement[FE_MODE] == FE_MODE_READONLY) {
$attributeDiv .= Support::doAttribute('data-view-only', 'true');
}
$htmlAnnotate = Support::wrapTag('<div ' . $attributeDiv . ' data-uid=\'' . $jsonDataUid . '\' >', '', false);
// $htmlAnnotate = Support::wrapTag('<div ' . $attributeDiv .'>', '', false);
$attributeInput = Support::doAttribute('id', $formElement[FE_HTML_ID]);
......@@ -3271,6 +3275,9 @@ abstract class AbstractBuildForm {
$attributeFabric .= Support::doAttribute('data-emojis', 'typo3conf/ext/qfq/Resources/Public/Json/qfq.emoji.json');
$attributeFabric .= Support::doAttribute('data-fabric-color', HelperFormElement::penColorToHex($formElement));
$attributeFabric .= $this->getAttributeFeMode($formElement[FE_MODE]);
if ($formElement[FE_MODE] == FE_MODE_READONLY) {
$attributeFabric .= Support::doAttribute('data-view-only', 'true');
}
$htmlFabric = Support::wrapTag('<div ' . $attributeFabric . ' >', '', false);
$attributeInput = Support::doAttribute('id', $formElement[FE_HTML_ID]);
......@@ -3301,8 +3308,7 @@ abstract class AbstractBuildForm {
* @throws CodeException
* @throws UserFormException
*/
public
function buildImageCut(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildImageCut(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$htmlImage = '';
if ($mode == FORM_LOAD && !empty($formElement[FE_IMAGE_SOURCE])) {
......@@ -3340,6 +3346,7 @@ abstract class AbstractBuildForm {
}
$attributeFabric .= Support::doAttribute('data-image-output', $htmlFabricImageId);
$attributeFabric .= $this->getAttributeFeMode($formElement[FE_MODE]);
$htmlFabric = Support::wrapTag('<div ' . $attributeFabric . ' >', '', false);
// <input id="fabric-output" name="fabric-data" type="hidden">
......@@ -3372,8 +3379,7 @@ abstract class AbstractBuildForm {
* @throws CodeException
* @throws UserFormException
*/
private
function fileToSipUrl($pathFileName) {
private function fileToSipUrl($pathFileName) {
$param[DOWNLOAD_MODE] = DOWNLOAD_MODE_FILE;
$param[SIP_DOWNLOAD_PARAMETER] = base64_encode(TOKEN_FILE . PARAM_TOKEN_DELIMITER . $pathFileName);
......@@ -3399,8 +3405,7 @@ abstract class AbstractBuildForm {
* @throws UserFormException
* @throws UserReportException
*/
public
function buildDateTime(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildDateTime(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$attribute = '';
$placeholder = '';
......@@ -3522,8 +3527,7 @@ abstract class AbstractBuildForm {
* @throws CodeException
* @throws UserFormException
*/
public
function buildDateJQW(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildDateJQW(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$arrMinMax = null;
// if ($formElement[FE_PLACEHOLDER] == '') {
......@@ -3608,8 +3612,7 @@ abstract class AbstractBuildForm {
* @throws UserFormException
* @throws UserReportException
*/
public
function buildEditor(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildEditor(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$attribute = '';
//TODO plugin autoresize nutzen um Editorgroesse anzugeben
......@@ -3652,8 +3655,7 @@ abstract class AbstractBuildForm {
*
* @return array
*/
private
function setEditorConfig(array $formElement, $htmlFormElementName) {
private function setEditorConfig(array $formElement, $htmlFormElementName) {
$flagMaxHeight = false;
// plugins
......@@ -3708,8 +3710,7 @@ abstract class AbstractBuildForm {
* @return string
* @throws \qfq\UserFormException
*/
private
function getPrefixedElementsAsJSON($prefix, array $formElement) {
private function getPrefixedElementsAsJSON($prefix, array $formElement) {
$settings = array();
// E.g.: $key = editor-plugins
......@@ -3746,8 +3747,7 @@ abstract class AbstractBuildForm {
*
* @throws UserFormException
*/
public
function buildGridJQW(array $formElement, $htmlFormElementName, $value, $fake, $mode = FORM_LOAD) {
public function buildGridJQW(array $formElement, $htmlFormElementName, $value, $fake, $mode = FORM_LOAD) {
// TODO: implement
throw new UserFormException("Not implemented yet: buildGridJQW()", ERROR_NOT_IMPLEMENTED);
}
......@@ -3765,8 +3765,7 @@ abstract class AbstractBuildForm {
* @throws CodeException
* @throws UserFormException
*/
public
function buildNote(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildNote(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$json = $this->getFormElementForJson($htmlFormElementName, $value, $formElement);
......@@ -3786,8 +3785,7 @@ abstract class AbstractBuildForm {
*
* @return mixed
*/
public
function buildPill(array $formElement, $htmlFormElementName, $value, array &$json) {
public function buildPill(array $formElement, $htmlFormElementName, $value, array &$json) {
return $value;
}
......@@ -3810,8 +3808,7 @@ abstract class AbstractBuildForm {
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public
function buildFieldset(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildFieldset(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$attribute = '';
// save parent processed FE's
......@@ -3856,8 +3853,7 @@ abstract class AbstractBuildForm {
*
* @return array
*/
private
function fillFeSpecNativeCheckboxWithTgMax(array $formElementArr, $tgMaxCopies) {
private function fillFeSpecNativeCheckboxWithTgMax(array $formElementArr, $tgMaxCopies) {
foreach ($formElementArr as $key => $formElement) {
if ($formElement[FE_TYPE] == FE_TYPE_CHECKBOX) {
......@@ -3888,8 +3884,7 @@ abstract class AbstractBuildForm {
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
public
function buildTemplateGroup(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
public function buildTemplateGroup(array $formElement, $htmlFormElementName, $value, array &$json, $mode = FORM_LOAD) {
$attribute = '';
$html = '';
......@@ -4012,8 +4007,7 @@ EOT;
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
private
function templateGroupCollectFilledElements($max, $htmlDelete, array &$json) {
private function templateGroupCollectFilledElements($max, $htmlDelete, array &$json) {
$record = $this->store->getStore(STORE_RECORD); // current values
if ($record === false || count($record) === 0) {
......@@ -4099,8 +4093,7 @@ EOT;
* @throws UserFormException
* @throws UserReportException
*/
private
function templateGroupDoValue() {
private function templateGroupDoValue() {
// Fire 'value' statement
$tgMax = 0;
......
......@@ -42,6 +42,7 @@ var QfqNS = QfqNS || {};
this.users = [];
this.currentUser = {};
this.language = "";
this.readOnly = false;
this.syntaxHighlight = {};
};
......@@ -58,22 +59,21 @@ var QfqNS = QfqNS || {};
};
this.page = page;
this.language = this.$parent.data("highlight") || "typo3conf/ext/qfq/Resources/Public/Json/javascript.json";
this.readOnly = this.$parent.data("view-only") || false;
this.currentUser = $container.data("uid");
var that = this;
if (this.$target.val()) {
var jImport = $.parseJSON(this.$target.val());
if (jImport.annotations) {
this.annotations = jImport.annotations;
console.log("[CodeCorrection] Imported Annotations: " + this.annotations.length);
}
if (jImport.users) {
this.users = jImport.users;
console.log("[CodeCorrection] Imported Users: " + this.users.length);
if (this.readOnly) {
if (this.$parent.data("annotations")) {
var jsonAnnotations = this.$parent.data("annotations");
this.annotations = jsonAnnotations.annotations;
this.users = jsonAnnotations.users;
} else {
this._importFromTarget();
}
} else {
this._importFromTarget();
}
if (this.data.url) {
// Get data of a file and write it to data.text
$.get(this.data.url, function(response) {
......@@ -87,6 +87,20 @@ var QfqNS = QfqNS || {};
}
};
n.CodeCorrection.prototype._importFromTarget = function() {
if (this.$target.val()) {
var jImport = $.parseJSON(this.$target.val());
if (jImport.annotations) {
this.annotations = jImport.annotations;
console.log("[CodeCorrection] Imported Annotations: " + this.annotations.length);
}
if (jImport.users) {
this.users = jImport.users;
console.log("[CodeCorrection] Imported Users: " + this.users.length);
}
}
};
n.CodeCorrection.prototype._prepareBuild = function() {
var that = this;
this.syntaxHighlight = new n.SyntaxHighlighter();
......@@ -206,8 +220,11 @@ var QfqNS = QfqNS || {};
* @private
*/
n.CodeCorrection.prototype._buildCommentContainer = function($hook) {
var options = {
readOnly: this.readOnly
};
var commentController = new n.CommentController();
commentController.buildContainer($hook);
commentController.buildContainer($hook, options);
commentController.setCurrentUser(this.currentUser);
return commentController;
};
......@@ -350,13 +367,15 @@ var QfqNS = QfqNS || {};
comments.commentController.toggle();
comments.commentController.emitEvent("new");
} else {
comments.lineNumber = lineCount;
comments.commentController = new n.CommentController();
comments.commentController.buildContainer($hook);
comments.commentController.setCurrentUser(this.currentUser);
comments.commentController.displayEditor();
this._setListeners(comments.commentController);
this.annotations.push(comments);
if (!this.readOnly) {
comments.lineNumber = lineCount;
comments.commentController = new n.CommentController();
comments.commentController.buildContainer($hook, {readOnly: this.readOnly});
comments.commentController.setCurrentUser(this.currentUser);
comments.commentController.displayEditor();
this._setListeners(comments.commentController);
this.annotations.push(comments);
}
}
};
......
......@@ -30,7 +30,7 @@ var QfqNS = QfqNS || {};
this.$comment = {};
this.$text = {};
if (arguments.length === 3) {
this.options = { readonly: false };
this.options = { readOnly: false };
} else {
this.options = options;
}
......@@ -81,7 +81,9 @@ var QfqNS = QfqNS || {};
class: "qfqCommentText"
});
$comment.html(this.comment.comment);
$comment.append(this._getCommands());
if (!this.options.readOnly) {
$comment.append(this._getCommands());
}
this.$text= $comment;
$comment.appendTo($commentWrap);
return $commentWrap;
......
......@@ -28,6 +28,7 @@ var QfqNS = QfqNS || {};
this.$container = {};
this.$parent = {};
this.height = "auto";
this.options = {};
// Event Emitter is a Library qfq uses to emit custom Events.
this.eventEmitter = new EventEmitter();
};
......@@ -69,10 +70,11 @@ var QfqNS = QfqNS || {};
this._changeHandler(event);
};
n.CommentController.prototype.buildContainer = function($hook) {
n.CommentController.prototype.buildContainer = function($hook, options) {
var $container = $("<div />", {
class: "qfqCommentContainer"
});
this.options = options;
$hook.after($container);
this.$container = $container;
};
......@@ -99,7 +101,7 @@ var QfqNS = QfqNS || {};
};
n.CommentController.prototype.addComment = function(comment, user) {
var commentObject = new n.Comment(comment, user, this.$container);
var commentObject = new n.Comment(comment, user, this.$container, this.options);
commentObject.display();
this.comments.push(commentObject);
this._changeHandler("new", commentObject);
......@@ -129,14 +131,16 @@ var QfqNS = QfqNS || {};
};
n.CommentController.prototype.displayEditor = function() {
var editor = new n.Editor();
var that = this;
var $editor = editor.buildEditor();
editor.on("editor.submit", function(editor) {
that._handleEditorSubmit(editor);
});
$editor.appendTo(this.$container);
editor.$textArea.focus();
if (!this.options.readOnly) {
var editor = new n.Editor();
var that = this;
var $editor = editor.buildEditor();
editor.on("editor.submit", function (editor) {
that._handleEditorSubmit(editor);
});
$editor.appendTo(this.$container);
editor.$textArea.focus();
}
};
n.CommentController.prototype._handleEditorSubmit = function(editor) {
......
......@@ -121,6 +121,7 @@ var QfqNS = QfqNS || {};
$.post(submitUrl, this.$form.serialize())
.done(this.ajaxSuccessHandler.bind(this))
.fail(this.submitFailureHandler.bind(this));
console.log(this.$form.serialize());
};
n.Form.prototype.serialize = function () {
......
......@@ -491,6 +491,7 @@ select.qfq-locked:invalid {
.codeCorrectionWrap {
border: 1px solid #ccc;
border-top: unset;
margin-bottom: 10px;
}
.qfqCodeCorrectionTitle {
......@@ -520,6 +521,7 @@ select.qfq-locked:invalid {
text-align: left;
font-size: 1.2em;
font-family: monospace;
word-break: break-word;
}
.qfqCodeLine {
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="../extension/Resources/Public/Css/bootstrap.min.css">
<link rel="stylesheet" href="../extension/Resources/Public/Css/bootstrap-theme.min.css">
<link rel="stylesheet" href="../extension/Resources/Public/Css/qfq-bs.css">
<title>Input Mode Switcher</title>
</head>
<body style="background-color: #f5f5f5;">
<div class="container-fluid">
<div class="row">
<div class="col-md-10 ">
<div class="btn-toolbar pull-right" role="toolbar">
<div class="btn-group" role="group">
<button id="save-button" type="button" class="btn btn-default navbar-btn"><span
class="glyphicon glyphicon-ok"></span></button>
<button id="close-button" type="button" class="btn btn-default navbar-btn"><span
class="glyphicon glyphicon-remove"></span></button>
</div>
<div class="btn-group" role="group">
<button id="delete-button" type="button" class="btn btn-default navbar-btn"><span
class="glyphicon glyphicon-trash"></span></button>
</div>
<div class="btn-group" role="group">
<a id="form-new-button" href="personmock.html?s=badcaffe1" class="btn btn-default navbar-btn"><span
class="glyphicon glyphicon-plus"></span></a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<div class="annotate-text"
data-uid='{ "uid": 5,
"name": "Definitely not an AI",
"avatar": "mockData/avatar1.png"}'
data-file="../javascript/src/CodeCorrection.js"
data-annotations= '{ "annotations": [
{ "lineNumber": 15,
"comments": [
{ "uid": 1,
"comment": "If we knew what it was we were doing, it would not be called research, would it?",
"dateTime": "2018-05-12 09:45:00"
}]
}, { "lineNumber": 47,
"comments": [
{ "uid": 1,
"comment": "The most beautiful thing we can experience is the mysterious. It is the source of all true art and all science.",
"dateTime": "2018-05-12 09:45:00"
},
{ "uid": 1,
"comment": "The only reason for time is so that everything does not happen at once.",
"dateTime": "0000-00-00 00:00:00"
}]
}
],
"users": [
{ "uid": 1,
"name": "Albert Einstein",
"avatar": "http://institutoiltonesteves.com.br/img/avatar-4.jpg"
}
]}'
data-highlight="mockData/javascript.json"
data-view-only="true"
>
</div>
<div class="annotate-text"
data-uid='{ "uid": 5,
"name": "Definitely not an AI",
"avatar": "mockData/avatar1.png"}'
data-file="../javascript/src/CodeCorrection.js"
data-target= 'codeCorrection-output1'
data-highlight="mockData/javascript.json"
data-view-only="true"
>
</div>
<input id="codeCorrection-output1" name="correction-data" type="hidden"
value='{ "annotations": [
{ "lineNumber": 15,
"comments": [
{ "uid": 1,
"comment": "If we knew what it was we were doing, it would not be called research, would it?",
"dateTime": "2018-05-12 09:45:00"
}]
}, { "lineNumber": 47,
"comments": [
{ "uid": 1,
"comment": "The most beautiful thing we can experience is the mysterious. It is the source of all true art and all science.",
"dateTime": "2018-05-12 09:45:00"
},
{ "uid": 1,
"comment": "The only reason for time is so that everything does not happen at once.",
"dateTime": "0000-00-00 00:00:00"
}]
}
],
"users": [
{ "uid": 1,
"name": "Albert Einstein",
"avatar": "http://institutoiltonesteves.com.br/img/avatar-4.jpg"
}
]}'>
</div>
</div>
</div>
<p><br></p>
<script src="../js/jquery.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
<script src="../js/validator.min.js"></script>
<script src="../js/EventEmitter.min.js"></script>
<script src="../js/qfq.debug.js"></script>
<script type="text/javascript">
$(function () {
var qfqPage = new QfqNS.QfqPage({
tabsId: 'myTabs',
formId: 'myForm',
submitTo: 'api/' + $("#submitTo").val(),
deleteUrl: 'api/' + $("#deleteUrl").val(),
fileUploadTo: 'api/' + $("#uploadTo").val(),
fileDeleteUrl: 'api/' + $("#fileDeleteUrl").val()
});
QfqNS.Log.level = 0;
//var codeCorrection = new QfqNS.CodeCorrection(qfqPage, {
// url: '../javascript/src/CodeCorrection.js'
//}, $('.annotate-text'), $('#codeCorrection-output1'), {
// uid: 5,
// name: "Definitely not an AI",
// avatar: "mockData/avatar1.png"
//}, 'http://localhost:63342/qfq/mockup/mockData/javascript.json');
//codeCorrection.initialize();
});
</script>
</body>
</html>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment