2011-08-07 15:43:46 +02:00
/ * *
2013-04-13 21:00:13 +02:00
* EGroupware eTemplate2 - JS Textbox object
2011-08-07 15:43:46 +02:00
*
* @ license http : //opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @ package etemplate
* @ subpackage api
* @ link http : //www.egroupware.org
* @ author Andreas Stöckel
* @ copyright Stylite 2011
* @ version $Id$
* /
"use strict" ;
/ * e g w : u s e s
jquery . jquery ;
2011-08-24 12:18:07 +02:00
et2 _core _inputWidget ;
et2 _core _valueWidget ;
2011-08-07 15:43:46 +02:00
* /
/ * *
* Class which implements the "textbox" XET - Tag
2014-01-29 16:55:18 +01:00
*
2013-04-13 21:00:13 +02:00
* @ augments et2 _inputWidget
2014-01-29 16:55:18 +01:00
* /
2014-12-04 17:38:34 +01:00
var et2 _textbox = et2 _inputWidget . extend ( [ et2 _IResizeable ] ,
2013-04-13 21:00:13 +02:00
{
2011-08-10 16:36:31 +02:00
attributes : {
"multiline" : {
"name" : "multiline" ,
"type" : "boolean" ,
"default" : false ,
"description" : "If true, the textbox is a multiline edit field."
2011-08-16 19:02:09 +02:00
} ,
"size" : {
"name" : "Size" ,
"type" : "integer" ,
"default" : et2 _no _init ,
"description" : "Field width"
2011-08-18 00:56:49 +02:00
} ,
2012-05-08 22:27:38 +02:00
"maxlength" : {
2012-03-27 01:27:53 +02:00
"name" : "Maximum length" ,
"type" : "integer" ,
"default" : et2 _no _init ,
"description" : "Maximum number of characters allowed"
} ,
2011-08-26 01:39:34 +02:00
"blur" : {
"name" : "Placeholder" ,
"type" : "string" ,
"default" : "" ,
"description" : "This text get displayed if an input-field is empty and does not have the input-focus (blur). It can be used to show a default value or a kind of help-text."
} ,
2011-08-18 00:56:49 +02:00
// These for multi-line
"rows" : {
"name" : "Rows" ,
"type" : "integer" ,
2011-08-19 18:39:28 +02:00
"default" : - 1 ,
2011-08-18 00:56:49 +02:00
"description" : "Multiline field height - better to use CSS"
} ,
"cols" : {
"name" : "Size" ,
"type" : "integer" ,
2011-08-19 18:39:28 +02:00
"default" : - 1 ,
2011-08-18 00:56:49 +02:00
"description" : "Multiline field width - better to use CSS"
2014-06-05 17:47:23 +02:00
} ,
"validator" : {
"name" : "Validator" ,
"type" : "string" ,
"default" : et2 _no _init ,
"description" : "Perl regular expression eg. '/^[0-9][a-f]{4}$/i'"
2014-08-21 15:06:17 +02:00
} ,
"autocomplete" : {
"name" : "Autocomplete" ,
"type" : "string" ,
"default" : "" ,
2015-06-03 11:05:11 +02:00
"description" : "Weither or not browser should autocomplete that field: 'on', 'off', 'default' (use attribute from form). Default value for type password is set to off."
2015-03-19 22:21:03 +01:00
} ,
onkeypress : {
name : "onKeypress" ,
type : "js" ,
default : et2 _no _init ,
description : "JS code or app.$app.$method called when key is pressed, return false cancels it."
2011-08-26 11:58:25 +02:00
}
2011-08-10 16:36:31 +02:00
} ,
2011-08-07 15:43:46 +02:00
2014-06-05 17:47:23 +02:00
legacyOptions : [ "size" , "maxlength" , "validator" ] ,
2012-03-27 01:27:53 +02:00
2013-04-13 21:00:13 +02:00
/ * *
* Constructor
2014-01-29 16:55:18 +01:00
*
2013-04-13 21:00:13 +02:00
* @ memberOf et2 _textbox
* /
2011-08-24 12:05:52 +02:00
init : function ( ) {
2011-08-07 15:43:46 +02:00
this . _super . apply ( this , arguments ) ;
2011-08-10 16:36:31 +02:00
this . input = null ;
this . createInputWidget ( ) ;
2011-08-07 15:43:46 +02:00
} ,
2011-08-10 16:36:31 +02:00
createInputWidget : function ( ) {
2011-08-19 18:00:44 +02:00
if ( this . options . multiline || this . options . rows > 1 || this . options . cols > 1 )
2011-08-07 15:43:46 +02:00
{
2011-08-19 18:39:28 +02:00
this . input = $j ( document . createElement ( "textarea" ) ) ;
if ( this . options . rows > 0 )
{
this . input . attr ( "rows" , this . options . rows ) ;
}
if ( this . options . cols > 0 )
{
this . input . attr ( "cols" , this . options . cols ) ;
}
2011-08-07 15:43:46 +02:00
}
2011-08-10 16:36:31 +02:00
else
{
this . input = $j ( document . createElement ( "input" ) ) ;
2014-12-05 09:59:51 +01:00
switch ( this . options . type )
{
case "passwd" :
this . input . attr ( "type" , "password" ) ;
2015-06-03 11:05:11 +02:00
// Make autocomplete default value off for password field
if ( this . options . autocomplete === "" ) this . options . autocomplete = "off" ;
2014-12-05 09:59:51 +01:00
break ;
case "hidden" :
this . input . attr ( "type" , "hidden" ) ;
break ;
2012-06-26 22:37:58 +02:00
}
2014-08-21 15:06:17 +02:00
if ( this . options . autocomplete ) this . input . attr ( "autocomplete" , this . options . autocomplete ) ;
2011-08-10 16:36:31 +02:00
}
2011-09-27 02:16:00 +02:00
if ( this . options . size ) {
this . set _size ( this . options . size ) ;
2011-08-16 19:02:09 +02:00
}
2011-09-27 02:16:00 +02:00
if ( this . options . blur ) {
this . set _blur ( this . options . blur ) ;
2011-08-26 01:39:34 +02:00
}
2013-02-05 15:42:23 +01:00
if ( this . options . readonly ) {
this . set _readonly ( true ) ;
}
2011-08-10 16:36:31 +02:00
this . input . addClass ( "et2_textbox" ) ;
this . setDOMNode ( this . input [ 0 ] ) ;
2013-04-10 14:10:04 +02:00
if ( this . options . value )
{
this . set _value ( this . options . value ) ;
}
2015-03-19 22:21:03 +01:00
if ( this . options . onkeypress && typeof this . options . onkeypress == 'function' )
{
var self = this ;
this . input . keypress ( function ( _ev )
{
return self . options . onkeypress . call ( this , _ev , self ) ;
} ) ;
}
} ,
2016-02-16 11:14:02 +01:00
2015-06-03 16:07:15 +02:00
/ * *
* Override the parent set _id method to manuipulate the input DOM node
2016-02-16 11:14:02 +01:00
*
2015-06-03 16:07:15 +02:00
* @ param { type } _value
* @ returns { undefined }
* /
set _id : function ( _value )
{
this . _super . apply ( this , arguments ) ;
// Remove the name attribute inorder to affect autocomplete="off"
2016-02-16 11:14:02 +01:00
// for no password save. ATM seems all browsers ignore autocomplete for
2015-06-03 16:07:15 +02:00
// input field inside the form
if ( this . options . type === "passwd"
&& this . options . autocomplete === "off" ) this . input . removeAttr ( 'name' ) ;
} ,
2016-02-16 11:14:02 +01:00
2015-03-19 22:21:03 +01:00
destroy : function ( ) {
var node = this . getInputNode ( ) ;
if ( node ) $j ( node ) . unbind ( "keypress" ) ;
this . _super . apply ( this , arguments ) ;
2011-08-07 15:43:46 +02:00
} ,
2011-09-27 02:16:00 +02:00
getValue : function ( )
{
2015-01-30 17:59:31 +01:00
if ( this . options && this . options . blur && this . input . val ( ) == this . options . blur ) return "" ;
2011-09-27 02:16:00 +02:00
return this . _super . apply ( this , arguments ) ;
} ,
2014-06-05 17:47:23 +02:00
/ * *
* Clientside validation using regular expression in "validator" attribute
*
* @ param { array } _messages
* /
isValid : function ( _messages )
{
var ok = true ;
// Check input is valid
2015-03-17 23:00:54 +01:00
if ( this . options && this . options . validator && ! this . options . readonly && ! this . disabled )
2014-06-05 17:47:23 +02:00
{
if ( typeof this . options . validator == 'string' )
{
var parts = this . options . validator . split ( '/' ) ;
var flags = parts . pop ( ) ;
if ( parts . length < 2 || parts [ 0 ] !== '' )
{
_messages . push ( this . egw ( ) . lang ( "'%1' has an invalid format !!!" , this . options . validator ) ) ;
return false ; // show invalid expression
}
parts . shift ( ) ;
this . options . validator = new RegExp ( parts . join ( '/' ) , flags ) ;
}
var value = this . getValue ( ) ;
if ( ! ( ok = this . options . validator . test ( value ) ) )
{
_messages . push ( this . egw ( ) . lang ( "'%1' has an invalid format !!!" , value ) ) ;
}
}
return this . _super . apply ( this , arguments ) && ok ;
} ,
2011-08-18 00:56:49 +02:00
2011-08-16 19:02:09 +02:00
/ * *
* Set input widget size
* @ param _size Rather arbitrary size units , approximately characters
* /
set _size : function ( _size ) {
2014-12-02 23:37:15 +01:00
if ( this . options . multiline || this . options . rows > 1 || this . options . cols > 1 )
{
this . input . css ( 'width' , _size + "em" ) ;
}
else if ( typeof _size != 'undefined' && _size != this . input . attr ( "size" ) )
2011-08-16 19:02:09 +02:00
{
this . size = _size ;
this . input . attr ( "size" , this . size ) ;
}
2011-08-26 01:39:34 +02:00
} ,
2012-03-27 01:27:53 +02:00
/ * *
* Set maximum characters allowed
* @ param _size Max characters allowed
* /
2012-05-08 22:27:38 +02:00
set _maxlength : function ( _size ) {
2012-03-27 01:27:53 +02:00
if ( typeof _size != 'undefined' && _size != this . input . attr ( "maxlength" ) )
{
this . maxLength = _size ;
this . input . attr ( "maxLength" , this . maxLength ) ;
}
} ,
2013-02-05 15:42:23 +01:00
/ * *
2014-01-29 16:55:18 +01:00
* Set HTML readonly attribute .
2013-02-05 15:42:23 +01:00
* Do not confuse this with etemplate readonly , which would use et _textbox _ro instead
* @ param _readonly Boolean
* /
set _readonly : function ( _readonly ) {
this . input . attr ( "readonly" , _readonly ) ;
} ,
2014-01-29 16:55:18 +01:00
2011-08-26 01:39:34 +02:00
set _blur : function ( _value ) {
if ( _value ) {
2014-12-08 16:57:06 +01:00
this . input . attr ( "placeholder" , this . egw ( ) . lang ( _value ) + "" ) ; // HTML5
2011-08-26 01:39:34 +02:00
if ( ! this . input [ 0 ] . placeholder ) {
// Not HTML5
2014-12-08 16:57:06 +01:00
if ( this . input . val ( ) == "" ) this . input . val ( this . egw ( ) . lang ( this . options . blur ) ) ;
2011-08-26 01:39:34 +02:00
this . input . focus ( this , function ( e ) {
2014-12-08 16:57:06 +01:00
if ( e . data . input . val ( ) == e . data . egw ( ) . lang ( e . data . options . blur ) ) e . data . input . val ( "" ) ;
2011-08-26 01:39:34 +02:00
} ) . blur ( this , function ( e ) {
2014-12-08 16:57:06 +01:00
if ( e . data . input . val ( ) == "" ) e . data . input . val ( e . data . egw ( ) . lang ( e . data . options . blur ) ) ;
2011-08-26 01:39:34 +02:00
} ) ;
}
} else {
2014-10-14 17:58:37 +02:00
if ( ! this . getValue ( ) ) this . input . val ( '' ) ;
2011-08-26 01:39:34 +02:00
this . input . removeAttr ( "placeholder" ) ;
}
2014-10-14 17:58:37 +02:00
this . options . blur = _value ;
2014-12-04 17:38:34 +01:00
} ,
2014-12-05 09:59:51 +01:00
2015-09-09 00:23:54 +02:00
set _autocomplete : function ( _value ) {
this . options . autocomplete = _value ;
this . input . attr ( 'autocomplete' , _value ) ;
} ,
2016-02-16 11:14:02 +01:00
2014-12-04 17:38:34 +01:00
resize : function ( _height )
{
2014-12-05 18:29:41 +01:00
if ( _height && this . options . multiline )
2014-12-04 17:38:34 +01:00
{
// apply the ratio
2014-12-05 18:29:41 +01:00
_height = ( this . options . resize _ratio != '' ) ? _height * this . options . resize _ratio : _height ;
2015-05-28 16:40:33 +02:00
if ( _height != 0 )
{
this . input . height ( this . input . height ( ) + _height ) ;
// resize parent too, so mailvelope injected into parent inherits its height
this . input . parent ( ) . height ( this . input . parent ( ) . height ( ) + _height ) ;
}
2014-12-04 17:38:34 +01:00
}
2011-08-16 19:02:09 +02:00
}
2011-08-07 15:43:46 +02:00
} ) ;
2014-12-05 09:59:51 +01:00
et2 _register _widget ( et2 _textbox , [ "textbox" , "passwd" , "hidden" ] ) ;
2011-08-07 15:43:46 +02:00
2011-08-16 14:31:18 +02:00
/ * *
* et2 _textbox _ro is the dummy readonly implementation of the textbox .
2014-01-29 16:55:18 +01:00
*
2013-04-13 21:00:13 +02:00
* @ augments et2 _valueWidget
2011-08-16 14:31:18 +02:00
* /
2014-01-29 16:55:18 +01:00
var et2 _textbox _ro = et2 _valueWidget . extend ( [ et2 _IDetachedDOM ] ,
2013-04-13 21:00:13 +02:00
{
2011-08-16 14:31:18 +02:00
/ * *
* Ignore all more advanced attributes .
* /
attributes : {
"multiline" : {
"ignore" : true
2012-07-11 22:09:15 +02:00
} ,
2012-07-24 01:54:16 +02:00
"maxlength" : {
2013-06-17 23:22:32 +02:00
"ignore" : true
2012-07-24 01:54:16 +02:00
} ,
"onchange" : {
"ignore" : true
} ,
2012-07-11 22:09:15 +02:00
"rows" : {
"ignore" : true
} ,
2012-07-24 01:54:16 +02:00
"cols" : {
"ignore" : true
} ,
2012-07-11 22:09:15 +02:00
"size" : {
"ignore" : true
} ,
2013-06-26 22:50:10 +02:00
"needed" : {
2012-07-11 22:09:15 +02:00
"ignore" : true
2011-08-16 14:31:18 +02:00
}
} ,
2013-04-13 21:00:13 +02:00
/ * *
* Constructor
2014-01-29 16:55:18 +01:00
*
2013-04-13 21:00:13 +02:00
* @ memberOf et2 _textbox _ro
* /
2011-08-16 14:31:18 +02:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . value = "" ;
2013-10-08 09:46:44 +02:00
this . span = $j ( document . createElement ( "label" ) )
. addClass ( "et2_label" ) ;
this . value _span = $j ( document . createElement ( "span" ) )
. addClass ( "et2_textbox_ro" )
. appendTo ( this . span ) ;
2011-08-16 14:31:18 +02:00
this . setDOMNode ( this . span [ 0 ] ) ;
} ,
2013-10-08 10:14:24 +02:00
set _label : function ( label )
{
2013-10-08 09:46:44 +02:00
// Remove current label
this . span . contents ( )
. filter ( function ( ) { return this . nodeType == 3 ; } ) . remove ( ) ;
2014-01-29 16:55:18 +01:00
2013-10-08 09:46:44 +02:00
var parts = et2 _csvSplit ( label , 2 , "%s" ) ;
this . span . prepend ( parts [ 0 ] ) ;
this . span . append ( parts [ 1 ] ) ;
this . label = label ;
} ,
2013-10-08 10:14:24 +02:00
set _value : function ( _value )
{
2011-08-16 14:31:18 +02:00
this . value = _value ;
2013-06-25 19:48:48 +02:00
if ( ! _value )
{
_value = "" ;
}
2014-07-01 18:18:01 +02:00
if ( this . label != "" )
{
this . span . removeClass ( 'et2_label_empty' ) ;
}
else
{
this . span . addClass ( 'et2_label_empty' ) ;
}
2013-10-08 09:46:44 +02:00
this . value _span . text ( _value ) ;
2011-10-18 18:04:47 +02:00
} ,
/ * *
2013-04-12 11:38:12 +02:00
* Code for implementing et2 _IDetachedDOM
2014-01-29 16:55:18 +01:00
*
* @ param { array } _attrs array to add further attributes to
2013-04-12 11:38:12 +02:00
* /
getDetachedAttributes : function ( _attrs )
{
2013-10-08 09:46:44 +02:00
_attrs . push ( "value" , "label" ) ;
2013-04-12 11:38:12 +02:00
} ,
getDetachedNodes : function ( )
{
2013-10-08 09:46:44 +02:00
return [ this . span [ 0 ] , this . value _span [ 0 ] ] ;
2013-04-12 11:38:12 +02:00
} ,
setDetachedAttributes : function ( _nodes , _values )
{
2011-10-18 18:04:47 +02:00
this . span = jQuery ( _nodes [ 0 ] ) ;
2013-10-08 09:46:44 +02:00
this . value _span = jQuery ( _nodes [ 1 ] ) ;
if ( typeof _values [ "label" ] != 'undefined' )
{
this . set _label ( _values [ "label" ] ) ;
}
2011-10-18 18:04:47 +02:00
if ( typeof _values [ "value" ] != 'undefined' )
{
this . set _value ( _values [ "value" ] ) ;
}
2011-08-16 14:31:18 +02:00
}
} ) ;
2012-07-26 00:37:56 +02:00
et2 _register _widget ( et2 _textbox _ro , [ "textbox_ro" ] ) ;
2011-08-16 14:31:18 +02:00
2016-02-15 19:30:40 +01:00
/ * *
* et2 _searchbox is a widget which provides a collapsable input search
* with on searching indicator and clear handler regardless of any browser limitation .
2016-02-16 11:14:02 +01:00
*
2016-02-15 19:30:40 +01:00
* @ type type
* /
var et2 _searchbox = et2 _textbox . extend (
{
/ * *
* Ignore all more advanced attributes .
* /
attributes : { } ,
/ * *
* Constructor
*
* @ memberOf et2 _searchbox
* /
init : function ( ) {
this . value = "" ;
this . div = jQuery ( document . createElement ( 'div' ) )
. addClass ( 'et2_searchbox' ) ;
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
this . _super . apply ( this , arguments ) ;
this . setDOMNode ( this . div [ 0 ] ) ;
this . _createWidget ( ) ;
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
_createWidget : function ( )
{
var self = this ;
// search button indicator
2016-02-16 11:14:02 +01:00
this . button = et2 _createWidget ( 'button' , { image : 'search' , background _image : true /*class:"et2_button_with_image"*/ } , this ) ;
this . button . onclick = function ( ) {
2016-02-15 19:30:40 +01:00
self . _show _hide ( true ) ;
2016-02-16 11:14:02 +01:00
self . search . input . focus ( ) ;
2016-02-15 19:30:40 +01:00
} ;
this . div . prepend ( this . button . getDOMNode ( ) ) ;
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
// input field
this . search = et2 _createWidget ( 'textbox' , { "blur" : egw . lang ( "search" ) ,
onkeypress : function ( event ) {
if ( event . which == 13 )
{
event . preventDefault ( ) ;
self . getInstanceManager ( ) . autocomplete _fixer ( ) ;
// Use a timeout to make sure we get the autocomplete value,
// if one was chosen, instead of what was actually typed.
// Chrome doesn't need this, but FF does.
window . setTimeout ( function ( ) {
self . set _value ( self . search . input . val ( ) ) ;
self . change ( ) ;
} , 0 ) ;
}
} } , this ) ;
this . search . input . on ( {
keyup : function ( event )
{
if ( event . which == 27 ) // Escape
{
// Excape clears search
self . set _value ( '' ) ;
}
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
blur : function ( event ) {
self . _show _hide ( false ) ;
if ( self . _oldValue != self . get _value ( ) ) {
self . change ( ) ;
}
} ,
mousedown : function ( event ) {
if ( event . target . type == 'span' ) event . stopImmidatePropagation ( ) ;
}
} ) ;
this . div . append ( this . search . getDOMNode ( ) ) ;
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
// clear button implementation
this . clear = jQuery ( document . createElement ( 'span' ) )
. addClass ( 'ui-icon clear' )
. on ( 'mousedown' , function ( event ) {
event . preventDefault ( ) ;
} )
. on ( 'click' , function ( event ) {
if ( self . get _value ( ) ) {
self . search . input . val ( '' ) ;
self . search . input . focus ( ) ;
self . _show _hide ( true ) ;
if ( self . _oldValue ) self . change ( ) ;
}
else
{
self . _show _hide ( false ) ;
}
} )
. appendTo ( this . div ) ;
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
/ * *
2016-02-16 11:14:02 +01:00
* Show / hide search field
2016-02-15 19:30:40 +01:00
* @ param { boolean } _stat true means show and false means hide
* /
_show _hide : function ( _stat )
{
jQuery ( this . search . getDOMNode ( ) ) . toggleClass ( 'hide' , ! _stat ) ;
jQuery ( 'span.clear' , this . div ) . toggleClass ( 'hide' , ! _stat ) ;
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
/ * *
* toggle search button status based on value
* /
_searchToggleState : function ( )
{
if ( ! this . get _value ( ) )
{
jQuery ( this . button . getDOMNode ( ) ) . removeClass ( 'searched' ) ;
}
else
{
jQuery ( this . button . getDOMNode ( ) ) . addClass ( 'searched' ) ;
}
} ,
/ * *
* override change function in order to preset the toggle state
* /
change : function ( )
{
this . _searchToggleState ( ) ;
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
this . _super . apply ( this , arguments ) ;
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
get _value : function ( ) {
return this . search . input . val ( ) ;
} ,
2016-02-16 11:14:02 +01:00
2016-02-15 19:30:40 +01:00
/ * *
2016-02-16 11:14:02 +01:00
* override doLoadingFinished in order to set initial state
2016-02-15 19:30:40 +01:00
* /
doLoadingFinished : function ( )
{
this . _super . apply ( this , arguments ) ;
if ( ! this . get _value ( ) ) {
this . _show _hide ( false ) ;
}
else {
this . _searchToggleState ( ) ;
}
}
} ) ;
et2 _register _widget ( et2 _searchbox , [ "searchbox" ] ) ;