Commit c3feb019 authored by Carsten  Rose's avatar Carsten Rose
Browse files

Merge remote-tracking branch 'origin/raos_work' into Typo3integrated

Client Logic for Close/Save implemented
parents fc4d5e5e fa5ff135
......@@ -9,6 +9,8 @@
/.npmpackages
/.phpdocinstall
/js
/css
/fonts
/qfq.flowchart.dia.autosave
/extension/config.ini
/support
......
......@@ -40,6 +40,39 @@ module.exports = function (grunt) {
}
]
},
bootstrap_dev: {
files: [
{
cwd: 'bower_components/bootstrap/dist/css/',
src: [
'bootstrap.min.css',
'bootstrap-theme.min.css'
],
dest: 'css/',
filter: 'isFile',
expand: true,
flatten: true
},
{
cwd: 'bower_components/bootstrap/dist/js/',
src: [
'bootstrap.min.js'
],
dest: 'js/',
expand: true,
flatten: true
},
{
cwd: 'bower_components/bootstrap/dist/fonts/',
expand: true,
src: [
'*'
],
dest: 'fonts/',
flatten: true
}
]
},
jquery: {
files: [
{
......@@ -96,6 +129,37 @@ module.exports = function (grunt) {
dest: typo3_css
}
]
},
jqwidgets_devel: {
files: [
{
cwd: 'bower_components/jqwidgets/jqwidgets/',
src: [
'jqx-all.js'
],
expand: true,
dest: 'js/',
flatten: true
},
{
cwd: 'bower_components/jqwidgets/jqwidgets/styles/',
src: [
'jqx.base.css',
'jqx.darkblue.css'
],
expand: true,
dest: 'css/',
flatten: true
},
{
cwd: 'bower_components/jqwidgets/jqwidgets/styles/',
src: [
'images/**'
],
expand: true,
dest: 'css/'
}
]
}
},
uglify: {
......@@ -114,14 +178,37 @@ module.exports = function (grunt) {
},
concat: {
debug: {
src: [ 'javascript/src/*.js'],
src: [
'javascript/src/Helper/*.js',
'javascript/src/*.js'
],
dest: 'js/<%= pkg.name %>.debug.js'
}
},
less: {
production: {
files: {
"extension/Resources/Public/Css/qfq-jqw.css": "less/qfq-jqw.css.less"
},
options: {
compress: true
}
},
devel: {
files: {
"css/qfq-jqw.css": "less/qfq-jqw.css.less"
},
options: {
banner: "/* Change qfq-jqw.css.less, not qfq-jqw.css */"
}
}
},
watch: {
scripts: {
files: [
'javascript/src/*.js'
'javascript/src/*.js',
'javascript/src/Helper/*.js',
'less/qfq-jqw.css.less'
],
tasks: [ 'default' ],
options: {
......@@ -138,8 +225,9 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
// Default task(s).
grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'copy']);
grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'copy', 'less']);
};
\ No newline at end of file
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
/* global $ */
if (!QfqNS) {
var QfqNS = {};
}
(function (n) {
'use strict';
/**
* Display a message.
*
* Display one message on a page. Several instances can be used per page, which results in messages being
* stacked, with the latest message being at the bottom.
*
* The first instance displaying a message will append an `alert container` to the body. The last message being
* dismissed will remove the `alert container`. A typical call sequence might look like:
*
* var alert = new QfqNS.Alert("Text being displayed", "info", "none");
* alert.show();
*
* Messages may have different background colors (severity levels), controlled by the second argument
* `messageType` of the constructor. The possible values are
*
* * `"info"`
* * `"warning"`
* * `"error"`
*
* The values are translated into Bootstrap `alert-*` classes internally.
*
* Messages can feature clickable buttons, or no buttons at all, in which case a click anywhere on the message
* will dismiss it. Buttons are controlled by the third argument to the constructor:
*
* * `"okcancel"`
* * `"yesno"`
* * `"yesnosave"`
* * `"none"`
*
* Callback functions of the `Ok` or `Yes` button are added by calling Alert#addOkButtonHandler(). Callback
* functions of the `Cancel` or `No` button are added by calling Alert#addCancelButtonHandler(). Lastly,
* Alert#addSaveButtonHandler() adds callback functions to the `Save` button.
*
* Regardless of the
*
*
* @param message {string} message to be displayed
* @param messageType {string} type of message, can either be `"info"`, `"warning"`, or `"error"`.
* @param buttons {string} buttons to be displayed, can either be `"okcancel"`, `"yesno"`, `"yesnosave"`, or `"none"`.
* When `"none"` is provided, clicking anywhere on the message will dismiss it.
* @constructor
*/
n.Alert = function (message, messageType, buttons) {
this.message = message;
this.messageType = messageType || "info";
this.buttons = buttons || "none";
this.$alertDiv = null;
this.shown = false;
// this.timeout < 1 means forever
this.timeout = 0;
this.fadeInDuration = 400;
this.fadeOutDuration = 400;
this.timerId = null;
this.userOkButtonHandlers = new QfqNS.Helper.FunctionList();
this.userCancelButtonHandlers = new QfqNS.Helper.FunctionList();
this.userSaveButtonHandlers = new QfqNS.Helper.FunctionList();
};
/**
*
* @private
*/
n.Alert.prototype.makeAlertContainerSingleton = function () {
var alertContainer = $("#qfqAlertContainer");
if (alertContainer.length === 0) {
// No container so far, create one
alertContainer = $("<div>").attr("id", "qfqAlertContainer");
$("body").append(alertContainer);
}
return alertContainer;
};
/**
*
* @returns {number|jQuery}
* @private
*/
n.Alert.prototype.countAlertsInAlertContainer = function () {
return $("#qfqAlertContainer > div").length;
};
/**
* @private
*/
n.Alert.prototype.removeAlertContainer = function () {
$("#qfqAlertContainer").remove();
};
/**
* @private
*/
n.Alert.prototype.getAlertClassBasedOnMessageType = function () {
switch (this.messageType) {
case "warning":
return "alert-warning";
case "error":
return "alert-danger";
/* jshint -W086 */
default:
QfqNS.Log.warning("Message type '" + this.messageType + "' unknown. Use default type.");
case "info":
return "alert-success";
/* jshint +W086 */
}
};
/**
* @private
*/
n.Alert.prototype.getButtons = function () {
var buttons = null;
switch (this.buttons) {
case 'okcancel':
buttons = $("<div>")
.addClass("alert-buttons")
.append(
$("<a>")
.append("Ok")
.addClass("btn btn-default")
.click(this.okButtonHandler.bind(this))
)
.append(
$("<a>")
.append("Cancel")
.addClass("btn btn-default")
.click(this.cancelButtonHandler.bind(this))
);
return buttons;
case "yesno":
buttons = $("<div>")
.addClass("alert-buttons")
.append(
$("<a>")
.append("Yes")
.addClass("btn btn-default")
.click(this.okButtonHandler.bind(this))
)
.append(
$("<a>")
.append("No")
.addClass("btn btn-default")
.click(this.cancelButtonHandler.bind(this))
);
return buttons;
case "yesnosave":
buttons = $("<div>")
.addClass("alert-buttons")
.append(
$("<a>")
.append("Yes")
.addClass("btn btn-default")
.click(this.okButtonHandler.bind(this))
)
.append(
$("<a>")
.append("No")
.addClass("btn btn-default")
.click(this.cancelButtonHandler.bind(this))
)
.append(
$("<a>")
.append("Save & Close")
.addClass("btn btn-default")
.click(this.saveButtonHandler.bind(this))
)
;
return buttons;
/* jshint -W086 */
default:
QfqNS.Log.warning("Buttons '" + this.buttons + "' unknown. Use default buttons");
case "none":
break;
/* jshint +W086 */
}
return buttons;
};
n.Alert.prototype.show = function () {
if (this.shown) {
// We only allow showing once
return;
}
var $alertContainer = this.makeAlertContainerSingleton();
this.$alertDiv = $("<div>")
.addClass("alert")
.addClass(this.getAlertClassBasedOnMessageType())
.attr("role", "alert")
.append(this.message);
var buttons = this.getButtons();
if (buttons && this.timeout < 1) {
// Buttons will take care of removing the message
this.$alertDiv.append(buttons);
} else {
// Click on the message anywhere will remove the message
this.$alertDiv.click(this.removeAlert.bind(this));
}
$alertContainer.append(this.$alertDiv);
this.$alertDiv.fadeIn(this.fadeInDuration, this.afterFadeIn.bind(this));
this.shown = true;
};
/**
* @private
*/
n.Alert.prototype.afterFadeIn = function () {
if (this.timeout > 0) {
this.timerId = window.setTimeout(this.removeAlert.bind(this), this.timeout);
}
};
/**
*
* @param event
*
* @private
*/
n.Alert.prototype.removeAlert = function (event) {
if (!event || event.type !== "click") {
// No user click, so it must be a timer event
if (this.timerId) {
window.clearTimeout(this.timerId);
this.timerId = null;
} else {
QfqNS.Log.error("Alert.remove(): Identified timer event, but had no timer id");
}
}
var that = this;
this.$alertDiv.fadeOut(this.fadeOutDuration, function () {
that.$alertDiv.remove();
that.$alertDiv = null;
that.shown = false;
if (that.countAlertsInAlertContainer() === 0) {
that.removeAlertContainer();
}
});
};
n.Alert.prototype.addOkButtonHandler = function (handler) {
this.userOkButtonHandlers.addFunction(handler);
};
n.Alert.prototype.addCancelButtonHandler = function (handler) {
this.userCancelButtonHandlers.addFunction(handler);
};
n.Alert.prototype.addSaveButtonHandler = function (handler) {
this.userSaveButtonHandlers.addFunction(handler);
};
/**
*
* @param handler
*
* @private
*/
n.Alert.prototype.okButtonHandler = function (handler) {
this.removeAlert();
this.userOkButtonHandlers.call(this);
};
/**
*
* @param handler
*
* @private
*/
n.Alert.prototype.saveButtonHandler = function (handler) {
this.removeAlert();
this.userSaveButtonHandlers.call(this);
};
/**
*
* @param handler
*
* @private
*/
n.Alert.prototype.cancelButtonHandler = function (handler) {
this.removeAlert();
this.userCancelButtonHandlers.call(this);
};
n.Alert.prototype.isShown = function () {
return this.shown;
};
})(QfqNS);
\ No newline at end of file
......@@ -23,7 +23,7 @@ if (!QfqNS) {
this._tabActiveSelector = '#' + this.tabId + ' .active a[data-toggle="tab"]';
this.tabs = {};
this.currentTab = this.getActiveTabFromDOM();
this.userTabShowHandlers = [];
this.userTabShowHandlers = new QfqNS.Helper.FunctionList();
// Fill this.tabs
......@@ -99,9 +99,7 @@ if (!QfqNS) {
var that = this;
QfqNS.Log.debug("BSTabs.tabShowHandler(): invoke user handler(s)");
this.userTabShowHandlers.forEach(function (handler) {
handler(that);
});
this.userTabShowHandlers.call(that);
QfqNS.Log.debug('Exit: BSTabs.tabShowHandler()');
};
......@@ -165,11 +163,7 @@ if (!QfqNS) {
* @param {function} handler handler function. `this` will be passed as first and only argument to the handler.
*/
n.BSTabs.prototype.addTabShowHandler = function (handler) {
if (typeof handler !== "function") {
throw new Error("Tab show handler must be function");
}
this.userTabShowHandlers.push(handler);
this.userTabShowHandlers.addFunction(handler);
};
n.BSTabs.prototype.getTabName = function (tabId) {
......@@ -185,4 +179,24 @@ if (!QfqNS) {
return this.currentTab;
};
n.BSTabs.prototype.getContainingTabIdForFormControl = function (formControlName) {
var $formControl = $("[name=" + formControlName + "]");
if ($formControl.length === 0) {
QfqNS.Log.debug("BSTabs.getContainingTabForFormControl(): unable to find form control with name '" + formControlName + "'");
return null;
}
var iterator = $formControl[0];
while (iterator !== null) {
if (iterator.hasAttribute('role') &&
iterator.getAttribute('role') === 'tabpanel') {
return iterator.id || null;
}
iterator = iterator.parentElement;
}
return null;
};
})(QfqNS);
\ No newline at end of file
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
/* global $ */
if (!QfqNS) {
var QfqNS = {};
}
(function (n) {
'use strict';
n.Form = function (formId) {
this.formId = formId;
if (!document.forms[this.formId]) {
throw new Error("Form '" + formId + "' does not exist.");
}
this.formChanged = false;
this.userFormChangeHandlers = new QfqNS.Helper.FunctionList();
this.userResetHandlers = new QfqNS.Helper.FunctionList();
this.userSubmitSuccessHandlers = new QfqNS.Helper.FunctionList();
this.userSubmitFailureHandlers = new QfqNS.Helper.FunctionList();
this.$form = $(document.forms[this.formId]);
this.$form.on("change", this.changeHandler.bind(this));
};
/**
*
* @param event
*
* @private
*/
n.Form.prototype.changeHandler = function (event) {
this.formChanged = true;
this.userFormChangeHandlers.call(this);
};
n.Form.prototype.addChangeHandler = function (callback) {
this.userFormChangeHandlers.addFunction(callback);
};
n.Form.prototype.addResetHandler = function (callback) {
this.userResetHandlers.addFunction(callback);
};
n.Form.prototype.addSubmitSuccessHandler = function (callback) {
this.userSubmitSuccessHandlers.addFunction(callback);
};
n.Form.prototype.addSubmitFailureHandler = function (callback) {
this.userSubmitFailureHandlers.addFunction(callback);
};
n.Form.prototype.getFormChanged = function () {
return this.formChanged;
};
n.Form.prototype.resetFormChanged = function () {
this.formChanged = false;
this.userResetHandlers.call(this);
};
n.Form.prototype.submitTo = function (to) {
$.post(to, this.$form.serialize())
.done(this.ajaxSuccessHandler.bind(this))
.fail(this.submitFailureHandler.bind(this));
};
/**
*
* @param data
* @param textStatus
* @param jqXHR
*
* @private
*/
n.Form.prototype.ajaxSuccessHandler = function (data, textStatus, jqXHR) {
this.userSubmitSuccessHandlers.call(this, data, textStatus);
};
/**
*
*
* @private
*/
n.Form.prototype.submitFailureHandler = function (jqXHR, textStatus, errorThrown) {
this.userSubmitFailureHandlers.call(this, textStatus, jqXHR, errorThrown);
};
})(QfqNS);
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
/* global $ */
if (!QfqNS) {
var QfqNS = {};
}
if (!QfqNS.Helper) {
QfqNS.Helper = {};
}