Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
e4eaa1fb
Commit
e4eaa1fb
authored
Mar 22, 2016
by
Carsten Rose
Browse files
Merge remote-tracking branch 'origin/raos_work' into crose_work
parents
8cd9955c
e12b61b8
Changes
29
Hide whitespace changes
Inline
Side-by-side
Gruntfile.js
View file @
e4eaa1fb
var
path
=
require
(
'
path
'
);
module
.
exports
=
function
(
grunt
)
{
var
typo3_css
=
'
extension/Resources/Public/Css/
'
;
var
typo3_js
=
'
extension/Resources/Public/JavaScript/
'
;
...
...
@@ -181,14 +182,50 @@ module.exports = function (grunt) {
'
javascript/src/*.js
'
]
},
concat
:
{
concat
_in_order
:
{
debug_standalone
:
{
src
:
js_sources
,
dest
:
'
js/<%= pkg.name %>.debug.js
'
options
:
{
extractRequired
:
function
(
filepath
,
filecontent
)
{
var
workingdir
=
path
.
normalize
(
filepath
).
split
(
path
.
sep
);
workingdir
.
pop
();
var
deps
=
this
.
getMatches
(
/
\*\s
*@depend
\s(
.*
\.
js
)
/g
,
filecontent
);
deps
.
forEach
(
function
(
dep
,
i
)
{
var
dependency
=
workingdir
.
concat
([
dep
]);
deps
[
i
]
=
path
.
join
.
apply
(
null
,
dependency
);
});
return
deps
;
},
extractDeclared
:
function
(
filepath
)
{
return
[
filepath
];
},
onlyConcatRequiredFiles
:
false
},
files
:
{
'
js/<%= pkg.name %>.debug.js
'
:
js_sources
}
},
debug_extension
:
{
src
:
js_sources
,
dest
:
typo3_js
+
'
<%= pkg.name %>.debug.js
'
options
:
{
extractRequired
:
function
(
filepath
,
filecontent
)
{
var
workingdir
=
path
.
normalize
(
filepath
).
split
(
path
.
sep
);
workingdir
.
pop
();
var
deps
=
this
.
getMatches
(
/
\*\s
*@depend
\s(
.*
\.
js
)
/g
,
filecontent
);
deps
.
forEach
(
function
(
dep
,
i
)
{
var
dependency
=
workingdir
.
concat
([
dep
]);
deps
[
i
]
=
path
.
join
.
apply
(
null
,
dependency
);
});
return
deps
;
},
extractDeclared
:
function
(
filepath
)
{
return
[
filepath
];
},
onlyConcatRequiredFiles
:
false
},
files
:
{
'
extension/Resources/Public/JavaScript/<%= pkg.name %>.debug.js
'
:
js_sources
}
}
},
less
:
{
...
...
@@ -234,7 +271,7 @@ module.exports = function (grunt) {
'
javascript/src/Element/*.js
'
,
'
less/qfq-bs.css.less
'
],
tasks
:
[
'
default
'
],
tasks
:
[
'
default
'
],
options
:
{
spawn
:
true
}
...
...
@@ -247,14 +284,15 @@ module.exports = function (grunt) {
grunt
.
loadNpmTasks
(
'
grunt-contrib-uglify
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-copy
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-concat
'
);
grunt
.
loadNpmTasks
(
'
grunt-concat-in-order
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-jshint
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-watch
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-less
'
);
grunt
.
loadNpmTasks
(
'
grunt-contrib-jasmine
'
);
// Default task(s).
grunt
.
registerTask
(
'
default
'
,
[
'
jshint
'
,
'
concat
'
,
'
uglify
'
,
'
copy
'
,
'
less
'
]);
grunt
.
registerTask
(
'
default
'
,
[
'
jshint
'
,
'
concat
_in_order
'
,
'
uglify
'
,
'
copy
'
,
'
less
'
]);
grunt
.
registerTask
(
'
run-jasmine
'
,
[
'
jshint
'
,
'
concat
'
,
'
jasmine
'
]);
grunt
.
registerTask
(
'
run-jasmine
'
,
[
'
jshint
'
,
'
concat
_in_order
'
,
'
jasmine
'
]);
};
\ No newline at end of file
JSDocConf.json
View file @
e4eaa1fb
{
"source"
:
{
"include"
:
[
"javascript/src/"
"javascript/src/"
,
"javascript/src/Helper/"
,
"javascript/src/Element/"
],
"includePattern"
:
".+
\\
.js"
},
...
...
javascript/src/Alert.js
View file @
e4eaa1fb
...
...
@@ -44,8 +44,6 @@ if (!QfqNS) {
* 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"`.
...
...
@@ -200,6 +198,7 @@ if (!QfqNS) {
var
$alertContainer
=
this
.
makeAlertContainerSingleton
();
this
.
$alertDiv
=
$
(
"
<div>
"
)
.
hide
()
.
addClass
(
"
alert
"
)
.
addClass
(
this
.
getAlertClassBasedOnMessageType
())
.
attr
(
"
role
"
,
"
alert
"
)
...
...
@@ -216,7 +215,7 @@ if (!QfqNS) {
}
$alertContainer
.
append
(
this
.
$alertDiv
);
this
.
$alertDiv
.
fadeI
n
(
this
.
fadeInDuration
,
this
.
afterFadeIn
.
bind
(
this
));
this
.
$alertDiv
.
slideDow
n
(
this
.
fadeInDuration
,
this
.
afterFadeIn
.
bind
(
this
));
this
.
shown
=
true
;
...
...
@@ -233,22 +232,18 @@ if (!QfqNS) {
/**
*
* @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
"
);
}
n
.
Alert
.
prototype
.
removeAlert
=
function
()
{
// In case we have an armed timer (or expired timer, for that matter), disarm it.
if
(
this
.
timerId
)
{
window
.
clearTimeout
(
this
.
timerId
);
this
.
timerId
=
null
;
}
var
that
=
this
;
this
.
$alertDiv
.
fadeOut
(
this
.
fadeOutDuration
,
function
()
{
this
.
$alertDiv
.
slideUp
(
this
.
fadeOutDuration
,
function
()
{
that
.
$alertDiv
.
remove
();
that
.
$alertDiv
=
null
;
that
.
shown
=
false
;
...
...
javascript/src/Element/Checkbox.js
0 → 100644
View file @
e4eaa1fb
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
/* @depend FormGroup.js */
if
(
!
QfqNS
)
{
var
QfqNS
=
{};
}
if
(
!
QfqNS
.
Element
)
{
QfqNS
.
Element
=
{};
}
(
function
(
n
)
{
'
use strict
'
;
/**
*
* @param $element
* @constructor
*/
function
Checkbox
(
$element
)
{
n
.
FormGroup
.
call
(
this
,
$element
);
if
(
!
this
.
isType
(
"
checkbox
"
))
{
throw
new
Error
(
"
$element is not of type 'checkbox'
"
);
}
}
Checkbox
.
prototype
=
Object
.
create
(
n
.
FormGroup
.
prototype
);
Checkbox
.
prototype
.
constructor
=
Checkbox
;
Checkbox
.
prototype
.
setValue
=
function
(
val
)
{
this
.
$element
.
prop
(
'
checked
'
,
val
);
};
Checkbox
.
prototype
.
getValue
=
function
()
{
return
this
.
$element
.
prop
(
'
checked
'
);
};
n
.
Checkbox
=
Checkbox
;
})(
QfqNS
.
Element
);
javascript/src/Element/Element.js
deleted
100644 → 0
View file @
8cd9955c
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
if
(
!
QfqNS
)
{
var
QfqNS
=
{};
}
if
(
!
QfqNS
.
Element
)
{
QfqNS
.
Element
=
{};
}
(
function
(
n
)
{
'
use strict
'
;
n
.
Element
=
function
(
$element
)
{
if
(
!
$element
||
$element
.
length
===
0
)
{
throw
new
Error
(
"
No element
"
);
}
this
.
formGroup
=
new
n
.
FormGroup
(
$element
);
};
/**
*
* @param type
* @returns {boolean}
*
* @protected
*/
n
.
Element
.
prototype
.
isType
=
function
(
type
)
{
var
lowerCaseType
=
type
.
toLowerCase
();
var
isOfType
=
true
;
this
.
formGroup
.
$element
.
each
(
function
()
{
if
(
this
.
hasAttribute
(
'
type
'
))
{
if
(
this
.
getAttribute
(
'
type
'
)
===
lowerCaseType
)
{
return
true
;
}
else
{
isOfType
=
false
;
return
false
;
}
}
else
{
// <select> is not an attribute value, obviously, so check for nodename
if
(
this
.
nodeName
.
toLowerCase
()
===
lowerCaseType
)
{
return
true
;
}
else
if
(
lowerCaseType
===
'
text
'
)
{
return
true
;
}
else
{
isOfType
=
false
;
return
false
;
}
}
});
return
isOfType
;
};
})(
QfqNS
.
Element
);
\ No newline at end of file
javascript/src/Element/FormGroup.js
View file @
e4eaa1fb
...
...
@@ -13,6 +13,17 @@ if (!QfqNS.Element) {
(
function
(
n
)
{
'
use strict
'
;
/**
* Form Group represents a `<input>/<select>` element including the label and help block.
*
* It is not meant to be used directly. Use the specialized objects instead.
*
* @param $enclosedElement {jQuery} a jQuery object contained in the Form Group. It used to find the enclosing
* HTML element having the `.form-group` class assigned.
*
*
* @constructor
*/
n
.
FormGroup
=
function
(
$enclosedElement
)
{
if
(
!
$enclosedElement
||
$enclosedElement
.
length
===
0
)
{
throw
new
Error
(
"
No enclosed element
"
);
...
...
@@ -24,6 +35,33 @@ if (!QfqNS.Element) {
this
.
$helpBlock
=
this
.
$formGroup
.
find
(
"
.help-block
"
);
};
n
.
FormGroup
.
prototype
.
isType
=
function
(
type
)
{
var
lowerCaseType
=
type
.
toLowerCase
();
var
isOfType
=
true
;
this
.
$element
.
each
(
function
()
{
if
(
this
.
hasAttribute
(
'
type
'
))
{
if
(
this
.
getAttribute
(
'
type
'
)
===
lowerCaseType
)
{
return
true
;
}
else
{
isOfType
=
false
;
return
false
;
}
}
else
{
// <select> is not an attribute value, obviously, so check for nodename
if
(
this
.
nodeName
.
toLowerCase
()
===
lowerCaseType
)
{
return
true
;
}
else
if
(
lowerCaseType
===
'
text
'
)
{
return
true
;
}
else
{
isOfType
=
false
;
return
false
;
}
}
});
return
isOfType
;
};
/**
*
* @param $enclosedElement
...
...
@@ -58,7 +96,55 @@ if (!QfqNS.Element) {
};
n
.
FormGroup
.
prototype
.
setReadOnly
=
function
(
readonly
)
{
this
.
$element
.
propr
(
'
readonly
'
,
readonly
);
this
.
$element
.
prop
(
'
readonly
'
,
readonly
);
this
.
handleReadOnlyEmulationIfRequired
(
readonly
);
};
/**
* @private
* @param readonlyState
*/
n
.
FormGroup
.
prototype
.
handleReadOnlyEmulationIfRequired
=
function
(
readonlyState
)
{
if
(
!
this
.
readOnlyEmulationRequired
())
{
return
;
}
if
(
readonlyState
)
{
// In case we're called with readonlyState===true twice in a row, make sure only one handler will be
// active at a time
this
.
$element
.
off
(
'
click
'
,
this
.
readOnlyHandler
);
this
.
$element
.
on
(
'
click
'
,
this
.
readOnlyHandler
);
}
else
{
this
.
$element
.
off
(
'
click
'
,
this
.
readOnlyHandler
);
}
};
n
.
FormGroup
.
prototype
.
readOnlyEmulationRequired
=
function
()
{
// Keep this at top, since select does not feature the type attribute.
if
(
n
.
readOnlyIgnored
.
indexOf
(
this
.
$element
[
0
].
nodeName
.
toLowerCase
()))
{
return
true
;
}
if
(
!
this
.
$element
[
0
].
hasAttribute
(
'
type
'
))
{
// if there is no type attribute, browsers default to text, which is `properly implements` read only.
return
false
;
}
if
(
n
.
readOnlyIgnored
.
indexOf
(
this
.
$element
[
0
].
getAttribute
(
'
type
'
).
toLowerCase
()))
{
return
true
;
}
return
false
;
};
/**
* Read Only click handler.
*
* Since the readonly attribute does not work as expected on certain input types, emulate read only
*/
n
.
FormGroup
.
prototype
.
readOnlyHandler
=
function
()
{
return
false
;
};
...
...
javascript/src/Element/NameSpaceFunctions.js
0 → 100644
View file @
e4eaa1fb
/**
* @author Rafael Ostertag <rafael.ostertag@math.uzh.ch>
*/
/* global $ */
if
(
!
QfqNS
)
{
var
QfqNS
=
{};
}
if
(
!
QfqNS
.
Element
)
{
QfqNS
.
Element
=
{};
}
(
function
(
n
)
{
'
use strict
'
;
n
.
getElement
=
function
(
name
)
{
var
$element
=
$
(
'
[name=
'
+
name
+
'
]
'
);
if
(
$element
.
length
===
0
)
{
throw
Error
(
'
No element with name "
'
+
name
+
'
" found.
'
);
}
if
(
$element
[
0
].
nodeName
.
toLowerCase
()
===
"
select
"
)
{
return
new
n
.
Select
(
$element
);
}
if
(
!
$element
[
0
].
hasAttribute
(
'
type
'
))
{
return
new
n
.
Text
(
$element
);
}
var
type
=
$element
[
0
].
getAttribute
(
'
type
'
).
toLowerCase
();
switch
(
type
)
{
case
'
checkbox
'
:
return
new
n
.
Checkbox
(
$element
);
case
'
radio
'
:
return
new
n
.
Radio
(
$element
);
case
'
text
'
:
return
new
n
.
Text
(
$element
);
default
:
throw
new
Error
(
"
Don't know how to handle <input> of type '
"
+
type
+
"
'
"
);
}
};
})(
QfqNS
.
Element
);
\ No newline at end of file
javascript/src/Element/Radio.js
View file @
e4eaa1fb
...
...
@@ -20,23 +20,23 @@ if (!QfqNS.Element) {
* @constructor
*/
function
Radio
(
$element
)
{
n
.
Element
.
call
(
this
,
$element
);
n
.
FormGroup
.
call
(
this
,
$element
);
if
(
!
this
.
isType
(
"
radio
"
))
{
throw
new
Error
(
"
$element is not of type 'radio'
"
);
}
}
Radio
.
prototype
=
Object
.
create
(
n
.
Element
.
prototype
);
Radio
.
prototype
=
Object
.
create
(
n
.
FormGroup
.
prototype
);
Radio
.
prototype
.
constructor
=
Radio
;
Radio
.
prototype
.
setValue
=
function
(
val
)
{
this
.
formGroup
.
$element
.
prop
(
'
checked
'
,
false
);
this
.
formGroup
.
$element
.
filter
(
'
[value=
'
+
val
+
"
]
"
).
prop
(
'
checked
'
,
true
);
this
.
$element
.
prop
(
'
checked
'
,
false
);
this
.
$element
.
filter
(
'
[value=
'
+
val
+
"
]
"
).
prop
(
'
checked
'
,
true
);
};
Radio
.
prototype
.
getValue
=
function
()
{
return
this
.
formGroup
.
$element
.
filter
(
'
:checked
'
).
val
();
return
this
.
$element
.
filter
(
'
:checked
'
).
val
();
};
n
.
Radio
=
Radio
;
...
...
javascript/src/Element/Select.js
View file @
e4eaa1fb
...
...
@@ -22,14 +22,14 @@ if (!QfqNS.Element) {
* @constructor
*/
function
Select
(
$element
)
{
n
.
Element
.
call
(
this
,
$element
);
n
.
FormGroup
.
call
(
this
,
$element
);
if
(
!
this
.
isType
(
"
select
"
))
{
throw
new
Error
(
"
$element is not of type 'select'
"
);
}
}
Select
.
prototype
=
Object
.
create
(
n
.
Element
.
prototype
);
Select
.
prototype
=
Object
.
create
(
n
.
FormGroup
.
prototype
);
Select
.
prototype
.
constructor
=
Select
;
/**
...
...
@@ -39,22 +39,22 @@ if (!QfqNS.Element) {
* array of objects, `<select>` will have its `<option>` tags set correspondingly.
*/
Select
.
prototype
.
setValue
=
function
(
val
)
{
if
(
typeof
(
val
)
in
[
'
string
'
,
'
number
'
])
{
if
([
'
string
'
,
'
number
'
]
.
indexOf
(
typeof
(
val
))
!==
-
1
)
{
this
.
setSelection
(
val
);
}
else
if
(
Array
.
isArray
(
val
))
{
this
.
formGroup
.
$element
.
empty
();
this
.
$element
.
empty
();
// Fill array with new <select> elements first and add it to the dom in one step, instead of appending
// each '<select>' separately.
var
selectArray
;
var
selectArray
=
[]
;
val
.
forEach
(
function
(
selectObj
)
{
var
$option
=
$
(
'
<option>
'
)
.
a
ddAttribute
(
'
value
'
,
selectObj
.
value
?
selectObj
.
value
:
selectObj
.
text
)
.
a
ttr
(
'
value
'
,
selectObj
.
value
?
selectObj
.
value
:
selectObj
.
text
)
.
prop
(
'
selected
'
,
selectObj
.
selected
?
selectObj
.
selected
:
false
)
.
append
(
selectObj
.
text
);
selectArray
.
append
(
$option
);
selectArray
.
push
(
$option
);
});
this
.
formGroup
.
$element
.
append
(
selectArray
);
this
.
$element
.
append
(
selectArray
);
}
else
{
throw
Error
(
'
Unsupported type of argument in Select.setValue: "
'
+
typeof
(
val
)
+
'
". Expected either
'
+
'
"string" or "array"
'
);
...
...
@@ -72,11 +72,11 @@ if (!QfqNS.Element) {
// First, see if we find an <option> tag having an attribute 'value' matching val. If that doesn't work,
// fall back to comparing text content of <option> tags.
var
$selectionByValue
=
this
.
formGroup
.
$element
.
find
(
'
option[value=
'
+
val
);
var
$selectionByValue
=
this
.
$element
.
find
(
'
option[value=
'
+
val
+
'
]
'
);
if
(
$selectionByValue
.
length
>
0
)
{
$selectionByValue
.
prop
(
'
selected
'
,
true
);
}
else
{
this
.
formGroup
.
$element
.
find
(
'
option
'
).
each
(
function
()
{
this
.
$element
.
find
(
'
option
'
).
each
(
function
()
{
var
$element
=
$
(
this
);
if
(
$element
.
text
()
===
val
)
{
$element
.
prop
(
'
selected
'
,
true
);
...
...
@@ -91,14 +91,14 @@ if (!QfqNS.Element) {
* @private
*/
Select
.
prototype
.
clearSelection
=
function
()
{
this
.
formGroup
.
$element
.
find
(
'
:selected
'
).
each
(
function
()
{
this
.
$element
.
find
(
'
:selected
'
).
each
(
function
()
{
$
(
this
).
prop
(
'
selected
'
,
false
);
});
};
Select
.
prototype
.
getValue
=
function
()
{
var
returnValue
=
[];
this
.
formGroup
.
$element
.
find
(
'
:selected
'
).
each
(
this
.
$element
.
find
(
'
:selected
'
).
each
(
function
()
{
if
(
this
.
hasAttribute
(
'
value
'
))
{
returnValue
.
push
(
this
.
getAttribute
(
'
value
'
));
...
...
javascript/src/Element/Text.js
View file @
e4eaa1fb
...
...
@@ -19,25 +19,25 @@ if (!QfqNS.Element) {
* @param $element
* @constructor
*/
function
Inpu
t
(
$element
)
{
n
.
Element
.
call
(
this
,
$element
);
function
Tex
t
(
$element
)
{
n
.
FormGroup
.
call
(
this
,
$element
);
if
(
!
this
.
isType
(
"
text
"
))
{
throw
new
Error
(
"
$element is not of type 'text'
"
);
}
}
Inpu
t
.
prototype
=
Object
.
create
(
n
.
Element
.
prototype
);
Inpu
t
.
prototype
.
constructor
=
Inpu
t
;
Tex
t
.
prototype
=
Object
.
create
(
n
.
FormGroup
.
prototype
);
Tex
t
.
prototype
.
constructor
=
Tex
t
;
Inpu
t
.
prototype
.
setValue
=
function
(
val
)
{
this
.
formGroup
.
$element
.
val
(
val
);
Tex
t
.
prototype
.
setValue
=
function
(
val
)
{
this
.
$element
.
val
(
val
);
};
Inpu
t
.
prototype
.
getValue
=
function
()
{
return
this
.
formGroup
.
$element
.
val
();
Tex
t
.
prototype
.
getValue
=
function
()
{
return
this
.
$element
.
val
();
};
n
.
Input
=
Inpu
t
;
n
.
Text
=
Tex
t
;
})(
QfqNS
.
Element
);
\ No newline at end of file
javascript/src/Element/data.js
View file @
e4eaa1fb
...
...
@@ -45,4 +45,17 @@ if (!QfqNS.Element) {
'
color
'
];
/*
* See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input for input types ignoring the readonly
* attribute.
*/
n
.
readOnlyIgnored
=
[
'
hidden
'
,
'
range
'
,
'
checkbox
'
,
'
radio
'
,
'
file
'
,
'
select
'
];
})(
QfqNS
.
Element
);
\ No newline at end of file
javascript/src/Form.js
View file @
e4eaa1fb
...
...
@@ -74,6 +74,10 @@ if (!QfqNS) {
.
fail
(
this
.
submitFailureHandler
.
bind
(
this
));
};
n
.
Form
.
prototype
.
serialize
=
function
()
{
return
this
.
$form
.
serialize
();
};
/**
*
* @param data
...
...
javascript/src/QfqForm.js
View file @
e4eaa1fb
...
...
@@ -11,10 +11,11 @@ if (!QfqNS) {
(
function
(
n
)
{
'
use strict
'
;
n
.
QfqForm
=
function
(
formId
,
submitTo
,
deleteUrl
)
{
n
.
QfqForm
=
function
(
formId
,
submitTo
,
deleteUrl
,
dataRefreshUrl
)
{
this
.
formId
=
formId
;
this
.
submitTo
=
submitTo
;
this
.
deleteUrl
=
deleteUrl
;
this
.
dataRefreshUrl
=
dataRefreshUrl
;
this
.
form
=
new
n
.
Form
(
this
.
formId
);
this
.
bsTabs
=
null
;
this
.
lastButtonPress
=
null
;
...
...
@@ -31,6 +32,8 @@ if (!QfqNS) {
this
.
getCloseButton
().
click
(
this
.
handleCloseClick
.
bind
(
this
));
this
.
getNewButton
().
click
(
this
.
handleNewClick
.
bind
(
this
));