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

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

parents 8e12d0ef d23f9810
......@@ -105,6 +105,53 @@ module.exports = function (grunt) {
}
]
},
jquery_tablesorter: {
files: [
{
cwd: 'bower_components/tablesorter/dist/js/',
src: [
'jquery.tablesorter.min.js'
],
expand: true,
dest: typo3_js,
flatten: true
},
{
cwd: 'bower_components/tablesorter/dist/css/',
src: [
'theme.default.min.css'
],
dest: typo3_css,
filter: 'isFile',
expand: true,
flatten: true
}
]
},
jquery_tablesorter_devel: {
files: [
{
cwd: 'bower_components/tablesorter/dist/js/',
src: [
'jquery.tablesorter.min.js'
],
expand: true,
dest: 'js/',
flatten: true
},
{
cwd: 'bower_components/tablesorter/dist/css/',
src: [
'theme.default.min.css'
],
dest: 'css/',
filter: 'isFile',
expand: true,
flatten: true
}
]
},
jqwidgets: {
files: [
{
......@@ -241,7 +288,8 @@ module.exports = function (grunt) {
devel: {
files: {
"css/qfq-bs.css": "less/qfq-bs.css.less",
"css/qfq-plain.css": "less/qfq-plain.css.less"
"css/qfq-plain.css": "less/qfq-plain.css.less",
"css/tablesorter.css": "less/tablesorter.less"
},
options: {
banner: "/* Change qfq-bs.css.less, not qfq-bs.css */"
......@@ -269,7 +317,7 @@ module.exports = function (grunt) {
'javascript/src/*.js',
'javascript/src/Helper/*.js',
'javascript/src/Element/*.js',
'less/qfq-bs.css.less'
'less/*.less'
],
tasks: ['default'],
options: {
......
......@@ -18,6 +18,7 @@
],
"dependencies": {
"bootstrap": "~3.3.6",
"jqwidgets": "*"
"jqwidgets": "*",
"tablesorter": "jquery.tablesorter#^2.25.6"
}
}
......@@ -14,6 +14,8 @@ if (!QfqNS) {
/**
* Tab Constructor.
*
* Programatically access Bootstrap nav-tabs.
*
* @param {string} tabId HTML id of the element having `nav` and `nav-tabs` classes
* @constructor
*/
......@@ -34,7 +36,10 @@ if (!QfqNS) {
};
/**
* Get active tab from DOM
* Get active tab from DOM.
*
* Used upon object creation to fill the currentTab. It gets the ID of the currently shown tab. It does it, by
* targeting the element in the navigator having the `active` class set.
*
* @private
*/
......
......@@ -33,7 +33,7 @@ if (!QfqNS) {
this.getNewButton().click(this.handleNewClick.bind(this));
this.getDeleteButton().click(this.handleDeleteClick.bind(this));
this.setupRefreshHandler();
this.setupFormUpdateHandler();
};
n.QfqForm.prototype.setBsTabs = function (bsTabs) {
......@@ -61,11 +61,11 @@ if (!QfqNS) {
}
};
n.QfqForm.prototype.setupRefreshHandler = function () {
$('input[data-load]').on('change', this.refreshHandler.bind(this));
n.QfqForm.prototype.setupFormUpdateHandler = function () {
$('input[data-load]').on('change', this.formUpdateHandler.bind(this));
};
n.QfqForm.prototype.refreshHandler = function () {
n.QfqForm.prototype.formUpdateHandler = function () {
var that = this;
$.post(this.dataRefreshUrl, this.form.serialize(), "json")
.fail(function (jqXHR, textStatus, errorThrown) {
......@@ -73,11 +73,36 @@ if (!QfqNS) {
alert.show();
})
.done(function (data) {
this.applyElementConfiguration(data);
this.handleFormUpdate(data);
}.bind(that));
};
n.QfqForm.prototype.handleFormUpdate = function (data) {
if (!data.status) {
throw new Error("Expected 'status' attribute to be present.");
}
if (data.status === "error") {
var alert = new QfqNS.Alert("Error while updating form:<br>" + (data.message ? data.message : "No reason" +
" given"), "error");
alert.show();
return;
}
if (data.status === "success") {
if (!data['form-update']) {
throw new Error("'form-update' attribute missing in form update data");
}
this.applyElementConfiguration(data['form-update']);
return;
}
throw new Error("Unexpected status: '" + data.status + "'");
};
/**
* @private
*/
......@@ -459,26 +484,32 @@ if (!QfqNS) {
);
};
/**
*
* @param configuration {array} array of objects.
*/
n.QfqForm.prototype.applyElementConfiguration = function (configuration) {
// key is the name attribute of the Form control.
for (var key in configuration) {
if (!configuration.hasOwnProperty(key)) continue;
var arrayLength = configuration.length;
for (var i = 0; i < arrayLength; i++) {
var configurationItem = configuration[i];
var formElementName = configurationItem["form-element"];
if (formElementName === undefined) {
QfqNS.Log.error("configuration lacks 'form-element' attribute. Skipping.");
continue;
}
try {
var element = n.Element.getElement(key);
var formControlConfig = configuration[key];
var element = n.Element.getElement(formElementName);
if (formControlConfig.value !== undefined) {
element.setValue(formControlConfig.value);
if (configurationItem.value !== undefined) {
element.setValue(configurationItem.value);
}
if (formControlConfig.readonly !== undefined) {
element.setReadOnly(formControlConfig.readonly);
if (configurationItem.readonly !== undefined) {
element.setReadOnly(configurationItem.readonly);
}
if (formControlConfig.disabled !== undefined) {
element.setEnabled(!formControlConfig.disabled);
if (configurationItem.disabled !== undefined) {
element.setEnabled(!configurationItem.disabled);
}
} catch (e) {
......
/* Tablesorter Custom LESS Theme by Rob Garrison
To create your own theme, modify the code below and run it through
a LESS compiler, like this one: http://leafo.net/lessphp/editor.html
or download less.js from http://lesscss.org/
Test out these custom less files live
Basic Theme : http://codepen.io/Mottie/pen/eqBbn
Bootstrap : http://codepen.io/Mottie/pen/Ltzpi
Metro Style : http://codepen.io/Mottie/pen/gCslk
*/
/*** theme ***/
@theme : tablesorter-default;
/*** fonts ***/
@tableHeaderFont : 11px 'trebuchet ms', verdana, arial;
@tableBodyFont : 11px 'trebuchet ms', verdana, arial;
/*** color definitions ***/
/* for best results, only change the hue (120),
leave the saturation (60%) and luminosity (75%) alone
pick the color from here: http://hslpicker.com/#99E699 */
@headerBackground : hsl(120, 60%, 75%);
@borderAndBackground : #cdcdcd;
@overallBorder : @borderAndBackground 1px solid;
@headerTextColor : #000;
@bodyBackground : #fff;
@bodyTextColor : #000;
@headerAsc : darken(spin(@headerBackground, 5), 10%);
/* darken(@headerBackground, 10%); */
@headerDesc : lighten(spin(@headerBackground, -5), 10%);
/* desaturate(@headerAsc, 5%); */
@captionBackground : #fff;
/* it might be best to match the document body background color here */
@errorBackground : #e6bf99;
/* ajax error message (added to thead) */
@filterCellBackground : #eee;
@filterElementTextColor: #333;
@filterElementBkgd : #fff;
@filterElementBorder : 1px solid #bbb;
@filterTransitionTime : 0.1s;
@filterRowHiddenHeight : 4px;
/* becomes height using padding (so it's divided by 2) */
@overallPadding : 4px;
/* 20px should be slightly wider than the icon width to avoid overlap */
@headerPadding : 4px 20px 4px 4px;
/* url(icons/loading.gif); */
@processingIcon : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=');
/* zebra striping */
.allRows {
background-color: @bodyBackground;
color: @bodyTextColor;
}
.evenRows {
background-color: lighten(@headerBackground, 40%);
color: @bodyTextColor;
}
.oddRows {
background-color: lighten(@headerBackground, 20%);
}
/* hovered rows */
.oddHovered {
background-color: desaturate(@headerBackground, 60%);
color: @bodyTextColor;
}
.evenHovered {
background-color: lighten(desaturate(@headerBackground, 60%), 10%);
color: @bodyTextColor;
}
/* Columns widget */
@primaryOdd : spin(@headerBackground, 10);
/* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */
@primaryEven : lighten(@primaryOdd, 10%);
@secondaryOdd : @primaryEven;
@secondaryEven : lighten(@primaryEven, 5%);
@tertiaryOdd : @secondaryEven;
@tertiaryEven : lighten(@secondaryEven, 5%);
/* Filter widget transition */
.filterWidgetTransition {
-webkit-transition: line-height @filterTransitionTime ease;
-moz-transition: line-height @filterTransitionTime ease;
-o-transition: line-height @filterTransitionTime ease;
transition: line-height @filterTransitionTime ease;
}
/*** Arrows ***/
@arrowPosition : right 5px center;
/* black */
@unsortedBlack : url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
@sortAscBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
@sortDescBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
/* white */
@unsortedWhite : url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
@sortAscWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
@sortDescWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
/* automatically choose the correct arrow/text color */
.headerText (@a) when (lightness(@a) >= 50%) {
color: @headerTextColor;
}
.headerText (@a) when (lightness(@a) < 50%) {
color: lighten(@headerTextColor, 90%);
}
.unsorted (@a) when (lightness(@a) >= 50%) {
background-image: @unsortedBlack;
}
.unsorted (@a) when (lightness(@a) < 50%) {
background-image: @unsortedWhite;
}
.sortAsc (@a) when (lightness(@a) >= 50%) {
background-image: @sortAscBlack;
}
.sortAsc (@a) when (lightness(@a) < 50%) {
background-image: @sortAscWhite;
}
.sortDesc (@a) when (lightness(@a) >= 50%) {
background-image: @sortDescBlack;
}
.sortDesc (@a) when (lightness(@a) < 50%) {
background-image: @sortDescWhite;
}
/* variable theme name - requires less.js 1.3+;
or just replace (!".@{theme}") with the contents of @theme
*/
.@{theme} {
/* style header */
.tablesorter-header {
.unsorted(@headerBackground);
background-repeat: no-repeat;
background-position: @arrowPosition;
padding: @headerPadding;
cursor: pointer;
}
.tablesorter-header.sorter-false {
background-image: none;
cursor: default;
padding: @overallPadding;
}
.tablesorter-headerAsc {
background-color: @headerAsc;
.sortAsc(@headerBackground);
}
.tablesorter-headerDesc {
background-color: @headerDesc;
.sortDesc(@headerBackground);
}
/* tfoot */
tfoot .tablesorter-headerAsc,
tfoot .tablesorter-headerDesc {
/* remove sort arrows from footer */
background-image: none;
}
}
{
"text": {
"value": "value. Now its enabled",
"disabled": false,
"readonly": true
},
"select": {
"value": [
{
"value": 100,
"text": "a",
"selected": true
},
{
"value": 200,
"text": "b",
"selected": false
}
]
},
"radio": {
"value": "a",
"disabled": false
},
"checkbox": {
"value": true,
"readonly": true
},
"trigger": {
"value": false
}
}
\ No newline at end of file
"status": "success",
"message": "ok",
"form-update": [
{
"form-element": "text",
"value": "value. Now its enabled",
"disabled": false,
"readonly": true
},
{
"form-element": "select",
"value": [
{
"value": 100,
"text": "a",
"selected": true
},
{
"value": 200,
"text": "b",
"selected": false
}
]
},
{
"form-element": "radio",
"value": "a",
"disabled": false
},
{
"form-element": "checkbox",
"value": true,
"readonly": true
},
{
"form-element": "trigger",
"value": false
}
]
}
{
"status": "error",
"message": "Sample error message",
"form-update": [
{
"form-element": "text",
"value": "value. Now its enabled",
"disabled": false,
"readonly": true
},
{
"form-element": "select",
"value": [
{
"value": 100,
"text": "a",
"selected": true
},
{
"value": 200,
"text": "b",
"selected": false
}
]
},
{
"form-element": "radio",
"value": "a",
"disabled": false
},
{
"form-element": "checkbox",
"value": true,
"readonly": true
},
{
"form-element": "trigger",
"value": false
}
]
}
......@@ -14,37 +14,53 @@
</head>
<body>
<label>Refresh URL
<select name="refreshUrl" id="refreshUrl">
<option>404 error</option>
<option>form_refresh.json</option>
<option>form_refresh_error.json</option>
</select>
</label>
<div style="float: right">
<pre id="sample">
{
"text": {
"value": "value. Now its enabled",
"disabled": false,
"readonly": true
},
"select": {
"value": [
{
"value": 1,
"text": "a",
"selected": true
},
{
"value": 2,
"text": "b",
"selected": false
}
]
},
"radio": {
"value": "a",
"disabled": false
},
"checkbox": {
"value": true,
"readonly": true
}
}
[
{
"form-element": "text",
"value": "value. Now its enabled",
"disabled": false,
"readonly": true
},
{
"form-element": "select",
"value": [
{
"value": 100,
"text": "a",
"selected": true
},
{
"value": 200,
"text": "b",
"selected": false
}
]
},
{
"form-element": "radio",
"value": "a",
"disabled": false
},
{
"form-element": "checkbox",
"value": true,
"readonly": true
},
{
"form-element": "trigger",
"value": false
}
]
</pre>
<button id="copy">Copy</button>
</div>
......@@ -162,7 +178,7 @@
<script src="../js/qfq.debug.js"></script>
<script type="text/javascript">
$(function () {
var form = new QfqNS.QfqForm("myForm", 'none', 'none', 'api/form_refresh.json');
var form = new QfqNS.QfqForm("myForm", 'none', 'none', 'api/' + $("#refreshUrl").val());
QfqNS.Log.level = 0;
$("#applyconfig").click(function () {
......@@ -174,7 +190,13 @@
$("#copy").click(function () {
$("#configuration").val($("#sample").text());
})
});
$("#refreshUrl").on("change", function (evt) {
form.dataRefreshUrl = 'api/' + $(evt.target).val();
});
});
</script>
</body>
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../css/bootstrap.min.css">
<link rel="stylesheet" href="../css/bootstrap-theme.min.css">
<link rel="stylesheet" href="../css/jqx.base.css">
<link rel="stylesheet" href="../css/jqx.darkblue.css">
<link rel="stylesheet" href="../css/tablesorter.css">
<title>Tablesorter</title>
</head>
<body>
<table id="thetable" class="table">