2013-08-06 12:50:22 +00:00
( function ( ) {
var instance = openerp ;
2012-04-17 12:09:49 +00:00
var _t = instance . web . _t ,
_lt = instance . web . _lt ;
var QWeb = instance . web . qweb ;
2011-08-18 17:43:22 +00:00
2012-04-09 23:36:15 +00:00
/** @namespace */
2012-04-17 12:09:49 +00:00
instance . web . form = { } ;
2011-03-30 14:00:48 +00:00
2012-05-02 09:15:48 +00:00
/ * *
* Interface implemented by the form view or any other object
* able to provide the features necessary for the fields to work .
2012-07-12 12:56:37 +00:00
*
2012-05-02 09:15:48 +00:00
* Properties :
* - display _invalid _fields : if true , all fields where is _valid ( ) return true should
* be displayed as invalid .
2012-09-28 10:23:50 +00:00
* - actual _mode : the current mode of the field manager . Can be "view" , "edit" or "create" .
2012-05-02 09:15:48 +00:00
* Events :
* - view _content _has _changed : when the values of the fields have changed . When
* this event is triggered all fields should reprocess their modifiers .
2012-09-24 16:30:21 +00:00
* - field _changed : < field _name > : when the value of a field change , an event is triggered
* named "field_changed:<field_name>" with < field _name > replaced by the name of the field .
* This event is not related to the on _change mechanism of OpenERP and is always called
* when the value of a field is setted or changed . This event is only triggered when the
* value of the field is syntactically valid , but it can be triggered when the value
* is sematically invalid ( ie , when a required field is false ) . It is possible that an event
* about a precise field is never triggered even if that field exists in the view , in that
* case the value of the field is assumed to be false .
2012-05-02 09:15:48 +00:00
* /
2012-05-02 09:18:47 +00:00
instance . web . form . FieldManagerMixin = {
2012-05-02 09:15:48 +00:00
/ * *
* Must return the asked field as in fields _get .
* /
2012-10-04 15:34:00 +00:00
get _field _desc : function ( field _name ) { } ,
2012-09-24 16:30:21 +00:00
/ * *
* Returns the current value of a field present in the view . See the get _value ( ) method
* method in FieldInterface for further information .
* /
get _field _value : function ( field _name ) { } ,
2012-09-25 15:59:45 +00:00
/ * *
Gives new values for the fields contained in the view . The new values could not be setted
right after the call to this method . Setting new values can trigger on _changes .
@ param ( dict ) values A dictonnary with key = field name and value = new value .
@ return ( Deferred ) Is resolved after all the values are setted .
* /
set _values : function ( values ) { } ,
2012-10-04 14:33:37 +00:00
/ * *
Computes an OpenERP domain .
@ param ( list ) expression An OpenERP domain .
@ return ( boolean ) The computed value of the domain .
* /
compute _domain : function ( expression ) { } ,
2012-10-04 14:52:06 +00:00
/ * *
Builds an evaluation context for the resolution of the fields ' contexts . Please note
the field are only supposed to use this context to evualuate their own , they should not
extend it .
@ return ( CompoundContext ) An OpenERP context .
* /
build _eval _context : function ( ) { } ,
2012-05-02 09:15:48 +00:00
} ;
2012-04-17 12:09:49 +00:00
instance . web . views . add ( 'form' , 'instance.web.FormView' ) ;
2012-07-25 14:13:33 +00:00
/ * *
* Properties :
* - actual _mode : always "view" , "edit" or "create" . Read - only property . Determines
2012-07-26 10:27:19 +00:00
* the mode used by the view .
2012-07-25 14:13:33 +00:00
* /
2012-06-21 23:56:41 +00:00
instance . web . FormView = instance . web . View . extend ( instance . web . form . FieldManagerMixin , {
2011-04-01 10:45:00 +00:00
/ * *
* Indicates that this view is not searchable , and thus that no search
* view should be displayed ( if there is one active ) .
* /
searchable : false ,
2012-03-12 15:34:52 +00:00
template : "FormView" ,
2011-12-16 13:00:00 +00:00
display _name : _lt ( 'Form' ) ,
2012-04-05 16:03:15 +00:00
view _type : "form" ,
2011-04-01 10:45:00 +00:00
/ * *
2012-04-17 12:09:49 +00:00
* @ constructs instance . web . FormView
* @ extends instance . web . View
2011-10-19 12:50:34 +00:00
*
2012-04-17 12:09:49 +00:00
* @ param { instance . web . Session } session the current openerp session
* @ param { instance . web . DataSet } dataset the dataset this view will work with
2011-04-01 10:45:00 +00:00
* @ param { String } view _id the identifier of the OpenERP view object
2011-12-21 17:16:02 +00:00
* @ param { Object } options
* - resize _textareas : [ true | false | max _height ]
2011-06-03 09:43:02 +00:00
*
2012-04-17 12:09:49 +00:00
* @ property { instance . web . Registry } registry = instance . web . form . widgets widgets registry for this form view instance
2011-04-01 10:45:00 +00:00
* /
2011-09-14 14:30:28 +00:00
init : function ( parent , dataset , view _id , options ) {
2012-07-25 14:18:32 +00:00
var self = this ;
2011-09-14 14:30:28 +00:00
this . _super ( parent ) ;
2013-04-17 13:34:38 +00:00
this . ViewManager = parent ;
2011-08-08 17:32:30 +00:00
this . set _default _options ( options ) ;
2011-03-30 14:00:48 +00:00
this . dataset = dataset ;
this . model = dataset . model ;
2011-09-20 10:08:23 +00:00
this . view _id = view _id || false ;
2011-04-04 15:06:19 +00:00
this . fields _view = { } ;
2011-03-30 14:00:48 +00:00
this . fields = { } ;
2011-12-01 15:50:29 +00:00
this . fields _order = [ ] ;
2011-04-05 15:14:40 +00:00
this . datarecord = { } ;
2011-06-20 18:25:49 +00:00
this . default _focus _field = null ;
this . default _focus _button = null ;
2012-04-17 12:09:49 +00:00
this . fields _registry = instance . web . form . widgets ;
this . tags _registry = instance . web . form . tags ;
2012-09-28 10:08:44 +00:00
this . widgets _registry = instance . web . form . custom _widgets ;
2011-06-17 14:19:45 +00:00
this . has _been _loaded = $ . Deferred ( ) ;
2011-08-24 15:13:57 +00:00
this . translatable _fields = [ ] ;
2011-12-05 13:50:37 +00:00
_ . defaults ( this . options , {
2012-04-10 10:07:41 +00:00
"not_interactible_on_create" : false ,
"initial_mode" : "view" ,
2012-08-01 16:12:04 +00:00
"disable_autofocus" : false ,
2012-10-16 12:56:27 +00:00
"footer_to_buttons" : false ,
2011-12-05 13:50:37 +00:00
} ) ;
2012-01-10 14:41:13 +00:00
this . is _initialized = $ . Deferred ( ) ;
this . mutating _mutex = new $ . Mutex ( ) ;
2012-10-31 15:39:46 +00:00
this . on _change _list = [ ] ;
this . save _list = [ ] ;
2012-01-10 14:44:20 +00:00
this . reload _mutex = new $ . Mutex ( ) ;
2012-06-20 11:15:27 +00:00
this . _ _clicked _inside = false ;
this . _ _blur _timeout = null ;
2012-07-20 14:13:04 +00:00
this . rendering _engine = new instance . web . form . FormRenderingEngine ( this ) ;
2012-07-26 09:52:31 +00:00
self . set ( { actual _mode : self . options . initial _mode } ) ;
2012-10-30 14:06:30 +00:00
this . has _been _loaded . done ( function ( ) {
2012-07-25 14:31:50 +00:00
self . on ( "change:actual_mode" , self , self . check _actual _mode ) ;
2012-07-26 09:52:31 +00:00
self . check _actual _mode ( ) ;
2012-07-26 11:57:42 +00:00
self . on ( "change:actual_mode" , self , self . init _pager ) ;
self . init _pager ( ) ;
2012-07-25 14:18:32 +00:00
} ) ;
2012-10-10 10:02:33 +00:00
self . on ( "load_record" , self , self . load _record ) ;
2012-09-06 13:26:02 +00:00
instance . web . bus . on ( 'clear_uncommitted_changes' , this , function ( e ) {
2012-09-05 12:35:32 +00:00
if ( ! this . can _be _discarded ( ) ) {
e . preventDefault ( ) ;
}
} ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-12-13 14:09:14 +00:00
view _loading : function ( r ) {
return this . load _form ( r ) ;
} ,
2012-02-21 16:29:12 +00:00
destroy : function ( ) {
2012-03-19 17:03:36 +00:00
_ . each ( this . get _widgets ( ) , function ( w ) {
2012-06-25 14:40:13 +00:00
w . off ( 'focused blurred' ) ;
2012-02-21 16:29:12 +00:00
w . destroy ( ) ;
2011-07-11 16:15:46 +00:00
} ) ;
2012-08-24 18:27:07 +00:00
if ( this . $el ) {
this . $el . off ( '.formBlur' ) ;
2012-07-26 14:44:20 +00:00
}
2011-09-28 15:16:13 +00:00
this . _super ( ) ;
2011-07-11 16:15:46 +00:00
} ,
2012-10-18 11:49:50 +00:00
load _form : function ( data ) {
2011-03-30 14:00:48 +00:00
var self = this ;
2012-02-07 12:05:39 +00:00
if ( ! data ) {
2012-11-29 00:22:00 +00:00
throw new Error ( _t ( "No data provided." ) ) ;
2012-02-07 13:01:25 +00:00
}
2012-03-12 15:34:52 +00:00
if ( this . arch ) {
2012-10-18 11:49:50 +00:00
throw "Form view does not support multiple calls to load_form" ;
2011-09-20 11:21:47 +00:00
}
2012-02-07 12:05:39 +00:00
this . fields _order = [ ] ;
this . fields _view = data ;
2012-04-10 12:21:10 +00:00
this . rendering _engine . set _fields _registry ( this . fields _registry ) ;
this . rendering _engine . set _tags _registry ( this . tags _registry ) ;
2012-09-28 10:08:44 +00:00
this . rendering _engine . set _widgets _registry ( this . widgets _registry ) ;
2012-10-11 14:47:05 +00:00
this . rendering _engine . set _fields _view ( data ) ;
var $dest = this . $el . hasClass ( "oe_form_container" ) ? this . $el : this . $el . find ( '.oe_form_container' ) ;
2012-10-11 14:51:48 +00:00
this . rendering _engine . render _to ( $dest ) ;
2012-03-12 15:34:52 +00:00
2012-08-24 18:27:07 +00:00
this . $el . on ( 'mousedown.formBlur' , function ( ) {
2012-06-20 11:15:27 +00:00
self . _ _clicked _inside = true ;
} ) ;
2012-04-09 18:44:45 +00:00
2012-04-10 13:55:37 +00:00
this . $buttons = $ ( QWeb . render ( "FormView.buttons" , { 'widget' : self } ) ) ;
2012-04-10 07:59:14 +00:00
if ( this . options . $buttons ) {
this . $buttons . appendTo ( this . options . $buttons ) ;
} else {
2012-08-24 18:27:07 +00:00
this . $el . find ( '.oe_form_buttons' ) . replaceWith ( this . $buttons ) ;
2012-04-10 07:59:14 +00:00
}
2012-11-13 15:36:10 +00:00
this . $buttons . on ( 'click' , '.oe_form_button_create' ,
this . guard _active ( this . on _button _create ) ) ;
this . $buttons . on ( 'click' , '.oe_form_button_edit' ,
this . guard _active ( this . on _button _edit ) ) ;
this . $buttons . on ( 'click' , '.oe_form_button_save' ,
this . guard _active ( this . on _button _save ) ) ;
this . $buttons . on ( 'click' , '.oe_form_button_cancel' ,
this . guard _active ( this . on _button _cancel ) ) ;
2012-10-16 12:56:27 +00:00
if ( this . options . footer _to _buttons ) {
this . $el . find ( 'footer' ) . appendTo ( this . $buttons ) ;
}
2012-04-09 20:16:47 +00:00
2012-08-24 18:27:07 +00:00
this . $sidebar = this . options . $sidebar || this . $el . find ( '.oe_form_sidebar' ) ;
2012-04-18 14:24:39 +00:00
if ( ! this . sidebar && this . options . $sidebar ) {
2012-04-17 12:09:49 +00:00
this . sidebar = new instance . web . Sidebar ( this ) ;
2012-04-09 18:44:45 +00:00
this . sidebar . appendTo ( this . $sidebar ) ;
2012-08-31 15:37:58 +00:00
if ( this . fields _view . toolbar ) {
2012-04-17 13:32:42 +00:00
this . sidebar . add _toolbar ( this . fields _view . toolbar ) ;
}
2012-09-04 15:18:24 +00:00
this . sidebar . add _items ( 'other' , _ . compact ( [
self . is _action _enabled ( 'delete' ) && { label : _t ( 'Delete' ) , callback : self . on _button _delete } ,
2012-12-10 14:38:08 +00:00
self . is _action _enabled ( 'create' ) && { label : _t ( 'Duplicate' ) , callback : self . on _button _duplicate }
2012-09-04 15:18:24 +00:00
] ) ) ;
2011-07-26 21:00:05 +00:00
}
2012-07-26 00:23:18 +00:00
2012-08-08 07:38:21 +00:00
this . has _been _loaded . resolve ( ) ;
2012-07-26 00:23:18 +00:00
// Add bounce effect on button 'Edit' when click on readonly page view.
2013-02-15 07:36:01 +00:00
this . $el . find ( ".oe_form_group_row,.oe_form_field,label,h1,.oe_title,.oe_notebook_page, .oe_list_content" ) . on ( 'click' , function ( e ) {
2012-07-26 10:14:22 +00:00
if ( self . get ( "actual_mode" ) == "view" ) {
2012-07-26 00:23:18 +00:00
var $button = self . options . $buttons . find ( ".oe_form_button_edit" ) ;
2012-12-19 15:12:17 +00:00
$button . openerpBounce ( ) ;
2012-09-12 10:30:44 +00:00
e . stopPropagation ( ) ;
2012-09-19 12:39:57 +00:00
instance . web . bus . trigger ( 'click' , e ) ;
2012-07-26 00:23:18 +00:00
}
} ) ;
2012-09-21 09:37:47 +00:00
//bounce effect on red button when click on statusbar.
2013-06-17 16:28:27 +00:00
this . $el . find ( ".oe_form_field_status:not(.oe_form_status_clickable)" ) . on ( 'click' , function ( e ) {
if ( ( self . get ( "actual_mode" ) == "view" ) ) {
var $button = self . $el . find ( ".oe_highlight:not(.oe_form_invisible)" ) . css ( { 'float' : 'left' , 'clear' : 'none' } ) ;
2012-12-19 15:12:17 +00:00
$button . openerpBounce ( ) ;
2012-09-21 09:37:47 +00:00
e . stopPropagation ( ) ;
}
} ) ;
2012-10-18 11:49:50 +00:00
this . trigger ( 'form_view_loaded' , data ) ;
2012-04-05 16:03:15 +00:00
return $ . when ( ) ;
2011-03-30 14:00:48 +00:00
} ,
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
widgetFocused : function ( ) {
2012-06-20 11:15:27 +00:00
// Clear click flag if used to focus a widget
this . _ _clicked _inside = false ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
if ( this . _ _blur _timeout ) {
clearTimeout ( this . _ _blur _timeout ) ;
2012-06-20 11:15:27 +00:00
this . _ _blur _timeout = null ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
}
} ,
widgetBlurred : function ( ) {
2012-06-20 11:15:27 +00:00
if ( this . _ _clicked _inside ) {
// clicked in an other section of the form (than the currently
// focused widget) => just ignore the blurring entirely?
this . _ _clicked _inside = false ;
return ;
}
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
var self = this ;
// clear timeout, if any
this . widgetFocused ( ) ;
this . _ _blur _timeout = setTimeout ( function ( ) {
2012-06-25 14:40:13 +00:00
self . trigger ( 'blurred' ) ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
} , 0 ) ;
} ,
2012-02-01 15:44:42 +00:00
do _load _state : function ( state , warm ) {
2011-12-15 14:29:39 +00:00
if ( state . id && this . datarecord . id != state . id ) {
2013-02-25 16:12:36 +00:00
if ( this . dataset . get _id _index ( state . id ) === null ) {
2012-01-25 08:53:10 +00:00
this . dataset . ids . push ( state . id ) ;
2011-12-15 14:29:39 +00:00
}
2012-02-01 15:44:42 +00:00
this . dataset . select _id ( state . id ) ;
2013-02-05 17:05:56 +00:00
this . do _show ( { reload : warm } ) ;
2011-12-15 14:29:39 +00:00
}
2011-10-26 14:42:18 +00:00
} ,
2012-06-27 10:02:06 +00:00
/ * *
*
* @ param { Object } [ options ]
2012-08-16 09:38:18 +00:00
* @ param { Boolean } [ mode = undefined ] If specified , switch the form to specified mode . Can be "edit" or "view" .
2012-06-27 10:02:06 +00:00
* @ param { Boolean } [ reload = true ] whether the form should reload its content on show , or use the currently loaded record
* @ return { $ . Deferred }
* /
2012-06-07 16:08:01 +00:00
do _show : function ( options ) {
2012-01-04 17:01:18 +00:00
var self = this ;
2012-06-07 16:08:01 +00:00
options = options || { } ;
2012-04-09 19:35:09 +00:00
if ( this . sidebar ) {
2012-08-24 18:27:07 +00:00
this . sidebar . $el . show ( ) ;
2012-04-09 19:35:09 +00:00
}
2012-04-09 19:43:33 +00:00
if ( this . $buttons ) {
2012-04-10 07:59:14 +00:00
this . $buttons . show ( ) ;
2012-04-09 19:43:33 +00:00
}
2012-08-24 18:27:07 +00:00
this . $el . show ( ) . css ( {
2012-08-01 16:12:04 +00:00
opacity : '0' ,
filter : 'alpha(opacity = 0)'
} ) ;
2012-08-24 18:27:07 +00:00
this . $el . add ( this . $buttons ) . removeClass ( 'oe_form_dirty' ) ;
2012-06-27 10:02:06 +00:00
var shown = this . has _been _loaded ;
if ( options . reload !== false ) {
2012-10-30 14:06:30 +00:00
shown = shown . then ( function ( ) {
2012-06-27 10:02:06 +00:00
if ( self . dataset . index === null ) {
// null index means we should start a new record
return self . on _button _new ( ) ;
2012-06-07 16:08:01 +00:00
}
2012-07-31 14:03:09 +00:00
var fields = _ . keys ( self . fields _view . fields ) ;
fields . push ( 'display_name' ) ;
return self . dataset . read _index ( fields , {
context : { 'bin_size' : true , 'future_display_name' : true }
2012-10-30 14:06:30 +00:00
} ) . then ( function ( r ) {
2012-10-10 10:02:33 +00:00
self . trigger ( 'load_record' , r ) ;
} ) ;
2012-01-09 10:45:40 +00:00
} ) ;
2012-06-27 10:02:06 +00:00
}
2012-10-30 14:06:30 +00:00
return shown . then ( function ( ) {
2012-08-16 09:38:18 +00:00
self . _actualize _mode ( options . mode || self . options . initial _mode ) ;
2012-08-24 18:27:07 +00:00
self . $el . css ( {
2012-08-01 16:12:04 +00:00
opacity : '1' ,
filter : 'alpha(opacity = 100)'
} ) ;
2011-12-19 16:30:51 +00:00
} ) ;
2011-04-06 21:10:37 +00:00
} ,
do _hide : function ( ) {
2011-07-26 21:00:05 +00:00
if ( this . sidebar ) {
2012-08-24 18:27:07 +00:00
this . sidebar . $el . hide ( ) ;
2011-07-26 21:00:05 +00:00
}
2012-04-09 20:53:34 +00:00
if ( this . $buttons ) {
2012-04-10 07:59:14 +00:00
this . $buttons . hide ( ) ;
2012-04-09 20:53:34 +00:00
}
if ( this . $pager ) {
2012-04-10 11:26:56 +00:00
this . $pager . hide ( ) ;
2012-04-09 20:53:34 +00:00
}
2011-12-14 17:18:11 +00:00
this . _super ( ) ;
2011-04-06 21:10:37 +00:00
} ,
2012-10-10 10:02:33 +00:00
load _record : function ( record ) {
2012-07-31 14:03:09 +00:00
var self = this , set _values = [ ] ;
2011-06-23 15:55:09 +00:00
if ( ! record ) {
2012-07-05 08:04:50 +00:00
this . set ( { 'title' : undefined } ) ;
2012-11-29 00:22:00 +00:00
this . do _warn ( _t ( "Form" ) , _t ( "The record could not be found in the database." ) , true ) ;
2012-02-13 12:38:05 +00:00
return $ . Deferred ( ) . reject ( ) ;
2011-06-23 15:55:09 +00:00
}
this . datarecord = record ;
2012-07-26 09:56:53 +00:00
this . _actualize _mode ( ) ;
2012-11-29 00:22:00 +00:00
this . set ( { 'title' : record . id ? record . display _name : _t ( "New" ) } ) ;
2011-11-17 16:00:09 +00:00
_ ( this . fields ) . each ( function ( field , f ) {
2012-04-18 11:50:04 +00:00
field . _dirty _flag = false ;
2012-09-24 16:07:21 +00:00
field . _inhibit _on _change _flag = true ;
2011-11-17 16:00:09 +00:00
var result = field . set _value ( self . datarecord [ f ] || false ) ;
2012-09-24 16:07:21 +00:00
field . _inhibit _on _change _flag = false ;
2012-07-31 14:03:09 +00:00
set _values . push ( result ) ;
2011-11-17 16:00:09 +00:00
} ) ;
2012-10-30 14:06:30 +00:00
return $ . when . apply ( null , set _values ) . then ( function ( ) {
2011-11-17 12:43:19 +00:00
if ( ! record . id ) {
2011-12-01 15:50:29 +00:00
// New record: Second pass in order to trigger the onchanges
// respecting the fields order defined in the view
_ . each ( self . fields _order , function ( field _name ) {
if ( record [ field _name ] !== undefined ) {
var field = self . fields [ field _name ] ;
2012-04-18 11:50:04 +00:00
field . _dirty _flag = true ;
2011-11-17 12:43:19 +00:00
self . do _onchange ( field ) ;
}
2011-12-01 15:50:29 +00:00
} ) ;
2011-04-07 13:07:25 +00:00
}
2011-11-17 12:43:19 +00:00
self . on _form _changed ( ) ;
2012-10-11 16:09:02 +00:00
self . rendering _engine . init _fields ( ) ;
2012-01-10 14:41:13 +00:00
self . is _initialized . resolve ( ) ;
2013-07-25 10:07:49 +00:00
self . do _update _pager ( record . id === null || record . id === undefined ) ;
2011-11-17 12:43:19 +00:00
if ( self . sidebar ) {
2012-04-17 01:19:33 +00:00
self . sidebar . do _attachement _update ( self . dataset , self . datarecord . id ) ;
2011-11-17 12:43:19 +00:00
}
2011-12-14 16:09:58 +00:00
if ( record . id ) {
self . do _push _state ( { id : record . id } ) ;
2012-08-08 14:16:41 +00:00
} else {
self . do _push _state ( { } ) ;
2011-12-14 16:09:58 +00:00
}
2012-08-24 18:27:07 +00:00
self . $el . add ( self . $buttons ) . removeClass ( 'oe_form_dirty' ) ;
2012-08-01 16:12:04 +00:00
self . autofocus ( ) ;
2011-11-17 12:43:19 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-07-16 11:04:30 +00:00
/ * *
* Loads and sets up the default values for the model as the current
* record
*
* @ return { $ . Deferred }
* /
load _defaults : function ( ) {
2012-10-04 12:27:11 +00:00
var self = this ;
2012-07-16 11:04:30 +00:00
var keys = _ . keys ( this . fields _view . fields ) ;
if ( keys . length ) {
2012-10-30 14:06:30 +00:00
return this . dataset . default _get ( keys ) . then ( function ( r ) {
2012-10-10 10:02:33 +00:00
self . trigger ( 'load_record' , r ) ;
} ) ;
2012-07-16 11:04:30 +00:00
}
2012-10-10 10:02:33 +00:00
return self . trigger ( 'load_record' , { } ) ;
2012-07-16 11:04:30 +00:00
} ,
2012-02-15 10:34:05 +00:00
on _form _changed : function ( ) {
2012-03-26 14:41:29 +00:00
this . trigger ( "view_content_has_changed" ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-02-15 10:34:05 +00:00
do _notify _change : function ( ) {
2012-08-24 18:27:07 +00:00
this . $el . add ( this . $buttons ) . addClass ( 'oe_form_dirty' ) ;
2012-02-15 10:34:05 +00:00
} ,
2012-10-12 06:20:04 +00:00
execute _pager _action : function ( action ) {
2011-09-14 21:09:02 +00:00
if ( this . can _be _discarded ( ) ) {
switch ( action ) {
case 'first' :
this . dataset . index = 0 ;
break ;
case 'previous' :
this . dataset . previous ( ) ;
break ;
case 'next' :
this . dataset . next ( ) ;
break ;
case 'last' :
this . dataset . index = this . dataset . ids . length - 1 ;
break ;
}
this . reload ( ) ;
2012-10-12 08:49:00 +00:00
this . trigger ( 'pager_action_executed' ) ;
2011-03-30 14:00:48 +00:00
}
2011-04-06 21:10:37 +00:00
} ,
2012-07-26 11:57:42 +00:00
init _pager : function ( ) {
var self = this ;
if ( this . $pager )
this . $pager . remove ( ) ;
if ( this . get ( "actual_mode" ) === "create" )
return ;
2012-09-19 10:02:25 +00:00
this . $pager = $ ( QWeb . render ( "FormView.pager" , { 'widget' : self } ) ) . hide ( ) ;
2012-07-26 11:57:42 +00:00
if ( this . options . $pager ) {
this . $pager . appendTo ( this . options . $pager ) ;
} else {
2012-08-24 18:27:07 +00:00
this . $el . find ( '.oe_form_pager' ) . replaceWith ( this . $pager ) ;
2012-07-26 11:57:42 +00:00
}
this . $pager . on ( 'click' , 'a[data-pager-action]' , function ( ) {
var action = $ ( this ) . data ( 'pager-action' ) ;
2012-10-12 06:20:04 +00:00
self . execute _pager _action ( action ) ;
2012-07-26 11:57:42 +00:00
} ) ;
this . do _update _pager ( ) ;
} ,
2011-04-11 11:55:07 +00:00
do _update _pager : function ( hide _index ) {
2012-09-19 10:02:25 +00:00
this . $pager . toggle ( this . dataset . ids . length > 1 ) ;
if ( hide _index ) {
2012-09-18 10:12:47 +00:00
$ ( ".oe_form_pager_state" , this . $pager ) . html ( "" ) ;
} else {
2012-09-18 12:22:26 +00:00
$ ( ".oe_form_pager_state" , this . $pager ) . html ( _ . str . sprintf ( _t ( "%d / %d" ) , this . dataset . index + 1 , this . dataset . ids . length ) ) ;
2012-09-18 10:12:47 +00:00
}
2011-04-06 21:10:37 +00:00
} ,
2011-11-21 12:04:13 +00:00
parse _on _change : function ( on _change , widget ) {
var self = this ;
var onchange = _ . str . trim ( on _change ) ;
var call = onchange . match ( /^\s?(.*?)\((.*?)\)\s?$/ ) ;
if ( ! call ) {
2012-11-29 00:22:00 +00:00
throw new Error ( _ . str . sprintf ( _t ( "Wrong on change format: %s" ) , onchange ) ) ;
2011-11-21 12:04:13 +00:00
}
2011-11-21 12:45:32 +00:00
var method = call [ 1 ] ;
2011-11-21 12:28:45 +00:00
if ( ! _ . str . trim ( call [ 2 ] ) ) {
2013-07-25 10:33:01 +00:00
return { method : method , args : [ ] } ;
2011-11-21 12:28:45 +00:00
}
2011-11-21 12:04:13 +00:00
var argument _replacement = {
'False' : function ( ) { return false ; } ,
'True' : function ( ) { return true ; } ,
'None' : function ( ) { return null ; } ,
2012-11-27 13:34:35 +00:00
'context' : function ( ) {
return new instance . web . CompoundContext (
self . dataset . get _context ( ) ,
widget . build _context ( ) ? widget . build _context ( ) : { } ) ;
2011-11-21 12:04:13 +00:00
}
} ;
2012-11-27 13:34:35 +00:00
var parent _fields = null ;
2011-11-21 12:45:32 +00:00
var args = _ . map ( call [ 2 ] . split ( ',' ) , function ( a , i ) {
2011-11-21 12:04:13 +00:00
var field = _ . str . trim ( a ) ;
2011-11-21 12:41:45 +00:00
// literal constant or context
2011-11-21 12:04:13 +00:00
if ( field in argument _replacement ) {
2012-11-27 13:34:35 +00:00
return argument _replacement [ field ] ( ) ;
2011-11-21 12:41:45 +00:00
}
2011-11-22 12:43:53 +00:00
// literal number
if ( /^-?\d+(\.\d+)?$/ . test ( field ) ) {
return Number ( field ) ;
}
2011-11-21 12:41:45 +00:00
// form field
if ( self . fields [ field ] ) {
2012-04-17 14:32:27 +00:00
var value _ = self . fields [ field ] . get _value ( ) ;
2013-07-25 10:07:49 +00:00
return value _ === null || value _ === undefined ? false : value _ ;
2011-11-21 12:41:45 +00:00
}
// parent field
var splitted = field . split ( '.' ) ;
if ( splitted . length > 1 && _ . str . trim ( splitted [ 0 ] ) === "parent" && self . dataset . parent _view ) {
if ( parent _fields === null ) {
2012-11-08 10:38:56 +00:00
parent _fields = self . dataset . parent _view . get _fields _values ( ) ;
2011-11-21 12:04:13 +00:00
}
2011-11-21 12:41:45 +00:00
var p _val = parent _fields [ _ . str . trim ( splitted [ 1 ] ) ] ;
if ( p _val !== undefined ) {
2013-07-25 10:07:49 +00:00
return p _val === null || p _val === undefined ? false : p _val ;
2011-11-21 12:41:45 +00:00
}
}
// string literal
var first _char = field [ 0 ] , last _char = field [ field . length - 1 ] ;
if ( ( first _char === '"' && last _char === '"' )
|| ( first _char === "'" && last _char === "'" ) ) {
2011-11-21 12:45:32 +00:00
return field . slice ( 1 , - 1 ) ;
2011-11-21 12:04:13 +00:00
}
2011-11-21 12:41:45 +00:00
2011-11-21 12:05:09 +00:00
throw new Error ( "Could not get field with name '" + field +
"' for onchange '" + onchange + "'" ) ;
2011-11-21 12:04:13 +00:00
} ) ;
return {
method : method ,
2012-11-27 13:34:35 +00:00
args : args
2011-11-21 12:04:13 +00:00
} ;
} ,
2011-04-07 17:09:29 +00:00
do _onchange : function ( widget , processed ) {
2011-10-12 15:08:30 +00:00
var self = this ;
2012-10-31 15:39:46 +00:00
this . on _change _list = [ { widget : widget , processed : processed } ] . concat ( this . on _change _list ) ;
return this . _process _operations ( ) ;
} ,
_process _onchange : function ( on _change _obj ) {
var self = this ;
var widget = on _change _obj . widget ;
var processed = on _change _obj . processed ;
try {
var def ;
processed = processed || [ ] ;
processed . push ( widget . name ) ;
var on _change = widget . node . attrs . on _change ;
if ( on _change ) {
var change _spec = self . parse _on _change ( on _change , widget ) ;
2013-02-18 18:07:32 +00:00
var ids = [ ] ;
if ( self . datarecord . id && ! instance . web . BufferedDataSet . virtual _id _regex . test ( self . datarecord . id ) ) {
// In case of a o2m virtual id, we should pass an empty ids list
ids . push ( self . datarecord . id ) ;
}
2013-02-27 11:31:32 +00:00
def = self . alive ( new instance . web . Model ( self . dataset . model ) . call (
change _spec . method , [ ids ] . concat ( change _spec . args ) ) ) ;
2012-10-31 15:39:46 +00:00
} else {
def = $ . when ( { } ) ;
}
2012-11-08 11:14:48 +00:00
return def . then ( function ( response ) {
2012-10-31 15:39:46 +00:00
if ( widget . field [ 'change_default' ] ) {
2012-11-27 13:34:35 +00:00
var fieldname = widget . name ;
2012-10-31 15:39:46 +00:00
var value _ ;
if ( response . value && ( fieldname in response . value ) ) {
// Use value from onchange if onchange executed
value _ = response . value [ fieldname ] ;
} else {
// otherwise get form value for field
value _ = self . fields [ fieldname ] . get _value ( ) ;
}
var condition = fieldname + '=' + value _ ;
2012-02-07 16:01:58 +00:00
2012-10-31 15:39:46 +00:00
if ( value _ ) {
2013-02-27 11:31:32 +00:00
return self . alive ( new instance . web . Model ( 'ir.values' ) . call (
2012-11-27 13:34:35 +00:00
'get_defaults' , [ self . model , condition ]
2013-02-27 11:31:32 +00:00
) ) . then ( function ( results ) {
2012-10-31 15:39:46 +00:00
if ( ! results . length ) {
2012-10-31 14:30:36 +00:00
return response ;
2012-10-31 15:39:46 +00:00
}
if ( ! response . value ) {
response . value = { } ;
}
for ( var i = 0 ; i < results . length ; ++ i ) {
// [whatever, key, value]
var triplet = results [ i ] ;
response . value [ triplet [ 1 ] ] = triplet [ 2 ] ;
}
return response ;
} ) ;
2012-02-07 16:01:58 +00:00
}
2012-10-31 15:39:46 +00:00
}
return response ;
2012-11-08 11:14:48 +00:00
} ) . then ( function ( response ) {
2012-10-31 15:39:46 +00:00
return self . on _processed _onchange ( response , processed ) ;
} ) ;
} catch ( e ) {
console . error ( e ) ;
instance . webclient . crashmanager . show _message ( e ) ;
return $ . Deferred ( ) . reject ( ) ;
}
2011-04-06 14:51:13 +00:00
} ,
2012-06-25 13:52:15 +00:00
on _processed _onchange : function ( result , processed ) {
2011-10-12 15:08:30 +00:00
try {
2011-04-06 14:51:13 +00:00
if ( result . value ) {
2012-09-25 15:59:45 +00:00
this . _internal _set _values ( result . value , processed ) ;
2011-04-06 14:51:13 +00:00
}
2011-07-06 08:32:14 +00:00
if ( ! _ . isEmpty ( result . warning ) ) {
2012-07-13 11:47:37 +00:00
instance . web . dialog ( $ ( QWeb . render ( "CrashManager.warning" , result . warning ) ) , {
2012-05-22 06:28:14 +00:00
title : result . warning . title ,
2011-04-06 14:51:13 +00:00
modal : true ,
2011-12-15 10:40:31 +00:00
buttons : [
{ text : _t ( "Ok" ) , click : function ( ) { $ ( this ) . dialog ( "close" ) ; } }
]
2011-04-06 14:51:13 +00:00
} ) ;
}
2013-01-24 14:40:18 +00:00
var fields = this . fields ;
_ ( result . domain ) . each ( function ( domain , fieldname ) {
var field = fields [ fieldname ] ;
if ( ! field ) { return ; }
field . node . attrs . domain = domain ;
} ) ;
2011-10-12 15:08:30 +00:00
return $ . Deferred ( ) . resolve ( ) ;
} catch ( e ) {
console . error ( e ) ;
2012-10-11 00:37:29 +00:00
instance . webclient . crashmanager . show _message ( e ) ;
2011-10-12 15:08:30 +00:00
return $ . Deferred ( ) . reject ( ) ;
}
2011-03-30 14:00:48 +00:00
} ,
2012-10-31 15:39:46 +00:00
_process _operations : function ( ) {
var self = this ;
return this . mutating _mutex . exec ( function ( ) {
function iterate ( ) {
var on _change _obj = self . on _change _list . shift ( ) ;
if ( on _change _obj ) {
2012-11-08 11:14:48 +00:00
return self . _process _onchange ( on _change _obj ) . then ( function ( ) {
2012-10-31 15:39:46 +00:00
return iterate ( ) ;
} ) ;
}
2012-11-05 11:18:19 +00:00
var defs = [ ] ;
_ . each ( self . fields , function ( field ) {
defs . push ( field . commit _value ( ) ) ;
} ) ;
var args = _ . toArray ( arguments ) ;
2012-11-08 11:14:48 +00:00
return $ . when . apply ( $ , defs ) . then ( function ( ) {
2012-11-05 11:18:19 +00:00
if ( self . on _change _list . length !== 0 ) {
return iterate ( ) ;
}
var save _obj = self . save _list . pop ( ) ;
if ( save _obj ) {
2012-11-08 11:14:48 +00:00
return self . _process _save ( save _obj ) . then ( function ( ) {
2012-11-05 17:14:12 +00:00
save _obj . ret = _ . toArray ( arguments ) ;
return iterate ( ) ;
2012-11-16 15:12:48 +00:00
} , function ( ) {
save _obj . error = true ;
2012-11-05 11:18:19 +00:00
} ) ;
}
2012-11-05 17:14:12 +00:00
return $ . when ( ) ;
2012-11-05 11:18:19 +00:00
} ) ;
2013-07-25 10:07:49 +00:00
}
2012-10-31 15:39:46 +00:00
return iterate ( ) ;
} ) ;
} ,
2012-09-25 15:59:45 +00:00
_internal _set _values : function ( values , exclude ) {
exclude = exclude || [ ] ;
for ( var f in values ) {
if ( ! values . hasOwnProperty ( f ) ) { continue ; }
var field = this . fields [ f ] ;
// If field is not defined in the view, just ignore it
if ( field ) {
var value _ = values [ f ] ;
if ( field . get _value ( ) != value _ ) {
field . _inhibit _on _change _flag = true ;
field . set _value ( value _ ) ;
field . _inhibit _on _change _flag = false ;
field . _dirty _flag = true ;
if ( ! _ . contains ( exclude , field . name ) ) {
this . do _onchange ( field , exclude ) ;
}
}
}
}
this . on _form _changed ( ) ;
} ,
set _values : function ( values ) {
var self = this ;
2012-10-31 15:39:46 +00:00
return this . mutating _mutex . exec ( function ( ) {
2012-09-25 15:59:45 +00:00
self . _internal _set _values ( values ) ;
} ) ;
} ,
2012-07-26 10:27:19 +00:00
/ * *
* Ask the view to switch to view mode if possible . The view may not do it
* if the current record is not yet saved . It will then stay in create mode .
* /
2012-07-26 09:51:04 +00:00
to _view _mode : function ( ) {
2012-07-26 09:56:53 +00:00
this . _actualize _mode ( "view" ) ;
2012-07-26 09:51:04 +00:00
} ,
2012-07-26 10:27:19 +00:00
/ * *
* Ask the view to switch to edit mode if possible . The view may not do it
* if the current record is not yet saved . It will then stay in create mode .
* /
2012-07-26 09:51:04 +00:00
to _edit _mode : function ( ) {
2012-07-26 09:56:53 +00:00
this . _actualize _mode ( "edit" ) ;
2012-07-26 09:51:04 +00:00
} ,
/ * *
2012-08-16 09:38:18 +00:00
* Ask the view to switch to a precise mode if possible . The view is free to
* not respect this command if the state of the dataset is not compatible with
* the new mode . For example , it is not possible to switch to edit mode if
* the current record is not yet saved in database .
*
* @ param { string } [ new _mode ] Can be "edit" , "view" , "create" or undefined . If
* undefined the view will test the actual mode to check if it is still consistent
* with the dataset state .
2012-07-26 09:51:04 +00:00
* /
2012-07-26 09:56:53 +00:00
_actualize _mode : function ( switch _to ) {
2012-07-26 09:51:04 +00:00
var mode = switch _to || this . get ( "actual_mode" ) ;
2012-08-02 13:54:03 +00:00
if ( ! this . datarecord . id ) {
2012-07-26 09:51:04 +00:00
mode = "create" ;
2012-08-16 09:38:18 +00:00
} else if ( mode === "create" ) {
mode = "edit" ;
2012-08-02 13:54:03 +00:00
}
2012-07-26 09:51:04 +00:00
this . set ( { actual _mode : mode } ) ;
} ,
2012-07-25 14:31:50 +00:00
check _actual _mode : function ( source , options ) {
2012-04-09 21:30:43 +00:00
var self = this ;
2012-07-25 14:13:33 +00:00
if ( this . get ( "actual_mode" ) === "view" ) {
2012-08-24 18:27:07 +00:00
self . $el . removeClass ( 'oe_form_editable' ) . addClass ( 'oe_form_readonly' ) ;
2012-04-09 21:30:43 +00:00
self . $buttons . find ( '.oe_form_buttons_edit' ) . hide ( ) ;
self . $buttons . find ( '.oe_form_buttons_view' ) . show ( ) ;
2012-04-27 23:41:19 +00:00
self . $sidebar . show ( ) ;
2012-04-09 23:36:15 +00:00
} else {
2012-08-24 18:27:07 +00:00
self . $el . removeClass ( 'oe_form_readonly' ) . addClass ( 'oe_form_editable' ) ;
2012-04-09 23:36:15 +00:00
self . $buttons . find ( '.oe_form_buttons_edit' ) . show ( ) ;
self . $buttons . find ( '.oe_form_buttons_view' ) . hide ( ) ;
2012-04-27 23:41:19 +00:00
self . $sidebar . hide ( ) ;
2012-08-01 16:12:04 +00:00
this . autofocus ( ) ;
}
} ,
autofocus : function ( ) {
2012-08-02 09:53:26 +00:00
if ( this . get ( "actual_mode" ) !== "view" && ! this . options . disable _autofocus ) {
2012-08-01 16:12:04 +00:00
var fields _order = this . fields _order . slice ( 0 ) ;
if ( this . default _focus _field ) {
fields _order . unshift ( this . default _focus _field . name ) ;
2012-06-28 13:02:49 +00:00
}
for ( var i = 0 ; i < fields _order . length ; i += 1 ) {
2012-08-01 16:12:04 +00:00
var field = this . fields [ fields _order [ i ] ] ;
2012-10-12 14:51:43 +00:00
if ( ! field . get ( 'effective_invisible' ) && ! field . get ( 'effective_readonly' ) && field . $label ) {
2012-08-01 16:20:24 +00:00
if ( field . focus ( ) !== false ) {
break ;
}
2012-06-28 13:02:49 +00:00
}
}
2012-04-09 21:30:43 +00:00
}
2012-04-09 20:53:34 +00:00
} ,
2011-11-09 15:12:39 +00:00
on _button _save : function ( ) {
2011-04-07 13:07:25 +00:00
var self = this ;
2012-10-30 14:06:30 +00:00
return this . save ( ) . done ( function ( result ) {
2012-10-15 07:53:20 +00:00
self . trigger ( "save" , result ) ;
2012-07-26 09:51:04 +00:00
self . to _view _mode ( ) ;
2013-04-17 13:34:38 +00:00
} ) . then ( function ( result ) {
2013-07-19 09:07:53 +00:00
var parent = self . ViewManager . ActionManager . getParent ( ) ;
if ( parent ) {
parent . menu . do _reload _needaction ( ) ;
}
2011-04-07 13:07:25 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-04-19 20:44:18 +00:00
on _button _cancel : function ( event ) {
2012-02-15 12:39:01 +00:00
if ( this . can _be _discarded ( ) ) {
2012-08-02 16:54:40 +00:00
if ( this . get ( 'actual_mode' ) === 'create' ) {
this . trigger ( 'history_back' ) ;
} else {
this . to _view _mode ( ) ;
2012-10-10 10:02:33 +00:00
this . trigger ( 'load_record' , this . datarecord ) ;
2012-08-02 16:54:40 +00:00
}
2012-02-15 12:39:01 +00:00
}
2012-10-10 11:40:07 +00:00
this . trigger ( 'on_button_cancel' ) ;
2012-04-19 20:44:18 +00:00
return false ;
2011-11-07 13:45:39 +00:00
} ,
2011-12-01 12:22:33 +00:00
on _button _new : function ( ) {
2011-11-07 13:45:39 +00:00
var self = this ;
2012-07-26 09:51:04 +00:00
this . to _edit _mode ( ) ;
2012-10-30 14:06:30 +00:00
return $ . when ( this . has _been _loaded ) . then ( function ( ) {
2011-09-15 08:12:41 +00:00
if ( self . can _be _discarded ( ) ) {
2012-07-16 11:04:30 +00:00
return self . load _defaults ( ) ;
2011-09-15 08:12:41 +00:00
}
2011-04-07 13:07:25 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-04-09 20:53:34 +00:00
on _button _edit : function ( ) {
2012-07-26 09:51:04 +00:00
return this . to _edit _mode ( ) ;
2012-04-09 20:53:34 +00:00
} ,
on _button _create : function ( ) {
this . dataset . index = null ;
2012-04-09 23:36:15 +00:00
this . do _show ( ) ;
2012-04-09 20:53:34 +00:00
} ,
on _button _duplicate : function ( ) {
var self = this ;
2012-10-30 14:06:30 +00:00
return this . has _been _loaded . then ( function ( ) {
return self . dataset . call ( 'copy' , [ self . datarecord . id , { } , self . dataset . context ] ) . then ( function ( new _id ) {
self . record _created ( new _id ) ;
self . to _edit _mode ( ) ;
2012-04-09 20:53:34 +00:00
} ) ;
} ) ;
} ,
on _button _delete : function ( ) {
var self = this ;
var def = $ . Deferred ( ) ;
2012-10-30 14:06:30 +00:00
this . has _been _loaded . done ( function ( ) {
2012-04-09 20:53:34 +00:00
if ( self . datarecord . id && confirm ( _t ( "Do you really want to delete this record?" ) ) ) {
2012-10-30 14:06:30 +00:00
self . dataset . unlink ( [ self . datarecord . id ] ) . done ( function ( ) {
2013-05-01 05:41:29 +00:00
if ( self . dataset . size ( ) ) {
self . execute _pager _action ( 'next' ) ;
} else {
self . do _action ( 'history_back' ) ;
}
2012-04-09 20:53:34 +00:00
def . resolve ( ) ;
} ) ;
} else {
2012-10-30 14:06:30 +00:00
$ . async _when ( ) . done ( function ( ) {
2012-04-09 20:53:34 +00:00
def . reject ( ) ;
2013-07-25 10:33:01 +00:00
} ) ;
2012-04-09 20:53:34 +00:00
}
} ) ;
return def . promise ( ) ;
} ,
2011-09-14 21:09:02 +00:00
can _be _discarded : function ( ) {
2012-09-06 13:26:02 +00:00
if ( this . $el . is ( '.oe_form_dirty' ) ) {
if ( ! confirm ( _t ( "Warning, the record has been modified, your changes will be discarded.\n\nAre you sure you want to leave this page ?" ) ) ) {
return false ;
}
this . $el . removeClass ( 'oe_form_dirty' ) ;
}
return true ;
2011-09-14 21:09:02 +00:00
} ,
2011-06-06 13:11:08 +00:00
/ * *
* Triggers saving the form ' s record . Chooses between creating a new
* record or saving an existing one depending on whether the record
* already has an id property .
*
2012-10-12 08:38:27 +00:00
* @ param { Boolean } [ prepend _on _create = false ] if ` ` save ` ` creates a new
2012-08-29 10:23:00 +00:00
* record , should that record be inserted at the start of the dataset ( by
* default , records are added at the end )
2011-06-06 13:11:08 +00:00
* /
2012-10-12 08:38:27 +00:00
save : function ( prepend _on _create ) {
2011-04-11 11:35:16 +00:00
var self = this ;
2012-11-05 17:14:12 +00:00
var save _obj = { prepend _on _create : prepend _on _create , ret : null } ;
this . save _list . push ( save _obj ) ;
2012-11-08 11:14:48 +00:00
return this . _process _operations ( ) . then ( function ( ) {
2012-11-16 15:12:48 +00:00
if ( save _obj . error )
return $ . Deferred ( ) . reject ( ) ;
2012-11-05 17:14:12 +00:00
return $ . when . apply ( $ , save _obj . ret ) ;
2013-05-01 05:41:29 +00:00
} ) . done ( function ( ) {
self . $el . removeClass ( 'oe_form_dirty' ) ;
2012-11-05 17:14:12 +00:00
} ) ;
2012-10-31 15:39:46 +00:00
} ,
_process _save : function ( save _obj ) {
var self = this ;
var prepend _on _create = save _obj . prepend _on _create ;
try {
2011-11-15 14:58:06 +00:00
var form _invalid = false ,
2011-10-11 15:35:35 +00:00
values = { } ,
2013-03-08 10:40:50 +00:00
first _invalid _field = null ,
readonly _values = { } ;
2011-10-11 15:35:35 +00:00
for ( var f in self . fields ) {
2012-06-27 10:01:51 +00:00
if ( ! self . fields . hasOwnProperty ( f ) ) { continue ; }
2011-10-11 15:35:35 +00:00
f = self . fields [ f ] ;
if ( ! f . is _valid ( ) ) {
form _invalid = true ;
if ( ! first _invalid _field ) {
first _invalid _field = f ;
}
2013-03-08 10:40:50 +00:00
} else if ( f . name !== 'id' && ( ! self . datarecord . id || f . _dirty _flag ) ) {
2011-11-21 12:40:30 +00:00
// Special case 'id' field, do not save this field
// on 'create' : save all non readonly fields
// on 'edit' : save non readonly modified fields
2013-03-08 10:40:50 +00:00
if ( ! f . get ( "readonly" ) ) {
values [ f . name ] = f . get _value ( ) ;
} else {
readonly _values [ f . name ] = f . get _value ( ) ;
}
2011-06-22 12:25:42 +00:00
}
2011-03-30 14:00:48 +00:00
}
2011-10-11 15:35:35 +00:00
if ( form _invalid ) {
2012-04-18 12:20:39 +00:00
self . set ( { 'display_invalid_fields' : true } ) ;
2011-10-11 15:35:35 +00:00
first _invalid _field . focus ( ) ;
self . on _invalid ( ) ;
return $ . Deferred ( ) . reject ( ) ;
2011-04-11 11:35:16 +00:00
} else {
2012-04-18 12:20:39 +00:00
self . set ( { 'display_invalid_fields' : false } ) ;
2011-12-08 12:38:46 +00:00
var save _deferral ;
2011-10-11 15:35:35 +00:00
if ( ! self . datarecord . id ) {
2012-08-29 10:23:00 +00:00
// Creation save
2013-03-08 10:40:50 +00:00
save _deferral = self . dataset . create ( values , { readonly _fields : readonly _values } ) . then ( function ( r ) {
2012-10-10 12:33:51 +00:00
return self . record _created ( r , prepend _on _create ) ;
2011-12-08 12:38:46 +00:00
} , null ) ;
2013-01-02 10:28:35 +00:00
} else if ( _ . isEmpty ( values ) ) {
2012-08-29 10:23:00 +00:00
// Not dirty, noop save
2011-12-08 12:38:46 +00:00
save _deferral = $ . Deferred ( ) . resolve ( { } ) . promise ( ) ;
2011-10-11 15:35:35 +00:00
} else {
2012-08-29 10:23:00 +00:00
// Write save
2013-03-08 10:40:50 +00:00
save _deferral = self . dataset . write ( self . datarecord . id , values , { readonly _fields : readonly _values } ) . then ( function ( r ) {
2012-10-10 13:20:49 +00:00
return self . record _saved ( r ) ;
2011-12-08 12:38:46 +00:00
} , null ) ;
2011-10-11 15:35:35 +00:00
}
2012-08-29 10:23:00 +00:00
return save _deferral ;
2011-04-11 11:35:16 +00:00
}
2012-10-31 15:39:46 +00:00
} catch ( e ) {
console . error ( e ) ;
return $ . Deferred ( ) . reject ( ) ;
}
2011-04-05 14:34:25 +00:00
} ,
2011-03-30 14:00:48 +00:00
on _invalid : function ( ) {
2012-07-04 15:23:29 +00:00
var warnings = _ ( this . fields ) . chain ( )
. filter ( function ( f ) { return ! f . is _valid ( ) ; } )
. map ( function ( f ) {
return _ . str . sprintf ( '<li>%s</li>' ,
2012-07-11 11:29:59 +00:00
_ . escape ( f . string ) ) ;
2012-07-04 15:23:29 +00:00
} ) . value ( ) ;
warnings . unshift ( '<ul>' ) ;
warnings . push ( '</ul>' ) ;
2012-11-29 01:18:22 +00:00
this . do _warn ( _t ( "The following fields are invalid:" ) , warnings . join ( '' ) ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-08-29 10:23:00 +00:00
/ * *
* Reload the form after saving
*
* @ param { Object } r result of the write function .
* /
2012-10-10 13:20:49 +00:00
record _saved : function ( r ) {
var self = this ;
2012-10-01 22:02:48 +00:00
if ( ! r ) {
2011-09-12 14:07:53 +00:00
// should not happen in the server, but may happen for internal purpose
2012-10-10 13:20:49 +00:00
this . trigger ( 'record_saved' , r ) ;
2011-09-26 12:39:29 +00:00
return $ . Deferred ( ) . reject ( ) ;
2011-04-05 15:53:48 +00:00
} else {
2012-10-30 14:06:30 +00:00
return $ . when ( this . reload ( ) ) . then ( function ( ) {
2012-10-10 13:20:49 +00:00
self . trigger ( 'record_saved' , r ) ;
2012-08-29 10:23:00 +00:00
return r ;
} ) ;
2011-04-11 15:59:46 +00:00
}
} ,
2011-06-06 13:11:08 +00:00
/ * *
* Updates the form ' dataset to contain the new record :
*
* * Adds the newly created record to the current dataset ( at the end by
* default )
* * Selects that record ( sets the dataset ' s index to point to the new
* record ' s id ) .
* * Updates the pager and sidebar displays
*
* @ param { Object } r
2012-08-29 10:23:00 +00:00
* @ param { Boolean } [ prepend _on _create = false ] adds the newly created record
* at the beginning of the dataset instead of the end
2011-06-06 13:11:08 +00:00
* /
2012-10-10 12:33:51 +00:00
record _created : function ( r , prepend _on _create ) {
var self = this ;
2012-10-01 22:02:48 +00:00
if ( ! r ) {
2011-09-12 14:07:53 +00:00
// should not happen in the server, but may happen for internal purpose
2012-10-10 12:33:51 +00:00
this . trigger ( 'record_created' , r ) ;
2011-09-26 12:39:29 +00:00
return $ . Deferred ( ) . reject ( ) ;
2011-04-11 15:59:46 +00:00
} else {
2012-10-01 22:02:48 +00:00
this . datarecord . id = r ;
2011-06-06 13:11:08 +00:00
if ( ! prepend _on _create ) {
2012-02-14 15:20:31 +00:00
this . dataset . alter _ids ( this . dataset . ids . concat ( [ this . datarecord . id ] ) ) ;
2011-06-06 13:11:08 +00:00
this . dataset . index = this . dataset . ids . length - 1 ;
} else {
2012-04-17 01:19:33 +00:00
this . dataset . alter _ids ( [ this . datarecord . id ] . concat ( this . dataset . ids ) ) ;
2011-06-06 13:11:08 +00:00
this . dataset . index = 0 ;
}
2011-04-11 15:59:46 +00:00
this . do _update _pager ( ) ;
2011-07-26 21:00:05 +00:00
if ( this . sidebar ) {
2012-04-17 01:19:33 +00:00
this . sidebar . do _attachement _update ( this . dataset , this . datarecord . id ) ;
2012-12-18 13:47:40 +00:00
}
2012-01-12 14:45:47 +00:00
//openerp.log("The record has been created with id #" + this.datarecord.id);
2012-10-30 14:06:30 +00:00
return $ . when ( this . reload ( ) ) . then ( function ( ) {
2012-10-10 12:33:51 +00:00
self . trigger ( 'record_created' , r ) ;
2012-08-29 10:23:00 +00:00
return _ . extend ( r , { created : true } ) ;
} ) ;
2011-04-05 15:14:40 +00:00
}
2011-03-31 14:44:22 +00:00
} ,
2011-04-01 10:44:54 +00:00
on _action : function ( action ) {
2011-09-12 13:56:03 +00:00
console . debug ( 'Executing action' , action ) ;
2011-04-08 10:37:36 +00:00
} ,
2011-07-26 21:00:05 +00:00
reload : function ( ) {
2011-10-12 14:10:07 +00:00
var self = this ;
2012-01-10 14:47:09 +00:00
return this . reload _mutex . exec ( function ( ) {
2013-07-25 10:07:49 +00:00
if ( self . dataset . index === null || self . dataset . index === undefined ) {
2012-10-11 13:00:11 +00:00
self . trigger ( "previous_view" ) ;
2012-04-09 23:36:15 +00:00
return $ . Deferred ( ) . reject ( ) . promise ( ) ;
}
2013-07-25 10:07:49 +00:00
if ( self . dataset . index < 0 ) {
2011-10-12 14:10:07 +00:00
return $ . when ( self . on _button _new ( ) ) ;
} else {
2012-07-31 14:03:09 +00:00
var fields = _ . keys ( self . fields _view . fields ) ;
fields . push ( 'display_name' ) ;
2012-10-10 10:02:33 +00:00
return self . dataset . read _index ( fields ,
{
context : {
'bin_size' : true ,
'future_display_name' : true
}
2012-10-30 14:06:30 +00:00
} ) . then ( function ( r ) {
2012-10-10 10:02:33 +00:00
self . trigger ( 'load_record' , r ) ;
} ) ;
2011-10-12 14:10:07 +00:00
}
2012-01-10 14:47:09 +00:00
} ) ;
2011-07-26 21:00:05 +00:00
} ,
2012-03-19 17:03:36 +00:00
get _widgets : function ( ) {
return _ . filter ( this . getChildren ( ) , function ( obj ) {
2012-04-26 15:28:00 +00:00
return obj instanceof instance . web . form . FormWidget ;
2012-03-19 17:03:36 +00:00
} ) ;
} ,
2012-11-08 10:38:56 +00:00
get _fields _values : function ( ) {
2011-07-26 21:00:05 +00:00
var values = { } ;
2012-01-18 16:15:17 +00:00
var ids = this . get _selected _ids ( ) ;
values [ "id" ] = ids . length > 0 ? ids [ 0 ] : false ;
2012-04-17 14:32:27 +00:00
_ . each ( this . fields , function ( value _ , key ) {
2012-06-27 10:01:51 +00:00
values [ key ] = value _ . get _value ( ) ;
2011-07-26 21:00:05 +00:00
} ) ;
return values ;
2011-08-26 13:03:35 +00:00
} ,
get _selected _ids : function ( ) {
var id = this . dataset . ids [ this . dataset . index ] ;
return id ? [ id ] : [ ] ;
2011-09-26 12:39:29 +00:00
} ,
recursive _save : function ( ) {
var self = this ;
2012-10-30 14:06:30 +00:00
return $ . when ( this . save ( ) ) . then ( function ( res ) {
2011-09-26 16:00:57 +00:00
if ( self . dataset . parent _view )
return self . dataset . parent _view . recursive _save ( ) ;
2011-09-26 12:39:29 +00:00
} ) ;
2011-09-30 15:46:12 +00:00
} ,
2012-09-24 12:53:55 +00:00
recursive _reload : function ( ) {
var self = this ;
var pre = $ . when ( ) ;
if ( self . dataset . parent _view )
pre = self . dataset . parent _view . recursive _reload ( ) ;
2012-10-30 14:06:30 +00:00
return pre . then ( function ( ) {
2012-09-24 12:53:55 +00:00
return self . reload ( ) ;
} ) ;
} ,
2011-11-15 14:58:06 +00:00
is _dirty : function ( ) {
2012-04-17 14:32:27 +00:00
return _ . any ( this . fields , function ( value _ ) {
2012-04-18 11:50:04 +00:00
return value _ . _dirty _flag ;
2011-11-16 07:52:46 +00:00
} ) ;
2011-11-15 14:58:06 +00:00
} ,
2011-09-30 15:46:12 +00:00
is _interactible _record : function ( ) {
var id = this . datarecord . id ;
if ( ! id ) {
if ( this . options . not _interactible _on _create )
return false ;
} else if ( typeof ( id ) === "string" ) {
2012-04-17 12:09:49 +00:00
if ( instance . web . BufferedDataSet . virtual _id _regex . test ( id ) )
2011-09-30 15:46:12 +00:00
return false ;
}
return true ;
2011-11-21 14:14:18 +00:00
} ,
2012-11-20 10:06:20 +00:00
sidebar _eval _context : function ( ) {
return $ . when ( this . build _eval _context ( ) ) ;
2012-02-08 12:21:53 +00:00
} ,
open _defaults _dialog : function ( ) {
var self = this ;
2012-10-17 14:28:35 +00:00
var display = function ( field , value ) {
if ( field instanceof instance . web . form . FieldSelection ) {
return _ ( field . values ) . find ( function ( option ) {
return option [ 0 ] === value ;
} ) [ 1 ] ;
} else if ( field instanceof instance . web . form . FieldMany2One ) {
return field . get _displayed ( ) ;
}
return value ;
2013-07-25 10:33:01 +00:00
} ;
2012-02-08 12:21:53 +00:00
var fields = _ . chain ( this . fields )
2013-05-01 05:41:29 +00:00
. map ( function ( field ) {
2012-05-22 14:16:49 +00:00
var value = field . get _value ( ) ;
2012-02-08 12:21:53 +00:00
// ignore fields which are empty, invisible, readonly, o2m
// or m2m
2012-05-22 14:16:49 +00:00
if ( ! value
2012-03-26 16:29:34 +00:00
|| field . get ( 'invisible' )
2012-03-20 15:51:11 +00:00
|| field . get ( "readonly" )
2012-02-08 12:21:53 +00:00
|| field . field . type === 'one2many'
2012-09-21 10:30:44 +00:00
|| field . field . type === 'many2many'
2012-11-02 11:20:02 +00:00
|| field . field . type === 'binary'
|| field . password ) {
2012-02-08 12:21:53 +00:00
return false ;
}
2012-02-09 15:14:10 +00:00
2012-02-08 12:21:53 +00:00
return {
2013-05-01 05:41:29 +00:00
name : field . name ,
2012-06-29 15:02:25 +00:00
string : field . string ,
2012-05-22 14:16:49 +00:00
value : value ,
2012-10-17 14:28:35 +00:00
displayed : display ( field , value ) ,
2013-07-25 10:33:01 +00:00
} ;
2012-02-08 12:21:53 +00:00
} )
. compact ( )
2012-05-22 14:13:42 +00:00
. sortBy ( function ( field ) { return field . string ; } )
2012-02-08 12:21:53 +00:00
. value ( ) ;
2012-10-17 14:28:35 +00:00
var conditions = _ . chain ( self . fields )
. filter ( function ( field ) { return field . field . change _default ; } )
2013-05-01 05:41:29 +00:00
. map ( function ( field ) {
2012-10-17 14:28:35 +00:00
var value = field . get _value ( ) ;
return {
2013-05-01 05:41:29 +00:00
name : field . name ,
2012-10-17 14:28:35 +00:00
string : field . string ,
value : value ,
displayed : display ( field , value ) ,
2013-07-25 10:33:01 +00:00
} ;
2012-10-17 14:28:35 +00:00
} )
2012-02-08 12:21:53 +00:00
. value ( ) ;
2012-04-17 12:09:49 +00:00
var d = new instance . web . Dialog ( this , {
2012-02-08 12:21:53 +00:00
title : _t ( "Set Default" ) ,
args : {
fields : fields ,
conditions : conditions
} ,
buttons : [
{ text : _t ( "Close" ) , click : function ( ) { d . close ( ) ; } } ,
{ text : _t ( "Save default" ) , click : function ( ) {
2012-08-24 18:27:07 +00:00
var $defaults = d . $el . find ( '#formview_default_fields' ) ;
2012-02-08 12:21:53 +00:00
var field _to _set = $defaults . val ( ) ;
if ( ! field _to _set ) {
2012-03-26 12:29:50 +00:00
$defaults . parent ( ) . addClass ( 'oe_form_invalid' ) ;
2012-02-08 12:21:53 +00:00
return ;
}
2012-08-24 18:27:07 +00:00
var condition = d . $el . find ( '#formview_default_conditions' ) . val ( ) ,
all _users = d . $el . find ( '#formview_default_all' ) . is ( ':checked' ) ;
2012-04-17 12:09:49 +00:00
new instance . web . DataSet ( self , 'ir.values' ) . call (
2012-02-08 12:21:53 +00:00
'set_default' , [
self . dataset . model ,
field _to _set ,
self . fields [ field _to _set ] . get _value ( ) ,
all _users ,
2012-08-28 14:22:02 +00:00
true ,
2012-02-08 12:21:53 +00:00
condition || false
2012-10-30 14:06:30 +00:00
] ) . done ( function ( ) { d . close ( ) ; } ) ;
2012-02-08 12:21:53 +00:00
} }
]
} ) ;
d . template = 'FormView.set_default' ;
d . open ( ) ;
2012-04-16 15:08:39 +00:00
} ,
register _field : function ( field , name ) {
this . fields [ name ] = field ;
this . fields _order . push ( name ) ;
2012-07-26 15:47:16 +00:00
if ( JSON . parse ( field . node . attrs . default _focus || "0" ) ) {
2012-06-28 13:02:49 +00:00
this . default _focus _field = field ;
}
2012-06-25 13:52:15 +00:00
2012-06-25 14:40:13 +00:00
field . on ( 'focused' , null , this . proxy ( 'widgetFocused' ) )
. on ( 'blurred' , null , this . proxy ( 'widgetBlurred' ) ) ;
2012-10-04 15:34:00 +00:00
if ( this . get _field _desc ( name ) . translate ) {
2012-04-17 14:32:27 +00:00
this . translatable _fields . push ( field ) ;
2012-04-17 13:33:07 +00:00
}
2012-04-18 09:57:58 +00:00
field . on ( 'changed_value' , this , function ( ) {
2012-09-24 16:30:21 +00:00
if ( field . is _syntax _valid ( ) ) {
this . trigger ( 'field_changed:' + name ) ;
}
2012-09-24 16:07:21 +00:00
if ( field . _inhibit _on _change _flag ) {
return ;
}
2012-04-18 13:31:37 +00:00
field . _dirty _flag = true ;
2012-04-18 11:50:04 +00:00
if ( field . is _syntax _valid ( ) ) {
this . do _onchange ( field ) ;
this . on _form _changed ( true ) ;
this . do _notify _change ( ) ;
}
2012-04-18 09:57:58 +00:00
} ) ;
2012-04-17 13:33:07 +00:00
} ,
2012-10-04 15:34:00 +00:00
get _field _desc : function ( field _name ) {
2012-04-17 13:33:07 +00:00
return this . fields _view . fields [ field _name ] ;
2012-04-16 15:08:39 +00:00
} ,
2012-09-24 16:30:21 +00:00
get _field _value : function ( field _name ) {
return this . fields [ field _name ] . get _value ( ) ;
} ,
2012-10-04 14:33:37 +00:00
compute _domain : function ( expression ) {
return instance . web . form . compute _domain ( expression , this . fields ) ;
} ,
2012-11-08 10:38:56 +00:00
_build _view _fields _values : function ( ) {
2012-10-04 14:52:06 +00:00
var a _dataset = this . dataset ;
2012-11-08 10:38:56 +00:00
var fields _values = this . get _fields _values ( ) ;
2012-10-04 14:52:06 +00:00
var active _id = a _dataset . ids [ a _dataset . index ] ;
_ . extend ( fields _values , {
active _id : active _id || false ,
active _ids : active _id ? [ active _id ] : [ ] ,
active _model : a _dataset . model ,
parent : { }
} ) ;
if ( a _dataset . parent _view ) {
2012-11-08 10:38:56 +00:00
fields _values . parent = a _dataset . parent _view . get _fields _values ( ) ;
2012-10-04 14:52:06 +00:00
}
return fields _values ;
} ,
2012-11-08 10:38:56 +00:00
build _eval _context : function ( ) {
2012-10-04 14:52:06 +00:00
var a _dataset = this . dataset ;
2012-11-08 10:38:56 +00:00
return new instance . web . CompoundContext ( a _dataset . get _context ( ) , this . _build _view _fields _values ( ) ) ;
2012-10-04 14:52:06 +00:00
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2012-03-14 17:09:49 +00:00
2012-03-20 16:26:16 +00:00
/ * *
* Interface to be implemented by rendering engines for the form view .
* /
2012-05-02 09:10:53 +00:00
instance . web . form . FormRenderingEngineInterface = instance . web . Class . extend ( {
2012-03-20 16:26:16 +00:00
set _fields _view : function ( fields _view ) { } ,
2012-04-10 12:21:10 +00:00
set _fields _registry : function ( fields _registry ) { } ,
2012-08-24 18:27:07 +00:00
render _to : function ( $el ) { } ,
2012-05-02 09:10:53 +00:00
} ) ;
2012-03-20 16:26:16 +00:00
2012-03-20 16:18:06 +00:00
/ * *
* Default rendering engine for the form view .
2012-07-12 12:56:37 +00:00
*
2012-03-20 16:18:06 +00:00
* It is necessary to set the view using set _view ( ) before usage .
* /
2012-05-02 09:10:53 +00:00
instance . web . form . FormRenderingEngine = instance . web . form . FormRenderingEngineInterface . extend ( {
2012-03-20 16:18:06 +00:00
init : function ( view ) {
this . view = view ;
} ,
set _fields _view : function ( fvg ) {
2012-03-14 17:09:49 +00:00
this . fvg = fvg ;
2012-06-12 08:10:58 +00:00
this . version = parseFloat ( this . fvg . arch . attrs . version ) ;
if ( isNaN ( this . version ) ) {
this . version = 6.1 ;
}
2012-03-20 16:18:06 +00:00
} ,
2012-04-10 12:09:38 +00:00
set _tags _registry : function ( tags _registry ) {
this . tags _registry = tags _registry ;
2012-03-20 16:18:06 +00:00
} ,
2012-04-10 12:21:10 +00:00
set _fields _registry : function ( fields _registry ) {
this . fields _registry = fields _registry ;
} ,
2012-09-28 10:08:44 +00:00
set _widgets _registry : function ( widgets _registry ) {
this . widgets _registry = widgets _registry ;
} ,
2012-06-09 16:00:09 +00:00
// Backward compatibility tools, current default version: v6.1
process _version : function ( ) {
2012-06-12 08:10:58 +00:00
if ( this . version < 7.0 ) {
this . $form . find ( 'form:first' ) . wrapInner ( '<group col="4"/>' ) ;
this . $form . find ( 'page' ) . each ( function ( ) {
if ( ! $ ( this ) . parents ( 'field' ) . length ) {
$ ( this ) . wrapInner ( '<group col="4"/>' ) ;
}
} ) ;
}
2012-06-09 16:00:09 +00:00
} ,
2012-12-05 09:35:22 +00:00
get _arch _fragment : function ( ) {
2012-12-05 16:05:36 +00:00
var doc = $ . parseXML ( instance . web . json _node _to _xml ( this . fvg . arch ) ) . documentElement ;
2012-12-05 09:35:22 +00:00
// IE won't allow custom button@type and will revert it to spec default : 'submit'
2012-11-14 16:44:13 +00:00
$ ( 'button' , doc ) . each ( function ( ) {
2012-11-19 14:37:19 +00:00
$ ( this ) . attr ( 'data-button-type' , $ ( this ) . attr ( 'type' ) ) . attr ( 'type' , 'button' ) ;
2012-11-14 16:44:13 +00:00
} ) ;
2013-02-21 22:10:25 +00:00
// IE's html parser is also a css parser. How convenient...
$ ( 'board' , doc ) . each ( function ( ) {
$ ( this ) . attr ( 'layout' , $ ( this ) . attr ( 'style' ) ) ;
} ) ;
2012-12-05 10:59:33 +00:00
return $ ( '<div class="oe_form"/>' ) . append ( instance . web . xml _to _str ( doc ) ) ;
2012-11-14 16:44:13 +00:00
} ,
2012-04-10 12:21:10 +00:00
render _to : function ( $target ) {
2012-03-20 16:18:06 +00:00
var self = this ;
2012-04-10 12:21:10 +00:00
this . $target = $target ;
2012-03-21 10:53:36 +00:00
2012-12-05 09:35:22 +00:00
this . $form = this . get _arch _fragment ( ) ;
2012-03-14 17:09:49 +00:00
2012-06-12 08:10:58 +00:00
this . process _version ( ) ;
2012-06-09 16:00:09 +00:00
2012-04-10 13:04:44 +00:00
this . fields _to _init = [ ] ;
this . tags _to _init = [ ] ;
2012-09-28 10:08:44 +00:00
this . widgets _to _init = [ ] ;
2012-03-27 12:47:04 +00:00
this . labels = { } ;
2012-03-20 14:35:16 +00:00
this . process ( this . $form ) ;
2012-03-21 10:53:36 +00:00
2012-04-10 12:21:10 +00:00
this . $form . appendTo ( this . $target ) ;
2012-03-14 17:09:49 +00:00
2012-10-11 14:51:48 +00:00
this . to _replace = [ ] ;
2012-10-11 14:47:05 +00:00
_ . each ( this . fields _to _init , function ( $elem ) {
2012-04-10 13:04:44 +00:00
var name = $elem . attr ( "name" ) ;
if ( ! self . fvg . fields [ name ] ) {
2012-11-29 00:22:00 +00:00
throw new Error ( _ . str . sprintf ( _t ( "Field '%s' specified in view could not be found." ) , name ) ) ;
2012-04-10 13:04:44 +00:00
}
2012-04-10 13:26:57 +00:00
var obj = self . fields _registry . get _any ( [ $elem . attr ( 'widget' ) , self . fvg . fields [ name ] . type ] ) ;
if ( ! obj ) {
2012-11-29 00:22:00 +00:00
throw new Error ( _ . str . sprintf ( _t ( "Widget type '%s' is not implemented" ) , $elem . attr ( 'widget' ) ) ) ;
2012-04-10 13:04:44 +00:00
}
2012-04-17 12:09:49 +00:00
var w = new ( obj ) ( self . view , instance . web . xml _to _json ( $elem [ 0 ] ) ) ;
2012-04-10 13:04:44 +00:00
var $label = self . labels [ $elem . attr ( "name" ) ] ;
if ( $label ) {
w . set _input _id ( $label . attr ( "for" ) ) ;
2012-03-14 17:09:49 +00:00
}
2012-04-10 13:04:44 +00:00
self . alter _field ( w ) ;
2012-04-16 15:08:39 +00:00
self . view . register _field ( w , $elem . attr ( "name" ) ) ;
2012-10-11 14:51:48 +00:00
self . to _replace . push ( [ w , $elem ] ) ;
2012-03-14 17:09:49 +00:00
} ) ;
2012-04-10 13:04:44 +00:00
_ . each ( this . tags _to _init , function ( $elem ) {
var tag _name = $elem [ 0 ] . tagName . toLowerCase ( ) ;
var obj = self . tags _registry . get _object ( tag _name ) ;
2012-04-17 12:09:49 +00:00
var w = new ( obj ) ( self . view , instance . web . xml _to _json ( $elem [ 0 ] ) ) ;
2012-10-11 14:51:48 +00:00
self . to _replace . push ( [ w , $elem ] ) ;
2012-05-30 09:34:46 +00:00
} ) ;
2012-09-28 10:08:44 +00:00
_ . each ( this . widgets _to _init , function ( $elem ) {
var widget _type = $elem . attr ( "type" ) ;
var obj = self . widgets _registry . get _object ( widget _type ) ;
var w = new ( obj ) ( self . view , instance . web . xml _to _json ( $elem [ 0 ] ) ) ;
2012-10-11 14:51:48 +00:00
self . to _replace . push ( [ w , $elem ] ) ;
2012-09-28 10:08:44 +00:00
} ) ;
2012-10-11 14:51:48 +00:00
} ,
init _fields : function ( ) {
var defs = [ ] ;
_ . each ( this . to _replace , function ( el ) {
defs . push ( el [ 0 ] . replace ( el [ 1 ] ) ) ;
2012-09-28 10:08:44 +00:00
} ) ;
2012-10-11 15:21:40 +00:00
this . to _replace = [ ] ;
2012-10-11 14:51:48 +00:00
return $ . when . apply ( $ , defs ) ;
2012-03-21 10:53:36 +00:00
} ,
2012-05-31 09:08:30 +00:00
render _element : function ( template /* dictionaries */ ) {
var dicts = [ ] . slice . call ( arguments ) . slice ( 1 ) ;
2012-04-10 10:29:51 +00:00
var dict = _ . extend . apply ( _ , dicts ) ;
dict [ 'classnames' ] = dict [ 'class' ] || '' ; // class is a reserved word and might caused problem to Safari when used from QWeb
2012-03-21 10:53:36 +00:00
return $ ( QWeb . render ( template , dict ) ) ;
2012-03-20 11:01:15 +00:00
} ,
2012-04-09 21:43:48 +00:00
alter _field : function ( field ) {
} ,
2012-03-21 10:53:36 +00:00
toggle _layout _debugging : function ( ) {
2012-04-10 12:21:10 +00:00
if ( ! this . $target . has ( '.oe_layout_debug_cell:first' ) . length ) {
2012-04-18 16:10:39 +00:00
this . $target . find ( '[title]' ) . removeAttr ( 'title' ) ;
2012-04-10 12:21:10 +00:00
this . $target . find ( '.oe_form_group_cell' ) . each ( function ( ) {
2012-04-18 16:10:39 +00:00
var text = 'W:' + ( $ ( this ) . attr ( 'width' ) || '' ) + ' - C:' + $ ( this ) . attr ( 'colspan' ) ;
$ ( this ) . attr ( 'title' , text ) ;
2012-03-20 11:01:15 +00:00
} ) ;
}
2012-04-10 12:21:10 +00:00
this . $target . toggleClass ( 'oe_layout_debugging' ) ;
2012-03-14 17:09:49 +00:00
} ,
2012-05-31 09:08:30 +00:00
process : function ( $tag ) {
2012-03-20 11:05:29 +00:00
var self = this ;
var tagname = $tag [ 0 ] . nodeName . toLowerCase ( ) ;
2012-04-10 13:04:44 +00:00
if ( this . tags _registry . contains ( tagname ) ) {
this . tags _to _init . push ( $tag ) ;
return $tag ;
2012-03-20 11:05:29 +00:00
}
2012-04-10 13:04:44 +00:00
var fn = self [ 'process_' + tagname ] ;
2012-03-20 14:35:16 +00:00
if ( fn ) {
var args = [ ] . slice . call ( arguments ) ;
args [ 0 ] = $tag ;
2012-03-20 15:04:57 +00:00
return fn . apply ( self , args ) ;
2012-03-20 14:35:16 +00:00
} else {
// generic tag handling, just process children
$tag . children ( ) . each ( function ( ) {
2012-05-31 09:08:30 +00:00
self . process ( $ ( this ) ) ;
2012-03-20 11:05:29 +00:00
} ) ;
2012-03-29 09:55:24 +00:00
self . handle _common _properties ( $tag , $tag ) ;
2012-03-27 09:39:38 +00:00
$tag . removeAttr ( "modifiers" ) ;
2012-03-20 15:04:57 +00:00
return $tag ;
2012-03-20 11:05:29 +00:00
}
} ,
2012-09-28 10:08:44 +00:00
process _widget : function ( $widget ) {
this . widgets _to _init . push ( $widget ) ;
return $widget ;
} ,
2012-05-31 09:08:30 +00:00
process _sheet : function ( $sheet ) {
var $new _sheet = this . render _element ( 'FormRenderingSheet' , $sheet . getAttributes ( ) ) ;
2012-04-24 10:37:12 +00:00
this . handle _common _properties ( $new _sheet , $sheet ) ;
2012-05-31 09:08:30 +00:00
var $dst = $new _sheet . find ( '.oe_form_sheet' ) ;
2012-05-30 09:34:46 +00:00
$sheet . contents ( ) . appendTo ( $dst ) ;
2012-04-24 10:37:12 +00:00
$sheet . before ( $new _sheet ) . remove ( ) ;
2012-05-31 09:08:30 +00:00
this . process ( $new _sheet ) ;
2012-04-10 10:29:51 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _form : function ( $form ) {
2012-06-04 11:44:33 +00:00
if ( $form . find ( '> sheet' ) . length === 0 ) {
2012-06-04 10:11:45 +00:00
$form . addClass ( 'oe_form_nosheet' ) ;
}
2012-05-31 09:08:30 +00:00
var $new _form = this . render _element ( 'FormRenderingForm' , $form . getAttributes ( ) ) ;
2012-04-24 10:37:12 +00:00
this . handle _common _properties ( $new _form , $form ) ;
2012-05-31 09:08:30 +00:00
$form . contents ( ) . appendTo ( $new _form ) ;
2012-03-21 15:57:22 +00:00
if ( $form [ 0 ] === this . $form [ 0 ] ) {
// If root element, replace it
this . $form = $new _form ;
2012-03-21 10:53:36 +00:00
} else {
2012-03-21 15:57:22 +00:00
$form . before ( $new _form ) . remove ( ) ;
2012-03-21 10:53:36 +00:00
}
2012-05-31 09:08:30 +00:00
this . process ( $new _form ) ;
2012-03-21 10:53:36 +00:00
} ,
2012-05-28 17:21:14 +00:00
/ *
* Used by direct < field > children of a < group > tag only
* This method will add the implicit < label ... > for every field
* in the < group >
* /
2012-03-20 15:18:01 +00:00
preprocess _field : function ( $field ) {
2012-04-10 13:17:46 +00:00
var self = this ;
2012-03-14 17:09:49 +00:00
var name = $field . attr ( 'name' ) ,
2012-03-26 16:29:34 +00:00
field _colspan = parseInt ( $field . attr ( 'colspan' ) , 10 ) ,
field _modifiers = JSON . parse ( $field . attr ( 'modifiers' ) || '{}' ) ;
2012-04-10 10:29:51 +00:00
2012-03-27 12:21:54 +00:00
if ( $field . attr ( 'nolabel' ) === '1' )
return ;
$field . attr ( 'nolabel' , '1' ) ;
var found = false ;
this . $form . find ( 'label[for="' + name + '"]' ) . each ( function ( i , el ) {
2012-04-10 13:17:46 +00:00
$ ( el ) . parents ( ) . each ( function ( unused , tag ) {
2012-04-10 13:20:31 +00:00
var name = tag . tagName . toLowerCase ( ) ;
if ( name === "field" || name in self . tags _registry . map )
2012-04-10 13:17:46 +00:00
found = true ;
} ) ;
2012-03-27 12:21:54 +00:00
} ) ;
if ( found )
return ;
2012-04-10 10:29:51 +00:00
2012-06-27 10:01:51 +00:00
var $label = $ ( '<label/>' ) . attr ( {
2012-03-27 12:21:54 +00:00
'for' : name ,
"modifiers" : JSON . stringify ( { invisible : field _modifiers . invisible } ) ,
"string" : $field . attr ( 'string' ) ,
"help" : $field . attr ( 'help' ) ,
2012-06-05 12:53:32 +00:00
"class" : $field . attr ( 'class' ) ,
2012-03-27 12:21:54 +00:00
} ) ;
$label . insertBefore ( $field ) ;
if ( field _colspan > 1 ) {
$field . attr ( 'colspan' , field _colspan - 1 ) ;
2012-03-20 15:18:01 +00:00
}
2012-03-27 12:21:54 +00:00
return $label ;
2012-03-20 15:18:01 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _field : function ( $field ) {
2012-05-29 15:10:55 +00:00
if ( $field . parent ( ) . is ( 'group' ) ) {
// No implicit labels for normal fields, only for <group> direct children
var $label = this . preprocess _field ( $field ) ;
if ( $label ) {
2012-05-31 09:08:30 +00:00
this . process ( $label ) ;
2012-05-29 15:10:55 +00:00
}
}
2012-04-10 13:04:44 +00:00
this . fields _to _init . push ( $field ) ;
2012-03-20 15:18:01 +00:00
return $field ;
2012-03-14 17:09:49 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _group : function ( $group ) {
2012-03-20 11:05:29 +00:00
var self = this ;
2012-03-20 15:18:01 +00:00
$group . children ( 'field' ) . each ( function ( ) {
self . preprocess _field ( $ ( this ) ) ;
2012-03-20 11:05:29 +00:00
} ) ;
2012-05-31 09:08:30 +00:00
var $new _group = this . render _element ( 'FormRenderingGroup' , $group . getAttributes ( ) ) ;
2012-05-29 15:10:55 +00:00
var $table ;
if ( $new _group . first ( ) . is ( 'table.oe_form_group' ) ) {
2012-03-14 17:09:49 +00:00
$table = $new _group ;
2012-05-29 15:10:55 +00:00
} else if ( $new _group . filter ( 'table.oe_form_group' ) . length ) {
$table = $new _group . filter ( 'table.oe_form_group' ) . first ( ) ;
2012-03-14 17:09:49 +00:00
} else {
2012-05-29 15:10:55 +00:00
$table = $new _group . find ( 'table.oe_form_group' ) . first ( ) ;
2012-03-14 17:09:49 +00:00
}
2012-05-28 17:21:14 +00:00
2012-03-26 09:44:18 +00:00
var $tr , $td ,
2012-06-01 15:32:11 +00:00
cols = parseInt ( $group . attr ( 'col' ) || 2 , 10 ) ,
2012-03-14 17:09:49 +00:00
row _cols = cols ;
2012-03-20 13:19:39 +00:00
var children = [ ] ;
2012-03-26 09:44:18 +00:00
$group . children ( ) . each ( function ( a , b , c ) {
2012-04-25 14:23:36 +00:00
var $child = $ ( this ) ;
var colspan = parseInt ( $child . attr ( 'colspan' ) || 1 , 10 ) ;
var tagName = $child [ 0 ] . tagName . toLowerCase ( ) ;
var $td = $ ( '<td/>' ) . addClass ( 'oe_form_group_cell' ) . attr ( 'colspan' , colspan ) ;
var newline = tagName === 'newline' ;
2012-05-28 17:21:14 +00:00
2012-05-29 15:10:55 +00:00
// Note FME: those classes are used in layout debug mode
2012-04-25 14:23:36 +00:00
if ( $tr && row _cols > 0 && ( newline || row _cols < colspan ) ) {
$tr . addClass ( 'oe_form_group_row_incomplete' ) ;
if ( newline ) {
$tr . addClass ( 'oe_form_group_row_newline' ) ;
}
}
if ( newline ) {
2012-03-14 17:09:49 +00:00
$tr = null ;
return ;
}
if ( ! $tr || row _cols < colspan ) {
$tr = $ ( '<tr/>' ) . addClass ( 'oe_form_group_row' ) . appendTo ( $table ) ;
row _cols = cols ;
2012-07-10 07:31:45 +00:00
} else if ( tagName === 'group' ) {
// When <group> <group/><group/> </group>, we need a spacing between the two groups
2013-07-25 10:33:01 +00:00
$td . addClass ( 'oe_group_right' ) ;
2012-03-14 17:09:49 +00:00
}
row _cols -= colspan ;
2012-04-10 10:29:51 +00:00
2012-03-26 16:49:05 +00:00
// invisibility transfer
2012-03-27 09:39:38 +00:00
var field _modifiers = JSON . parse ( $child . attr ( 'modifiers' ) || '{}' ) ;
var invisible = field _modifiers . invisible ;
2012-03-29 09:55:24 +00:00
self . handle _common _properties ( $td , $ ( "<dummy>" ) . attr ( "modifiers" , JSON . stringify ( { invisible : invisible } ) ) ) ;
2012-04-10 10:29:51 +00:00
2012-03-14 17:09:49 +00:00
$tr . append ( $td . append ( $child ) ) ;
2012-03-20 13:19:39 +00:00
children . push ( $child [ 0 ] ) ;
2012-03-14 17:09:49 +00:00
} ) ;
2012-03-27 10:18:32 +00:00
if ( row _cols && $td ) {
2012-03-26 09:44:18 +00:00
$td . attr ( 'colspan' , parseInt ( $td . attr ( 'colspan' ) , 10 ) + row _cols ) ;
}
2012-03-14 17:09:49 +00:00
$group . before ( $new _group ) . remove ( ) ;
2012-03-15 21:58:10 +00:00
2012-04-10 13:04:20 +00:00
$table . find ( '> tbody > tr' ) . each ( function ( ) {
2012-03-15 19:32:45 +00:00
var to _compute = [ ] ,
2012-03-20 12:06:21 +00:00
row _cols = cols ,
2012-03-15 19:32:45 +00:00
total = 100 ;
2012-03-15 21:58:10 +00:00
$ ( this ) . children ( ) . each ( function ( ) {
2012-03-15 19:32:45 +00:00
var $td = $ ( this ) ,
$child = $td . children ( ':first' ) ;
2013-05-01 05:41:29 +00:00
if ( $child . attr ( 'cell-class' ) ) {
$td . addClass ( $child . attr ( 'cell-class' ) ) ;
}
2012-03-15 19:32:45 +00:00
switch ( $child [ 0 ] . tagName . toLowerCase ( ) ) {
case 'separator' :
break ;
case 'label' :
if ( $child . attr ( 'for' ) ) {
2012-04-24 09:03:50 +00:00
$td . attr ( 'width' , '1%' ) . addClass ( 'oe_form_group_cell_label' ) ;
2012-06-04 20:44:49 +00:00
row _cols -= $td . attr ( 'colspan' ) || 1 ;
2012-03-15 19:32:45 +00:00
total -- ;
}
break ;
default :
2012-04-19 15:33:41 +00:00
var width = _ . str . trim ( $child . attr ( 'width' ) || '' ) ,
iwidth = parseInt ( width , 10 ) ;
if ( iwidth ) {
if ( width . substr ( - 1 ) === '%' ) {
total -= iwidth ;
width = iwidth + '%' ;
2012-05-03 14:30:43 +00:00
} else {
// Absolute width
$td . css ( 'min-width' , width + 'px' ) ;
2012-04-19 15:33:41 +00:00
}
$td . attr ( 'width' , width ) ;
$child . removeAttr ( 'width' ) ;
2012-06-04 21:00:31 +00:00
row _cols -= $td . attr ( 'colspan' ) || 1 ;
2012-04-19 15:33:41 +00:00
} else {
to _compute . push ( $td ) ;
}
2012-03-15 19:32:45 +00:00
}
} ) ;
2012-06-04 21:00:31 +00:00
if ( row _cols ) {
var unit = Math . floor ( total / row _cols ) ;
if ( ! $ ( this ) . is ( '.oe_form_group_row_incomplete' ) ) {
_ . each ( to _compute , function ( $td , i ) {
var width = parseInt ( $td . attr ( 'colspan' ) , 10 ) * unit ;
$td . attr ( 'width' , width + '%' ) ;
total -= width ;
} ) ;
}
2012-04-25 14:23:36 +00:00
}
2012-03-15 21:58:10 +00:00
} ) ;
2012-03-20 13:19:39 +00:00
_ . each ( children , function ( el ) {
2012-03-20 15:18:01 +00:00
self . process ( $ ( el ) ) ;
2012-03-20 13:19:39 +00:00
} ) ;
2012-03-29 09:55:24 +00:00
this . handle _common _properties ( $new _group , $group ) ;
2012-03-20 15:04:57 +00:00
return $new _group ;
2012-03-15 19:32:45 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _notebook : function ( $notebook ) {
2012-03-20 11:05:29 +00:00
var self = this ;
2012-03-15 10:53:24 +00:00
var pages = [ ] ;
$notebook . find ( '> page' ) . each ( function ( ) {
2012-04-01 21:55:07 +00:00
var $page = $ ( this ) ;
var page _attrs = $page . getAttributes ( ) ;
2012-03-15 10:53:24 +00:00
page _attrs . id = _ . uniqueId ( 'notebook_page_' ) ;
2012-05-31 09:08:30 +00:00
var $new _page = self . render _element ( 'FormRenderingNotebookPage' , page _attrs ) ;
$page . contents ( ) . appendTo ( $new _page ) ;
2012-03-15 10:53:24 +00:00
$page . before ( $new _page ) . remove ( ) ;
2012-06-07 10:41:23 +00:00
var ic = self . handle _common _properties ( $new _page , $page ) . invisibility _changer ;
page _attrs . _ _page = $new _page ;
page _attrs . _ _ic = ic ;
pages . push ( page _attrs ) ;
2012-07-12 12:56:37 +00:00
2012-06-07 10:41:23 +00:00
$new _page . children ( ) . each ( function ( ) {
self . process ( $ ( this ) ) ;
} ) ;
2012-03-15 10:53:24 +00:00
} ) ;
2012-05-31 09:08:30 +00:00
var $new _notebook = this . render _element ( 'FormRenderingNotebook' , { pages : pages } ) ;
2012-05-30 09:34:46 +00:00
$notebook . contents ( ) . appendTo ( $new _notebook ) ;
2012-03-15 10:53:24 +00:00
$notebook . before ( $new _notebook ) . remove ( ) ;
2012-06-07 10:41:23 +00:00
self . process ( $ ( $new _notebook . children ( ) [ 0 ] ) ) ;
//tabs and invisibility handling
2012-03-15 10:53:24 +00:00
$new _notebook . tabs ( ) ;
2012-06-07 10:41:23 +00:00
_ . each ( pages , function ( page , i ) {
if ( ! page . _ _ic )
return ;
page . _ _ic . on ( "change:effective_invisible" , null , function ( ) {
2013-05-01 05:41:29 +00:00
if ( ! page . _ _ic . get ( 'effective_invisible' ) && page . autofocus ) {
2012-09-12 12:32:36 +00:00
$new _notebook . tabs ( 'select' , i ) ;
return ;
}
2012-06-07 10:41:23 +00:00
var current = $new _notebook . tabs ( "option" , "selected" ) ;
if ( ! pages [ current ] . _ _ic || ! pages [ current ] . _ _ic . get ( "effective_invisible" ) )
return ;
var first _visible = _ . find ( _ . range ( pages . length ) , function ( i2 ) {
return ( ! pages [ i2 ] . _ _ic ) || ( ! pages [ i2 ] . _ _ic . get ( "effective_invisible" ) ) ;
} ) ;
if ( first _visible !== undefined ) {
$new _notebook . tabs ( 'select' , first _visible ) ;
}
} ) ;
} ) ;
2012-07-12 12:56:37 +00:00
2012-03-29 09:55:24 +00:00
this . handle _common _properties ( $new _notebook , $notebook ) ;
2012-03-20 15:04:57 +00:00
return $new _notebook ;
2012-03-14 17:09:49 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _separator : function ( $separator ) {
var $new _separator = this . render _element ( 'FormRenderingSeparator' , $separator . getAttributes ( ) ) ;
2012-03-15 14:16:22 +00:00
$separator . before ( $new _separator ) . remove ( ) ;
2012-03-29 09:55:24 +00:00
this . handle _common _properties ( $new _separator , $separator ) ;
2012-03-20 15:04:57 +00:00
return $new _separator ;
2012-03-14 17:09:49 +00:00
} ,
2012-05-31 09:08:30 +00:00
process _label : function ( $label ) {
2012-03-27 12:21:54 +00:00
var name = $label . attr ( "for" ) ,
field _orm = this . fvg . fields [ name ] ;
var dict = {
2012-03-27 14:31:33 +00:00
string : $label . attr ( 'string' ) || ( field _orm || { } ) . string || '' ,
help : $label . attr ( 'help' ) || ( field _orm || { } ) . help || '' ,
2012-03-29 15:01:36 +00:00
_for : name ? _ . uniqueId ( 'oe-field-input-' ) : undefined ,
2012-03-27 12:21:54 +00:00
} ;
2012-03-19 10:29:04 +00:00
var align = parseFloat ( dict . align ) ;
if ( isNaN ( align ) || align === 1 ) {
align = 'right' ;
} else if ( align === 0 ) {
align = 'left' ;
} else {
align = 'center' ;
}
dict . align = align ;
2012-05-31 09:08:30 +00:00
var $new _label = this . render _element ( 'FormRenderingLabel' , dict ) ;
2012-03-14 17:09:49 +00:00
$label . before ( $new _label ) . remove ( ) ;
2012-03-29 09:55:24 +00:00
this . handle _common _properties ( $new _label , $label ) ;
2012-03-29 15:01:36 +00:00
if ( name ) {
this . labels [ name ] = $new _label ;
}
2012-03-20 15:04:57 +00:00
return $new _label ;
2012-03-26 15:14:37 +00:00
} ,
2012-04-10 12:21:10 +00:00
handle _common _properties : function ( $new _element , $node ) {
2012-06-27 10:01:51 +00:00
var str _modifiers = $node . attr ( "modifiers" ) || "{}" ;
2012-03-29 09:55:24 +00:00
var modifiers = JSON . parse ( str _modifiers ) ;
2012-06-07 10:41:23 +00:00
var ic = null ;
2012-03-29 09:55:24 +00:00
if ( modifiers . invisible !== undefined )
2012-06-07 10:41:23 +00:00
ic = new instance . web . form . InvisibilityChanger ( this . view , this . view , modifiers . invisible , $new _element ) ;
2012-04-10 12:21:10 +00:00
$new _element . addClass ( $node . attr ( "class" ) || "" ) ;
2012-04-24 12:22:49 +00:00
$new _element . attr ( 'style' , $node . attr ( 'style' ) ) ;
2012-06-07 10:41:23 +00:00
return { invisibility _changer : ic , } ;
2012-03-26 16:29:34 +00:00
} ,
2012-03-14 17:09:49 +00:00
} ) ;
2012-10-04 16:14:33 +00:00
/ * *
Welcome .
If you read this documentation , it probably means that you were asked to use a form view widget outside of
a form view . Before going further , you must understand that those fields were never really created for
that usage . Don ' t think that this class will hold the answer to all your problems , at best it will allow
you to hack the system with more style .
* /
2012-10-04 16:29:28 +00:00
instance . web . form . DefaultFieldManager = instance . web . Widget . extend ( {
2012-10-04 16:14:33 +00:00
init : function ( parent , eval _context ) {
this . _super ( parent ) ;
this . field _descs = { } ;
this . eval _context = eval _context || { } ;
2012-10-05 10:12:35 +00:00
this . set ( {
display _invalid _fields : false ,
actual _mode : 'create' ,
} ) ;
2012-10-04 16:14:33 +00:00
} ,
get _field _desc : function ( field _name ) {
if ( this . field _descs [ field _name ] === undefined ) {
this . field _descs [ field _name ] = {
2012-10-04 16:29:28 +00:00
string : field _name ,
2012-10-04 16:14:33 +00:00
} ;
}
return this . field _descs [ field _name ] ;
} ,
2012-10-04 16:29:28 +00:00
extend _field _desc : function ( fields ) {
var self = this ;
_ . each ( fields , function ( v , k ) {
_ . extend ( self . get _field _desc ( k ) , v ) ;
} ) ;
} ,
2012-10-04 16:14:33 +00:00
get _field _value : function ( field _name ) {
return false ;
} ,
set _values : function ( values ) {
// nothing
} ,
compute _domain : function ( expression ) {
return instance . web . form . compute _domain ( expression , { } ) ;
} ,
build _eval _context : function ( ) {
return new instance . web . CompoundContext ( this . eval _context ) ;
} ,
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . compute _domain = function ( expr , fields ) {
2012-10-12 09:06:44 +00:00
if ( ! ( expr instanceof Array ) )
return ! ! expr ;
2011-04-11 17:36:43 +00:00
var stack = [ ] ;
2011-04-11 17:50:25 +00:00
for ( var i = expr . length - 1 ; i >= 0 ; i -- ) {
2011-04-11 17:36:43 +00:00
var ex = expr [ i ] ;
if ( ex . length == 1 ) {
2011-04-11 17:50:25 +00:00
var top = stack . pop ( ) ;
2011-05-17 09:35:03 +00:00
switch ( ex ) {
2011-04-11 17:50:25 +00:00
case '|' :
stack . push ( stack . pop ( ) || top ) ;
continue ;
case '&' :
stack . push ( stack . pop ( ) && top ) ;
continue ;
case '!' :
stack . push ( ! top ) ;
continue ;
default :
2012-02-03 08:48:52 +00:00
throw new Error ( _ . str . sprintf (
_t ( "Unknown operator %s in domain %s" ) ,
ex , JSON . stringify ( expr ) ) ) ;
2011-04-11 17:50:25 +00:00
}
2011-04-11 17:36:43 +00:00
}
2011-08-10 15:42:38 +00:00
var field = fields [ ex [ 0 ] ] ;
if ( ! field ) {
2012-02-03 08:48:52 +00:00
throw new Error ( _ . str . sprintf (
_t ( "Unknown field %s in domain %s" ) ,
ex [ 0 ] , JSON . stringify ( expr ) ) ) ;
2011-08-10 15:42:38 +00:00
}
2012-04-18 09:16:13 +00:00
var field _value = field . get _value ? field . get _value ( ) : field . value ;
2011-04-11 17:36:43 +00:00
var op = ex [ 1 ] ;
var val = ex [ 2 ] ;
switch ( op . toLowerCase ( ) ) {
case '=' :
case '==' :
2012-09-14 13:46:04 +00:00
stack . push ( _ . isEqual ( field _value , val ) ) ;
2011-04-11 17:36:43 +00:00
break ;
case '!=' :
case '<>' :
2012-11-28 13:41:42 +00:00
stack . push ( ! _ . isEqual ( field _value , val ) ) ;
2011-04-11 17:36:43 +00:00
break ;
case '<' :
2011-08-10 15:42:38 +00:00
stack . push ( field _value < val ) ;
2011-04-11 17:36:43 +00:00
break ;
case '>' :
2011-08-10 15:42:38 +00:00
stack . push ( field _value > val ) ;
2011-04-11 17:36:43 +00:00
break ;
case '<=' :
2011-08-10 15:42:38 +00:00
stack . push ( field _value <= val ) ;
2011-04-11 17:36:43 +00:00
break ;
case '>=' :
2011-08-10 15:42:38 +00:00
stack . push ( field _value >= val ) ;
2011-04-11 17:36:43 +00:00
break ;
case 'in' :
2012-01-16 13:25:54 +00:00
if ( ! _ . isArray ( val ) ) val = [ val ] ;
2011-08-10 15:42:38 +00:00
stack . push ( _ ( val ) . contains ( field _value ) ) ;
2011-04-11 17:36:43 +00:00
break ;
case 'not in' :
2012-01-16 13:25:54 +00:00
if ( ! _ . isArray ( val ) ) val = [ val ] ;
2011-08-10 15:42:38 +00:00
stack . push ( ! _ ( val ) . contains ( field _value ) ) ;
2011-04-11 17:36:43 +00:00
break ;
default :
2012-02-03 08:48:52 +00:00
console . warn (
_t ( "Unsupported operator %s in domain %s" ) ,
op , JSON . stringify ( expr ) ) ;
2011-04-11 17:36:43 +00:00
}
}
2011-07-14 14:29:58 +00:00
return _ . all ( stack , _ . identity ) ;
2011-05-17 09:35:03 +00:00
} ;
2011-05-11 14:49:10 +00:00
2012-12-11 10:33:57 +00:00
instance . web . form . is _bin _size = function ( v ) {
2013-07-25 10:07:49 +00:00
return ( /^\d+(\.\d*)? \w+$/ ) . test ( v ) ;
2012-12-11 10:33:57 +00:00
} ;
2012-03-26 16:29:34 +00:00
/ * *
2012-04-19 13:43:41 +00:00
* Must be applied over an class already possessing the PropertiesMixin .
2012-03-26 16:29:34 +00:00
*
2012-08-24 18:27:07 +00:00
* Apply the result of the "invisible" domain to this . $el .
2012-03-26 16:29:34 +00:00
* /
2012-04-17 12:09:49 +00:00
instance . web . form . InvisibilityChangerMixin = {
2012-03-26 16:29:34 +00:00
init : function ( field _manager , invisible _domain ) {
2012-06-27 10:01:51 +00:00
var self = this ;
this . _ic _field _manager = field _manager ;
2012-03-26 16:29:34 +00:00
this . _ic _invisible _modifier = invisible _domain ;
this . _ic _field _manager . on ( "view_content_has_changed" , this , function ( ) {
2012-06-27 10:01:51 +00:00
var result = self . _ic _invisible _modifier === undefined ? false :
2012-10-04 14:33:37 +00:00
self . _ic _field _manager . compute _domain ( self . _ic _invisible _modifier ) ;
2012-06-27 10:01:51 +00:00
self . set ( { "invisible" : result } ) ;
2012-03-26 16:29:34 +00:00
} ) ;
2012-05-02 14:23:32 +00:00
this . set ( { invisible : this . _ic _invisible _modifier === true , force _invisible : false } ) ;
var check = function ( ) {
2012-06-27 10:01:51 +00:00
if ( self . get ( "invisible" ) || self . get ( 'force_invisible' ) ) {
self . set ( { "effective_invisible" : true } ) ;
2012-05-02 14:23:32 +00:00
} else {
2012-06-27 10:01:51 +00:00
self . set ( { "effective_invisible" : false } ) ;
2012-05-02 14:23:32 +00:00
}
} ;
this . on ( 'change:invisible' , this , check ) ;
this . on ( 'change:force_invisible' , this , check ) ;
2012-06-27 10:01:51 +00:00
check . call ( this ) ;
2012-03-26 16:29:34 +00:00
} ,
start : function ( ) {
2012-06-05 16:16:10 +00:00
this . on ( "change:effective_invisible" , this , this . _check _visibility ) ;
this . _check _visibility ( ) ;
} ,
_check _visibility : function ( ) {
2012-08-24 18:27:07 +00:00
this . $el . toggleClass ( 'oe_form_invisible' , this . get ( "effective_invisible" ) ) ;
2012-03-26 16:29:34 +00:00
} ,
} ;
2012-06-21 23:56:41 +00:00
instance . web . form . InvisibilityChanger = instance . web . Class . extend ( instance . web . PropertiesMixin , instance . web . form . InvisibilityChangerMixin , {
2012-08-24 18:27:07 +00:00
init : function ( parent , field _manager , invisible _domain , $el ) {
2012-03-26 16:29:34 +00:00
this . setParent ( parent ) ;
2012-04-19 13:43:41 +00:00
instance . web . PropertiesMixin . init . call ( this ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . InvisibilityChangerMixin . init . call ( this , field _manager , invisible _domain ) ;
2012-08-24 18:27:07 +00:00
this . $el = $el ;
2012-03-26 16:29:34 +00:00
this . start ( ) ;
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2012-03-26 16:29:34 +00:00
2012-09-28 12:28:58 +00:00
/ * *
Base class for all fields , custom widgets and buttons to be displayed in the form view .
Properties :
- effective _readonly : when it is true , the widget is displayed as readonly . Vary depending
the values of the "readonly" property and the "mode" property on the field manager .
* /
2012-06-21 23:56:41 +00:00
instance . web . form . FormWidget = instance . web . Widget . extend ( instance . web . form . InvisibilityChangerMixin , {
2011-09-12 11:43:50 +00:00
/ * *
2012-04-26 15:28:00 +00:00
* @ constructs instance . web . form . FormWidget
2012-04-17 12:09:49 +00:00
* @ extends instance . web . Widget
2011-09-12 11:43:50 +00:00
*
2012-09-28 12:28:58 +00:00
* @ param field _manager
2011-09-12 11:43:50 +00:00
* @ param node
* /
2012-09-28 12:28:58 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager ) ;
this . field _manager = field _manager ;
2012-10-04 14:13:51 +00:00
if ( this . field _manager instanceof instance . web . FormView )
this . view = this . field _manager ;
2011-03-30 14:00:48 +00:00
this . node = node ;
2011-07-07 10:37:40 +00:00
this . modifiers = JSON . parse ( this . node . attrs . modifiers || '{}' ) ;
2012-09-28 12:28:58 +00:00
instance . web . form . InvisibilityChangerMixin . init . call ( this , this . field _manager , this . modifiers . invisible ) ;
2011-08-31 12:45:38 +00:00
2012-09-28 12:28:58 +00:00
this . field _manager . on ( "view_content_has_changed" , this , this . process _modifiers ) ;
2012-10-05 11:48:46 +00:00
this . set ( {
required : false ,
readonly : false ,
} ) ;
2012-09-28 12:28:58 +00:00
// some events to make the property "effective_readonly" sync automatically with "readonly" and
// "mode" on field_manager
var self = this ;
var test _effective _readonly = function ( ) {
self . set ( { "effective_readonly" : self . get ( "readonly" ) || self . field _manager . get ( "actual_mode" ) === "view" } ) ;
} ;
this . on ( "change:readonly" , this , test _effective _readonly ) ;
this . field _manager . on ( "change:actual_mode" , this , test _effective _readonly ) ;
test _effective _readonly . call ( this ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-03-29 09:55:24 +00:00
renderElement : function ( ) {
2012-10-05 11:48:46 +00:00
this . process _modifiers ( ) ;
2012-03-29 09:55:24 +00:00
this . _super ( ) ;
2012-08-24 18:27:07 +00:00
this . $el . addClass ( this . node . attrs [ "class" ] || "" ) ;
2012-03-29 09:55:24 +00:00
} ,
2012-02-21 16:29:12 +00:00
destroy : function ( ) {
2012-02-09 13:59:39 +00:00
$ . fn . tipsy . clear ( ) ;
2012-03-26 16:29:34 +00:00
this . _super . apply ( this , arguments ) ;
2012-01-26 14:37:34 +00:00
} ,
2012-06-25 13:52:15 +00:00
/ * *
2012-06-28 10:11:00 +00:00
* Sets up blur / focus forwarding from DOM elements to a widget ( ` this ` ) .
*
* This method is an utility method that is meant to be called by child classes .
2012-06-20 11:15:27 +00:00
*
* @ param { jQuery } $e jQuery object of elements to bind focus / blur on
* /
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
setupFocus : function ( $e ) {
var self = this ;
2012-06-25 14:40:13 +00:00
$e . on ( {
focus : function ( ) { self . trigger ( 'focused' ) ; } ,
blur : function ( ) { self . trigger ( 'blurred' ) ; }
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
} ) ;
} ,
2011-07-07 10:37:40 +00:00
process _modifiers : function ( ) {
2012-03-20 15:51:11 +00:00
var to _set = { } ;
2011-07-07 10:37:40 +00:00
for ( var a in this . modifiers ) {
2012-06-27 10:01:51 +00:00
if ( ! this . modifiers . hasOwnProperty ( a ) ) { continue ; }
2012-03-26 16:29:34 +00:00
if ( ! _ . include ( [ "invisible" ] , a ) ) {
2012-10-04 14:33:37 +00:00
var val = this . field _manager . compute _domain ( this . modifiers [ a ] ) ;
2012-03-26 16:29:34 +00:00
to _set [ a ] = val ;
}
2011-03-30 14:00:48 +00:00
}
2012-03-20 15:51:11 +00:00
this . set ( to _set ) ;
2011-10-13 09:38:14 +00:00
} ,
2011-11-14 20:59:16 +00:00
do _attach _tooltip : function ( widget , trigger , options ) {
widget = widget || this ;
2012-08-24 18:27:07 +00:00
trigger = trigger || this . $el ;
2011-11-14 20:59:16 +00:00
options = _ . extend ( {
2012-01-26 13:24:41 +00:00
delayIn : 500 ,
delayOut : 0 ,
fade : true ,
title : function ( ) {
2012-03-15 16:21:07 +00:00
var template = widget . template + '.tooltip' ;
2011-11-14 20:59:16 +00:00
if ( ! QWeb . has _template ( template ) ) {
template = 'WidgetLabel.tooltip' ;
}
return QWeb . render ( template , {
2012-08-14 15:29:00 +00:00
debug : instance . session . debug ,
2011-11-14 20:59:16 +00:00
widget : widget
2013-07-25 10:33:01 +00:00
} ) ;
} ,
2012-02-09 10:54:01 +00:00
gravity : $ . fn . tipsy . autoBounds ( 50 , 'nw' ) ,
2012-01-26 13:24:41 +00:00
html : true ,
opacity : 0.85 ,
trigger : 'hover'
2011-11-14 20:59:16 +00:00
} , options || { } ) ;
2012-04-23 11:09:07 +00:00
$ ( trigger ) . tipsy ( options ) ;
2011-11-14 20:59:16 +00:00
} ,
2011-10-13 09:38:14 +00:00
/ * *
* Builds a new context usable for operations related to fields by merging
* the fields 'context with the action' s context .
* /
2012-11-08 10:38:56 +00:00
build _context : function ( ) {
2012-01-10 14:20:55 +00:00
// only use the model's context if there is not context on the node
var v _context = this . node . attrs . context ;
if ( ! v _context ) {
v _context = ( this . field || { } ) . context || { } ;
2011-10-13 09:38:14 +00:00
}
2012-07-12 12:56:37 +00:00
2012-01-10 14:20:55 +00:00
if ( v _context . _ _ref || true ) { //TODO: remove true
2012-11-08 10:38:56 +00:00
var fields _values = this . field _manager . build _eval _context ( ) ;
2012-04-17 12:09:49 +00:00
v _context = new instance . web . CompoundContext ( v _context ) . set _eval _context ( fields _values ) ;
2011-10-13 09:38:14 +00:00
}
2012-01-10 14:20:55 +00:00
return v _context ;
2011-10-13 09:38:14 +00:00
} ,
build _domain : function ( ) {
var f _domain = this . field . domain || [ ] ;
var n _domain = this . node . attrs . domain || null ;
// if there is a domain on the node, overrides the model's domain
var final _domain = n _domain !== null ? n _domain : f _domain ;
2012-01-03 17:17:13 +00:00
if ( ! ( final _domain instanceof Array ) || true ) { //TODO: remove true
2012-10-04 14:52:06 +00:00
var fields _values = this . field _manager . build _eval _context ( ) ;
2012-04-17 12:09:49 +00:00
final _domain = new instance . web . CompoundDomain ( final _domain ) . set _eval _context ( fields _values ) ;
2011-10-13 09:38:14 +00:00
}
return final _domain ;
2011-03-30 14:00:48 +00:00
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-07-11 14:48:51 +00:00
2012-04-26 15:28:00 +00:00
instance . web . form . WidgetButton = instance . web . form . FormWidget . extend ( {
2012-03-13 15:58:52 +00:00
template : 'WidgetButton' ,
2012-09-28 12:28:58 +00:00
init : function ( field _manager , node ) {
2012-11-14 16:44:13 +00:00
node . attrs . type = node . attrs [ 'data-button-type' ] ;
2012-09-28 12:28:58 +00:00
this . _super ( field _manager , node ) ;
2011-09-30 16:15:06 +00:00
this . force _disabled = false ;
2012-03-14 17:09:49 +00:00
this . string = ( this . node . attrs . string || '' ) . replace ( /_/g , '' ) ;
2012-07-26 15:47:16 +00:00
if ( JSON . parse ( this . node . attrs . default _focus || "0" ) ) {
2011-06-20 18:25:49 +00:00
// TODO fme: provide enter key binding to widgets
this . view . default _focus _button = this ;
}
2012-07-26 00:58:35 +00:00
if ( this . node . attrs . icon && ( ! /\// . test ( this . node . attrs . icon ) ) ) {
this . node . attrs . icon = '/web/static/src/img/icons/' + this . node . attrs . icon + '.png' ;
}
2011-04-11 15:59:46 +00:00
} ,
start : function ( ) {
this . _super . apply ( this , arguments ) ;
2013-03-12 17:05:15 +00:00
this . view . on ( 'view_content_has_changed' , this , this . check _disable ) ;
this . check _disable ( ) ;
2012-08-24 18:27:07 +00:00
this . $el . click ( this . on _click ) ;
2012-08-14 15:29:00 +00:00
if ( this . node . attrs . help || instance . session . debug ) {
2011-11-14 20:59:16 +00:00
this . do _attach _tooltip ( ) ;
}
2012-08-24 18:27:07 +00:00
this . setupFocus ( this . $el ) ;
2011-04-11 15:59:46 +00:00
} ,
2011-09-26 12:39:29 +00:00
on _click : function ( ) {
2011-09-30 16:15:06 +00:00
var self = this ;
this . force _disabled = true ;
this . check _disable ( ) ;
this . execute _action ( ) . always ( function ( ) {
self . force _disabled = false ;
self . check _disable ( ) ;
} ) ;
} ,
execute _action : function ( ) {
2011-04-11 15:59:46 +00:00
var self = this ;
2011-09-26 12:39:29 +00:00
var exec _action = function ( ) {
if ( self . node . attrs . confirm ) {
2011-09-30 16:15:06 +00:00
var def = $ . Deferred ( ) ;
2012-04-17 12:09:49 +00:00
var dialog = instance . web . dialog ( $ ( '<div/>' ) . text ( self . node . attrs . confirm ) , {
2011-12-15 10:06:52 +00:00
title : _t ( 'Confirm' ) ,
2011-04-11 15:59:46 +00:00
modal : true ,
2011-12-15 10:40:31 +00:00
buttons : [
2012-01-17 15:33:33 +00:00
{ text : _t ( "Cancel" ) , click : function ( ) {
$ ( this ) . dialog ( "close" ) ;
}
} ,
2011-12-15 10:40:31 +00:00
{ text : _t ( "Ok" ) , click : function ( ) {
2013-03-01 14:00:15 +00:00
var self2 = this ;
self . on _confirmed ( ) . always ( function ( ) {
$ ( self2 ) . dialog ( "close" ) ;
2011-12-15 10:40:31 +00:00
} ) ;
}
2011-04-11 15:59:46 +00:00
}
2013-03-01 14:00:15 +00:00
] ,
beforeClose : function ( ) {
def . resolve ( ) ;
} ,
2011-04-11 15:59:46 +00:00
} ) ;
2011-09-30 16:15:06 +00:00
return def . promise ( ) ;
2011-04-11 15:59:46 +00:00
} else {
2011-09-30 16:15:06 +00:00
return self . on _confirmed ( ) ;
2011-04-11 15:59:46 +00:00
}
2011-09-26 12:39:29 +00:00
} ;
2011-10-12 14:10:07 +00:00
if ( ! this . node . attrs . special ) {
2012-10-30 14:06:30 +00:00
return this . view . recursive _save ( ) . then ( exec _action ) ;
2011-09-26 12:39:29 +00:00
} else {
2011-09-30 16:15:06 +00:00
return exec _action ( ) ;
2011-04-11 15:59:46 +00:00
}
} ,
on _confirmed : function ( ) {
2011-05-04 09:12:33 +00:00
var self = this ;
2011-10-19 12:50:34 +00:00
2012-07-23 13:49:14 +00:00
var context = this . build _context ( ) ;
2011-05-04 09:12:33 +00:00
2011-09-30 16:15:06 +00:00
return this . view . do _execute _action (
2011-10-13 09:38:14 +00:00
_ . extend ( { } , this . node . attrs , { context : context } ) ,
this . view . dataset , this . view . datarecord . id , function ( ) {
2012-09-24 12:53:55 +00:00
self . view . recursive _reload ( ) ;
2011-04-12 15:09:55 +00:00
} ) ;
2011-09-30 15:46:12 +00:00
} ,
2011-09-30 16:15:06 +00:00
check _disable : function ( ) {
2012-03-20 15:51:11 +00:00
var disabled = ( this . force _disabled || ! this . view . is _interactible _record ( ) ) ;
2012-08-24 18:27:07 +00:00
this . $el . prop ( 'disabled' , disabled ) ;
this . $el . css ( 'color' , disabled ? 'grey' : '' ) ;
2011-03-30 14:00:48 +00:00
}
} ) ;
2012-03-13 16:37:19 +00:00
/ * *
* Interface to be implemented by fields .
2012-07-12 12:56:37 +00:00
*
2012-03-15 16:43:26 +00:00
* Events :
2012-09-24 16:30:21 +00:00
* - changed _value : triggered when the value of the field has changed . This can be due
* to a user interaction or a call to set _value ( ) .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* /
2012-06-21 23:56:41 +00:00
instance . web . form . FieldInterface = {
2012-03-15 16:43:26 +00:00
/ * *
* Constructor takes 2 arguments :
2012-05-02 09:18:47 +00:00
* - field _manager : Implements FieldManagerMixin
2012-03-15 16:43:26 +00:00
* - node : the "<field>" node in json form
* /
init : function ( field _manager , node ) { } ,
2012-03-13 16:37:19 +00:00
/ * *
* Called by the form view to indicate the value of the field .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* Multiple calls to set _value ( ) can occur at any time and must be handled correctly by the implementation ,
2012-10-12 12:37:13 +00:00
* regardless of any asynchronous operation currently running . Calls to set _value ( ) can and will also occur
* before the widget is inserted into the DOM .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* set _value ( ) must be able , at any moment , to handle the syntax returned by the "read" method of the
* osv class in the OpenERP server as well as the syntax used by the set _value ( ) ( see below ) . It must
* also be able to handle any other format commonly used in the _defaults key on the models in the addons
* as well as any format commonly returned in a on _change . It must be able to autodetect those formats as
* no information is ever given to know which format is used .
* /
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) { } ,
2012-03-13 16:37:19 +00:00
/ * *
* Get the current value of the widget .
2012-07-12 12:56:37 +00:00
*
2012-06-27 10:01:51 +00:00
* Must always return a syntactically correct value to be passed to the "write" method of the osv class in
2012-03-13 16:37:19 +00:00
* the OpenERP server , although it is not assumed to respect the constraints applied to the field .
2012-06-27 10:01:51 +00:00
* For example if the field is marked as "required" , a call to get _value ( ) can return false .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* get _value ( ) can also be called * before * a call to set _value ( ) and , in that case , is supposed to
2012-06-27 10:01:51 +00:00
* return a default value according to the type of field .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* This method is always assumed to perform synchronously , it can not return a promise .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* If there was no user interaction to modify the value of the field , it is always assumed that
* get _value ( ) return the same semantic value than the one passed in the last call to set _value ( ) ,
2012-06-27 10:01:51 +00:00
* although the syntax can be different . This can be the case for type of fields that have a different
2012-03-13 16:37:19 +00:00
* syntax for "read" and "write" ( example : m2o : set _value ( [ 0 , "Administrator" ] ) , get _value ( ) => 0 ) .
* /
get _value : function ( ) { } ,
2012-03-27 12:47:04 +00:00
/ * *
* Inform the current object of the id it should use to match a html < label > that exists somewhere in the
* view .
* /
2012-04-18 11:50:04 +00:00
set _input _id : function ( id ) { } ,
2012-04-18 13:05:40 +00:00
/ * *
* Returns true if is _syntax _valid ( ) returns true and the value is semantically
* valid too according to the semantic restrictions applied to the field .
* /
2012-04-18 11:50:04 +00:00
is _valid : function ( ) { } ,
2012-04-18 13:05:40 +00:00
/ * *
2012-06-27 10:01:51 +00:00
* Returns true if the field holds a value which is syntactically correct , ignoring
2012-04-18 13:05:40 +00:00
* the potential semantic restrictions applied to the field .
* /
2012-04-18 11:50:04 +00:00
is _syntax _valid : function ( ) { } ,
2012-04-18 13:05:40 +00:00
/ * *
2012-06-28 13:02:49 +00:00
* Must set the focus on the field . Return false if field is not focusable .
2012-04-18 13:05:40 +00:00
* /
2012-04-18 12:37:04 +00:00
focus : function ( ) { } ,
2012-08-30 16:12:37 +00:00
/ * *
* Called when the translate button is clicked .
* /
2012-09-28 10:23:50 +00:00
on _translate : function ( ) { } ,
2012-11-05 11:16:35 +00:00
/ * *
This method is called by the form view before reading on _change values and before saving . It tells
2012-11-05 15:05:40 +00:00
the field to save its value before reading it using get _value ( ) . Must return a promise .
2012-11-05 11:16:35 +00:00
* /
commit _value : function ( ) { } ,
2012-03-13 16:37:19 +00:00
} ;
/ * *
2012-06-21 23:56:41 +00:00
* Abstract class for classes implementing FieldInterface .
2012-07-12 12:56:37 +00:00
*
2012-03-15 16:43:26 +00:00
* Properties :
2012-04-18 13:05:40 +00:00
* - value : useful property to hold the value of the field . By default , set _value ( ) and get _value ( )
* set and retrieve the value property . Changing the value property also triggers automatically
* a 'changed_value' event that inform the view to trigger on _changes .
2012-07-12 12:56:37 +00:00
*
2012-03-13 16:37:19 +00:00
* /
2012-06-21 23:56:41 +00:00
instance . web . form . AbstractField = instance . web . form . FormWidget . extend ( instance . web . form . FieldInterface , {
2011-09-12 11:43:50 +00:00
/ * *
2012-04-17 12:09:49 +00:00
* @ constructs instance . web . form . AbstractField
2012-04-26 15:28:00 +00:00
* @ extends instance . web . form . FormWidget
2011-09-12 11:43:50 +00:00
*
2012-03-15 16:43:26 +00:00
* @ param field _manager
2011-09-12 11:43:50 +00:00
* @ param node
* /
2012-03-15 16:43:26 +00:00
init : function ( field _manager , node ) {
2013-07-25 10:33:01 +00:00
var self = this ;
2012-03-15 16:43:26 +00:00
this . _super ( field _manager , node ) ;
2012-03-14 17:09:49 +00:00
this . name = this . node . attrs . name ;
2012-10-04 15:34:00 +00:00
this . field = this . field _manager . get _field _desc ( this . name ) ;
2012-06-27 15:17:59 +00:00
this . widget = this . node . attrs . widget ;
2012-06-29 15:02:25 +00:00
this . string = this . node . attrs . string || this . field . string || this . name ;
2012-10-11 12:57:48 +00:00
this . options = instance . web . py _eval ( this . node . attrs . options || '{}' ) ;
2012-06-27 15:17:59 +00:00
this . set ( { 'value' : false } ) ;
2012-07-12 12:56:37 +00:00
2012-04-17 15:45:05 +00:00
this . on ( "change:value" , this , function ( ) {
2012-09-24 16:07:21 +00:00
this . trigger ( 'changed_value' ) ;
2012-04-18 12:23:41 +00:00
this . _check _css _flags ( ) ;
2012-04-18 12:20:39 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-05-02 11:42:15 +00:00
renderElement : function ( ) {
2012-05-09 12:56:42 +00:00
var self = this ;
2012-05-02 11:42:15 +00:00
this . _super ( ) ;
2012-10-04 14:13:51 +00:00
if ( this . field . translate && this . view ) {
2012-08-24 18:27:07 +00:00
this . $el . addClass ( 'oe_form_field_translatable' ) ;
2012-08-30 16:12:37 +00:00
this . $el . find ( '.oe_field_translate' ) . click ( this . on _translate ) ;
2011-08-24 15:13:57 +00:00
}
2012-10-04 14:13:51 +00:00
this . $label = this . view ? this . view . $el . find ( 'label[for=' + this . id _for _label + ']' ) : $ ( ) ;
2012-08-14 15:29:00 +00:00
if ( instance . session . debug ) {
2012-08-24 18:27:07 +00:00
this . do _attach _tooltip ( this , this . $label [ 0 ] || this . $el ) ;
2012-05-09 12:56:42 +00:00
this . $label . off ( 'dblclick' ) . on ( 'dblclick' , function ( ) {
console . log ( "Field '%s' of type '%s' in View: %o" , self . name , ( self . node . attrs . widget || self . field . type ) , self . view ) ;
window . w = self ;
console . log ( "window.w =" , window . w ) ;
} ) ;
2011-11-14 20:59:16 +00:00
}
2012-03-27 13:02:54 +00:00
if ( ! this . disable _utility _classes ) {
2012-05-02 11:42:15 +00:00
this . off ( "change:required" , this , this . _set _required ) ;
this . on ( "change:required" , this , this . _set _required ) ;
this . _set _required ( ) ;
2012-03-27 13:02:54 +00:00
}
2012-06-05 16:16:10 +00:00
this . _check _visibility ( ) ;
2012-10-08 12:25:52 +00:00
this . field _manager . off ( "change:display_invalid_fields" , this , this . _check _css _flags ) ;
this . field _manager . on ( "change:display_invalid_fields" , this , this . _check _css _flags ) ;
2012-06-05 16:16:10 +00:00
this . _check _css _flags ( ) ;
2011-08-24 15:13:57 +00:00
} ,
2012-10-11 15:21:40 +00:00
start : function ( ) {
var tmp = this . _super ( ) ;
this . on ( "change:value" , this , function ( ) {
if ( ! this . no _rerender )
2012-10-11 16:09:02 +00:00
this . render _value ( ) ;
2012-10-11 15:21:40 +00:00
} ) ;
2012-10-11 16:09:02 +00:00
this . render _value ( ) ;
2012-10-11 15:21:40 +00:00
} ,
2012-05-02 11:42:15 +00:00
/ * *
* Private . Do not use .
* /
_set _required : function ( ) {
2012-08-24 18:27:07 +00:00
this . $el . toggleClass ( 'oe_form_required' , this . get ( "required" ) ) ;
2012-05-02 11:42:15 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
this . set ( { 'value' : value _ } ) ;
2011-08-24 15:13:57 +00:00
} ,
2011-04-05 14:34:25 +00:00
get _value : function ( ) {
2012-04-17 14:32:27 +00:00
return this . get ( 'value' ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-10-11 15:21:40 +00:00
/ * *
Utility method that all implementations should use to change the
value without triggering a re - rendering .
* /
internal _set _value : function ( value _ ) {
2013-05-01 05:41:29 +00:00
var tmp = this . no _rerender ;
2012-10-11 15:21:40 +00:00
this . no _rerender = true ;
this . set ( { 'value' : value _ } ) ;
this . no _rerender = tmp ;
} ,
/ * *
This method is called each time the value is modified .
* /
render _value : function ( ) { } ,
2011-07-27 10:25:19 +00:00
is _valid : function ( ) {
2012-06-25 13:52:15 +00:00
return this . is _syntax _valid ( ) && ! ( this . get ( 'required' ) && this . is _false ( ) ) ;
2011-07-27 10:25:19 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _syntax _valid : function ( ) {
2012-04-18 09:16:13 +00:00
return true ;
2011-07-27 10:25:19 +00:00
} ,
2012-04-18 13:05:40 +00:00
/ * *
* Method useful to implement to ease validity testing . Must return true if the current
* value is similar to false in OpenERP .
* /
2012-04-18 09:50:43 +00:00
is _false : function ( ) {
return this . get ( 'value' ) === false ;
2011-06-29 16:21:36 +00:00
} ,
2012-06-28 14:36:16 +00:00
_check _css _flags : function ( ) {
2011-08-29 14:08:39 +00:00
if ( this . field . translate ) {
2012-09-28 12:54:14 +00:00
this . $el . find ( '.oe_field_translate' ) . toggle ( this . field _manager . get ( 'actual_mode' ) !== "create" ) ;
2011-08-29 14:08:39 +00:00
}
2011-07-27 09:09:05 +00:00
if ( ! this . disable _utility _classes ) {
2012-04-18 12:20:39 +00:00
if ( this . field _manager . get ( 'display_invalid_fields' ) ) {
2012-08-24 18:27:07 +00:00
this . $el . toggleClass ( 'oe_form_invalid' , ! this . is _valid ( ) ) ;
2011-07-27 09:09:05 +00:00
}
2011-04-11 11:35:16 +00:00
}
2011-03-30 14:00:48 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2012-08-01 16:49:33 +00:00
return false ;
2011-12-21 15:08:31 +00:00
} ,
2012-03-27 12:47:04 +00:00
set _input _id : function ( id ) {
this . id _for _label = id ;
} ,
2012-08-30 16:12:37 +00:00
on _translate : function ( ) {
var self = this ;
2012-09-04 13:31:37 +00:00
var trans = new instance . web . DataSet ( this , 'ir.translation' ) ;
2012-10-30 14:06:30 +00:00
return trans . call _button ( 'translate_fields' , [ this . view . dataset . model , this . view . datarecord . id , this . name , this . view . dataset . get _context ( ) ] ) . done ( function ( r ) {
2012-10-04 07:00:55 +00:00
self . do _action ( r ) ;
2012-08-30 16:12:37 +00:00
} ) ;
} ,
2012-10-18 14:57:12 +00:00
set _dimensions : function ( height , width ) {
2012-11-13 12:30:47 +00:00
this . $el . css ( {
width : width ,
minHeight : height
} ) ;
2012-11-05 11:16:35 +00:00
} ,
commit _value : function ( ) {
return $ . when ( ) ;
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2012-03-19 10:31:16 +00:00
/ * *
2012-09-28 12:41:32 +00:00
* A mixin to apply on any FormWidget that has to completely re - render when its readonly state
2012-03-19 10:31:16 +00:00
* switch .
* /
2012-09-28 12:41:32 +00:00
instance . web . form . ReinitializeWidgetMixin = {
2012-03-20 10:17:47 +00:00
/ * *
2012-10-12 12:56:20 +00:00
* Default implementation of , you should not override it , use initialize _field ( ) instead .
2012-03-20 10:17:47 +00:00
* /
2011-03-30 14:00:48 +00:00
start : function ( ) {
2012-03-20 10:17:47 +00:00
this . initialize _field ( ) ;
2012-10-11 16:09:02 +00:00
this . _super ( ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-03-20 10:17:47 +00:00
initialize _field : function ( ) {
2012-10-08 15:28:31 +00:00
this . on ( "change:effective_readonly" , this , this . reinitialize ) ;
this . initialize _content ( ) ;
} ,
reinitialize : function ( ) {
this . destroy _content ( ) ;
this . renderElement ( ) ;
2012-03-20 10:17:47 +00:00
this . initialize _content ( ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-03-20 10:17:47 +00:00
/ * *
* Called to destroy anything that could have been created previously , called before a
* re - initialization .
* /
destroy _content : function ( ) { } ,
/ * *
* Called to initialize the content .
* /
initialize _content : function ( ) { } ,
2012-09-28 12:41:32 +00:00
} ;
/ * *
* A mixin to apply on any field that has to completely re - render when its readonly state
* switch .
* /
instance . web . form . ReinitializeFieldMixin = _ . extend ( { } , instance . web . form . ReinitializeWidgetMixin , {
2012-10-08 15:28:31 +00:00
reinitialize : function ( ) {
instance . web . form . ReinitializeWidgetMixin . reinitialize . call ( this ) ;
2012-09-28 12:41:32 +00:00
this . render _value ( ) ;
} ,
} ) ;
2012-03-19 10:31:16 +00:00
2013-03-01 14:46:53 +00:00
/ * *
Some hack to make placeholders work in ie9 .
* /
if ( $ . browser . msie && $ . browser . version === "9.0" ) {
document . addEventListener ( "DOMNodeInserted" , function ( event ) {
var nodename = event . target . nodeName . toLowerCase ( ) ;
if ( nodename === "input" || nodename == "textarea" ) {
$ ( event . target ) . placeholder ( ) ;
}
} ) ;
}
2012-06-21 23:56:41 +00:00
instance . web . form . FieldChar = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-03-19 10:31:16 +00:00
template : 'FieldChar' ,
2012-06-01 17:10:53 +00:00
widget _class : 'oe_form_field_char' ,
2012-12-10 14:38:08 +00:00
events : {
'change input' : 'store_dom_value' ,
} ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2012-03-19 10:31:16 +00:00
this . password = this . node . attrs . password === 'True' || this . node . attrs . password === '1' ;
2011-03-30 14:00:48 +00:00
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-12-10 14:38:08 +00:00
this . setupFocus ( this . $ ( 'input' ) ) ;
} ,
store _dom _value : function ( ) {
2012-12-10 15:44:11 +00:00
if ( ! this . get ( 'effective_readonly' )
&& this . $ ( 'input' ) . length
&& this . is _syntax _valid ( ) ) {
2012-12-10 14:38:08 +00:00
this . internal _set _value (
this . parse _value (
this . $ ( 'input' ) . val ( ) ) ) ;
}
} ,
commit _value : function ( ) {
this . store _dom _value ( ) ;
return this . _super ( ) ;
2011-04-11 11:35:16 +00:00
} ,
2012-03-16 11:22:23 +00:00
render _value : function ( ) {
2012-10-09 09:08:51 +00:00
var show _value = this . format _value ( this . get ( 'value' ) , '' ) ;
2012-03-16 11:22:23 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
2012-08-24 18:27:07 +00:00
this . $el . find ( 'input' ) . val ( show _value ) ;
2012-03-16 11:22:23 +00:00
} else {
if ( this . password ) {
show _value = new Array ( show _value . length + 1 ) . join ( '*' ) ;
}
2012-10-08 15:28:31 +00:00
this . $ ( ".oe_form_char_content" ) . text ( show _value ) ;
2011-04-11 11:35:16 +00:00
}
2011-06-20 18:25:49 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _syntax _valid : function ( ) {
2012-10-12 14:43:52 +00:00
if ( ! this . get ( "effective_readonly" ) && this . $ ( "input" ) . size ( ) > 0 ) {
2012-03-19 15:34:06 +00:00
try {
2012-12-10 14:38:08 +00:00
this . parse _value ( this . $ ( 'input' ) . val ( ) , '' ) ;
2012-04-18 09:50:43 +00:00
return true ;
2012-03-19 15:34:06 +00:00
} catch ( e ) {
2012-04-18 09:16:13 +00:00
return false ;
2012-03-19 15:34:06 +00:00
}
2011-04-11 11:35:16 +00:00
}
2012-04-18 09:16:13 +00:00
return true ;
2011-06-20 18:25:49 +00:00
} ,
2012-10-09 09:08:51 +00:00
parse _value : function ( val , def ) {
return instance . web . parse _value ( val , this , def ) ;
} ,
format _value : function ( val , def ) {
return instance . web . format _value ( val , this , def ) ;
} ,
2012-04-18 09:50:43 +00:00
is _false : function ( ) {
2012-06-07 14:31:04 +00:00
return this . get ( 'value' ) === '' || this . _super ( ) ;
2012-04-18 09:50:43 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = this . $ ( 'input:first' ) [ 0 ] ;
return input ? input . focus ( ) : false ;
2012-11-07 13:21:52 +00:00
} ,
set _dimensions : function ( height , width ) {
this . _super ( height , width ) ;
this . $ ( 'input' ) . css ( {
height : height ,
width : width
} ) ;
2011-03-30 14:00:48 +00:00
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2012-04-17 12:09:49 +00:00
instance . web . form . FieldID = instance . web . form . FieldChar . extend ( {
2012-12-18 17:31:15 +00:00
process _modifiers : function ( ) {
this . _super ( ) ;
this . set ( { readonly : true } ) ;
} ,
2012-01-25 14:04:38 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldEmail = instance . web . form . FieldChar . extend ( {
2012-03-13 20:28:23 +00:00
template : 'FieldEmail' ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-03-16 11:33:22 +00:00
this . _super ( ) ;
2012-08-24 18:27:07 +00:00
var $button = this . $el . find ( 'button' ) ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
$button . click ( this . on _button _clicked ) ;
this . setupFocus ( $button ) ;
2011-05-12 16:25:50 +00:00
} ,
2012-03-16 11:33:22 +00:00
render _value : function ( ) {
if ( ! this . get ( "effective_readonly" ) ) {
this . _super ( ) ;
} else {
2012-08-24 18:27:07 +00:00
this . $el . find ( 'a' )
2012-04-17 14:32:27 +00:00
. attr ( 'href' , 'mailto:' + this . get ( 'value' ) )
2012-06-27 15:29:22 +00:00
. text ( this . get ( 'value' ) || '' ) ;
2012-03-16 11:33:22 +00:00
}
} ,
2011-05-12 16:25:50 +00:00
on _button _clicked : function ( ) {
2012-04-18 09:50:43 +00:00
if ( ! this . get ( 'value' ) || ! this . is _syntax _valid ( ) ) {
2013-04-29 10:28:55 +00:00
this . do _warn ( _t ( "E-mail Error" ) , _t ( "Can't send email to invalid e-mail address" ) ) ;
2011-05-12 16:25:50 +00:00
} else {
2012-04-17 14:32:27 +00:00
location . href = 'mailto:' + this . get ( 'value' ) ;
2011-05-12 16:25:50 +00:00
}
2011-04-11 11:35:16 +00:00
}
2011-03-30 14:00:48 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldUrl = instance . web . form . FieldChar . extend ( {
2012-03-13 20:28:23 +00:00
template : 'FieldUrl' ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-03-16 11:44:24 +00:00
this . _super ( ) ;
2012-08-24 18:27:07 +00:00
var $button = this . $el . find ( 'button' ) ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
$button . click ( this . on _button _clicked ) ;
this . setupFocus ( $button ) ;
2011-05-19 13:55:22 +00:00
} ,
2012-03-16 11:44:24 +00:00
render _value : function ( ) {
if ( ! this . get ( "effective_readonly" ) ) {
this . _super ( ) ;
} else {
2012-04-17 14:32:27 +00:00
var tmp = this . get ( 'value' ) ;
2013-02-25 16:09:32 +00:00
var s = /(\w+):(.+)|^\.{0,2}\// . exec ( tmp ) ;
2012-03-16 11:44:24 +00:00
if ( ! s ) {
2012-04-17 14:32:27 +00:00
tmp = "http://" + this . get ( 'value' ) ;
2012-03-16 11:44:24 +00:00
}
2013-03-13 15:43:45 +00:00
var text = this . get ( 'value' ) ? this . node . attrs . text || tmp : '' ;
this . $el . find ( 'a' ) . attr ( 'href' , tmp ) . text ( text ) ;
2012-03-16 11:44:24 +00:00
}
} ,
2011-05-19 13:55:22 +00:00
on _button _clicked : function ( ) {
2012-04-17 14:32:27 +00:00
if ( ! this . get ( 'value' ) ) {
2013-04-29 10:28:55 +00:00
this . do _warn ( _t ( "Resource Error" ) , _t ( "This resource is empty" ) ) ;
2011-05-19 13:55:22 +00:00
} else {
2012-04-17 14:32:27 +00:00
var url = $ . trim ( this . get ( 'value' ) ) ;
2012-04-16 23:32:07 +00:00
if ( /^www\./i . test ( url ) )
url = 'http://' + url ;
window . open ( url ) ;
2011-05-19 13:55:22 +00:00
}
}
2011-03-30 14:00:48 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldFloat = instance . web . form . FieldChar . extend ( {
2012-03-29 10:20:48 +00:00
is _field _number : true ,
2012-06-01 17:10:53 +00:00
widget _class : 'oe_form_field_float' ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2012-10-11 15:21:40 +00:00
this . internal _set _value ( 0 ) ;
2012-03-14 17:09:49 +00:00
if ( this . node . attrs . digits ) {
2012-06-21 12:41:23 +00:00
this . digits = this . node . attrs . digits ;
2011-10-21 12:22:56 +00:00
} else {
2012-03-13 20:28:23 +00:00
this . digits = this . field . digits ;
2011-10-21 12:22:56 +00:00
}
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
if ( value _ === false || value _ === undefined ) {
2011-05-09 15:19:23 +00:00
// As in GTK client, floats default to 0
2012-04-17 14:32:27 +00:00
value _ = 0 ;
2011-05-09 15:19:23 +00:00
}
2012-04-17 14:32:27 +00:00
this . _super . apply ( this , [ value _ ] ) ;
2012-08-08 15:41:26 +00:00
} ,
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var $input = this . $ ( 'input:first' ) ;
return $input . length ? $input . select ( ) : false ;
2011-07-07 08:55:15 +00:00
}
} ) ;
2012-08-14 13:42:46 +00:00
instance . web . DateTimeWidget = instance . web . Widget . extend ( {
2012-06-04 09:32:39 +00:00
template : "web.datepicker" ,
2011-09-21 10:41:36 +00:00
jqueryui _object : 'datetimepicker' ,
type _of _date : "datetime" ,
2012-12-10 14:38:08 +00:00
events : {
'change .oe_datepicker_master' : 'change_datetime' ,
} ,
2011-11-16 22:27:05 +00:00
init : function ( parent ) {
this . _super ( parent ) ;
this . name = parent . name ;
} ,
2011-04-05 14:34:25 +00:00
start : function ( ) {
2011-09-14 15:46:10 +00:00
var self = this ;
2012-08-24 18:27:07 +00:00
this . $input = this . $el . find ( 'input.oe_datepicker_master' ) ;
this . $input _picker = this . $el . find ( 'input.oe_datepicker_container' ) ;
2012-12-18 13:47:40 +00:00
2013-05-01 05:41:29 +00:00
$ . datepicker . setDefaults ( {
clearText : _t ( 'Clear' ) ,
clearStatus : _t ( 'Erase the current date' ) ,
closeText : _t ( 'Done' ) ,
closeStatus : _t ( 'Close without change' ) ,
prevText : _t ( '<Prev' ) ,
prevStatus : _t ( 'Show the previous month' ) ,
nextText : _t ( 'Next>' ) ,
nextStatus : _t ( 'Show the next month' ) ,
currentText : _t ( 'Today' ) ,
currentStatus : _t ( 'Show the current month' ) ,
monthNames : Date . CultureInfo . monthNames ,
monthNamesShort : Date . CultureInfo . abbreviatedMonthNames ,
monthStatus : _t ( 'Show a different month' ) ,
yearStatus : _t ( 'Show a different year' ) ,
weekHeader : _t ( 'Wk' ) ,
weekStatus : _t ( 'Week of the year' ) ,
dayNames : Date . CultureInfo . dayNames ,
dayNamesShort : Date . CultureInfo . abbreviatedDayNames ,
dayNamesMin : Date . CultureInfo . shortestDayNames ,
dayStatus : _t ( 'Set DD as first week day' ) ,
dateStatus : _t ( 'Select D, M d' ) ,
firstDay : Date . CultureInfo . firstDayOfWeek ,
initStatus : _t ( 'Select a date' ) ,
isRTL : false
} ) ;
$ . timepicker . setDefaults ( {
timeOnlyTitle : _t ( 'Choose Time' ) ,
timeText : _t ( 'Time' ) ,
hourText : _t ( 'Hour' ) ,
minuteText : _t ( 'Minute' ) ,
secondText : _t ( 'Second' ) ,
currentText : _t ( 'Now' ) ,
closeText : _t ( 'Done' )
} ) ;
2011-09-14 15:46:10 +00:00
this . picker ( {
2012-05-23 13:15:27 +00:00
onClose : this . on _picker _select ,
2011-09-14 15:46:10 +00:00
onSelect : this . on _picker _select ,
changeMonth : true ,
changeYear : true ,
showWeek : true ,
2012-07-23 13:56:20 +00:00
showButtonPanel : true ,
firstDay : Date . CultureInfo . firstDayOfWeek
2011-09-14 15:46:10 +00:00
} ) ;
2013-02-25 11:06:14 +00:00
// Some clicks in the datepicker dialog are not stopped by the
// datepicker and "bubble through", unexpectedly triggering the bus's
// click event. Prevent that.
this . picker ( 'widget' ) . click ( function ( e ) { e . stopPropagation ( ) ; } ) ;
2012-08-24 18:27:07 +00:00
this . $el . find ( 'img.oe_datepicker_trigger' ) . click ( function ( ) {
2012-06-25 13:52:15 +00:00
if ( self . get ( "effective_readonly" ) || self . picker ( 'widget' ) . is ( ':visible' ) ) {
2012-06-20 11:34:02 +00:00
self . $input . focus ( ) ;
return ;
2011-09-14 15:46:10 +00:00
}
2012-11-14 14:43:45 +00:00
self . picker ( 'setDate' , self . get ( 'value' ) ? instance . web . auto _str _to _date ( self . get ( 'value' ) ) : new Date ( ) ) ;
2012-06-20 11:34:02 +00:00
self . $input _picker . show ( ) ;
self . picker ( 'show' ) ;
self . $input _picker . hide ( ) ;
2011-09-14 15:46:10 +00:00
} ) ;
2011-09-21 11:50:54 +00:00
this . set _readonly ( false ) ;
2012-04-17 14:32:27 +00:00
this . set ( { 'value' : false } ) ;
2011-05-12 10:36:01 +00:00
} ,
2011-09-14 15:46:10 +00:00
picker : function ( ) {
2011-11-16 22:27:05 +00:00
return $ . fn [ this . jqueryui _object ] . apply ( this . $input _picker , arguments ) ;
2011-09-14 15:46:10 +00:00
} ,
2012-04-17 11:43:58 +00:00
on _picker _select : function ( text , instance _ ) {
2011-09-14 15:46:10 +00:00
var date = this . picker ( 'getDate' ) ;
2012-06-20 11:34:02 +00:00
this . $input
. val ( date ? this . format _client ( date ) : '' )
. change ( )
. focus ( ) ;
2011-09-14 15:46:10 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
this . set ( { 'value' : value _ } ) ;
this . $input . val ( value _ ? this . format _client ( value _ ) : '' ) ;
2011-09-14 15:46:10 +00:00
} ,
get _value : function ( ) {
2012-04-17 14:32:27 +00:00
return this . get ( 'value' ) ;
2011-05-12 10:36:01 +00:00
} ,
2012-04-17 15:45:05 +00:00
set _value _from _ui _ : function ( ) {
2012-04-17 14:32:27 +00:00
var value _ = this . $input . val ( ) || false ;
this . set ( { 'value' : this . parse _client ( value _ ) } ) ;
2011-05-12 10:36:01 +00:00
} ,
2011-09-21 10:41:36 +00:00
set _readonly : function ( readonly ) {
this . readonly = readonly ;
2012-02-13 16:31:20 +00:00
this . $input . prop ( 'readonly' , this . readonly ) ;
2012-08-24 18:27:07 +00:00
this . $el . find ( 'img.oe_datepicker_trigger' ) . toggleClass ( 'oe_input_icon_disabled' , readonly ) ;
2011-06-30 09:40:53 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _valid _ : function ( ) {
2012-04-17 14:32:27 +00:00
var value _ = this . $input . val ( ) ;
if ( value _ === "" ) {
2012-03-26 14:31:12 +00:00
return true ;
2011-06-30 12:10:08 +00:00
} else {
2011-09-14 15:46:10 +00:00
try {
2012-04-17 14:32:27 +00:00
this . parse _client ( value _ ) ;
2011-09-21 10:41:36 +00:00
return true ;
2011-09-14 15:46:10 +00:00
} catch ( e ) {
2011-09-21 10:41:36 +00:00
return false ;
2011-09-14 15:46:10 +00:00
}
2011-06-30 12:10:08 +00:00
}
2011-05-12 10:36:01 +00:00
} ,
2011-09-14 15:46:10 +00:00
parse _client : function ( v ) {
2012-04-17 12:09:49 +00:00
return instance . web . parse _value ( v , { "widget" : this . type _of _date } ) ;
2011-09-14 15:46:10 +00:00
} ,
format _client : function ( v ) {
2012-04-17 12:09:49 +00:00
return instance . web . format _value ( v , { "widget" : this . type _of _date } ) ;
2011-09-21 10:41:36 +00:00
} ,
2012-10-12 13:01:40 +00:00
change _datetime : function ( ) {
2012-04-18 09:50:43 +00:00
if ( this . is _valid _ ( ) ) {
2012-04-17 15:45:05 +00:00
this . set _value _from _ui _ ( ) ;
2012-10-12 10:31:04 +00:00
this . trigger ( "datetime_changed" ) ;
2011-09-21 10:41:36 +00:00
}
2012-12-10 14:38:08 +00:00
} ,
commit _value : function ( ) {
this . change _datetime ( ) ;
} ,
2011-03-30 14:00:48 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . DateWidget = instance . web . DateTimeWidget . extend ( {
2011-09-21 10:41:36 +00:00
jqueryui _object : 'datepicker' ,
2011-11-16 22:27:05 +00:00
type _of _date : "date"
2011-03-30 14:00:48 +00:00
} ) ;
2012-06-21 23:56:41 +00:00
instance . web . form . FieldDatetime = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-06-04 09:32:39 +00:00
template : "FieldDatetime" ,
2011-09-21 10:41:36 +00:00
build _widget : function ( ) {
2012-04-17 12:09:49 +00:00
return new instance . web . DateTimeWidget ( this ) ;
2011-09-21 10:41:36 +00:00
} ,
2012-03-20 10:17:47 +00:00
destroy _content : function ( ) {
2012-03-19 15:10:45 +00:00
if ( this . datewidget ) {
2012-03-20 09:58:19 +00:00
this . datewidget . destroy ( ) ;
2012-03-19 15:10:45 +00:00
this . datewidget = undefined ;
}
2011-09-21 10:41:36 +00:00
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-03-19 15:10:45 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
this . datewidget = this . build _widget ( ) ;
2012-10-12 10:27:28 +00:00
this . datewidget . on ( 'datetime_changed' , this , _ . bind ( function ( ) {
2012-10-11 15:21:40 +00:00
this . internal _set _value ( this . datewidget . get _value ( ) ) ;
2012-04-17 15:45:05 +00:00
} , this ) ) ;
2012-08-24 18:27:07 +00:00
this . datewidget . appendTo ( this . $el ) ;
2012-06-25 13:52:15 +00:00
this . setupFocus ( this . datewidget . $input ) ;
2012-03-19 15:10:45 +00:00
}
2011-09-21 10:41:36 +00:00
} ,
2012-03-19 15:10:45 +00:00
render _value : function ( ) {
if ( ! this . get ( "effective_readonly" ) ) {
2012-04-17 14:32:27 +00:00
this . datewidget . set _value ( this . get ( 'value' ) ) ;
2012-03-19 15:10:45 +00:00
} else {
2012-08-24 18:27:07 +00:00
this . $el . text ( instance . web . format _value ( this . get ( 'value' ) , this , '' ) ) ;
2012-03-19 15:10:45 +00:00
}
2011-09-21 10:41:36 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _syntax _valid : function ( ) {
2012-10-12 14:40:37 +00:00
if ( ! this . get ( "effective_readonly" ) && this . datewidget ) {
2012-04-18 09:50:43 +00:00
return this . datewidget . is _valid _ ( ) ;
2012-03-26 14:31:12 +00:00
}
2012-04-18 09:16:13 +00:00
return true ;
2011-09-21 10:41:36 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _false : function ( ) {
2012-06-07 14:31:04 +00:00
return this . get ( 'value' ) === '' || this . _super ( ) ;
2011-09-21 10:41:36 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = this . datewidget && this . datewidget . $input [ 0 ] ;
return input ? input . focus ( ) : false ;
2012-11-08 10:36:31 +00:00
} ,
set _dimensions : function ( height , width ) {
this . _super ( height , width ) ;
this . datewidget . $input . css ( 'height' , height ) ;
2011-09-21 10:41:36 +00:00
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-09-21 10:41:36 +00:00
2012-04-17 12:09:49 +00:00
instance . web . form . FieldDate = instance . web . form . FieldDatetime . extend ( {
2012-06-04 09:32:39 +00:00
template : "FieldDate" ,
2011-09-21 10:41:36 +00:00
build _widget : function ( ) {
2012-04-17 12:09:49 +00:00
return new instance . web . DateWidget ( this ) ;
2011-09-21 10:41:36 +00:00
}
} ) ;
2012-06-21 23:56:41 +00:00
instance . web . form . FieldText = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-03-13 20:28:23 +00:00
template : 'FieldText' ,
2012-12-10 14:38:08 +00:00
events : {
'keyup' : function ( e ) {
if ( e . which === $ . ui . keyCode . ENTER ) {
e . stopPropagation ( ) ;
}
} ,
'change textarea' : 'store_dom_value' ,
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-08-31 10:50:42 +00:00
var self = this ;
2013-03-06 15:13:06 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
this . $textarea = this . $el . find ( 'textarea' ) ;
this . auto _sized = false ;
this . default _height = this . $textarea . css ( 'height' ) ;
if ( this . get ( "effective_readonly" ) ) {
this . $textarea . attr ( 'disabled' , 'disabled' ) ;
}
this . setupFocus ( this . $textarea ) ;
} else {
this . $textarea = undefined ;
2012-03-19 15:18:23 +00:00
}
2011-04-05 09:55:49 +00:00
} ,
2012-12-10 14:38:08 +00:00
commit _value : function ( ) {
2013-03-06 16:24:36 +00:00
if ( ! this . get ( "effective_readonly" ) && this . $textarea ) {
this . store _dom _value ( ) ;
}
2012-12-10 14:38:08 +00:00
return this . _super ( ) ;
} ,
store _dom _value : function ( ) {
2013-03-06 15:13:06 +00:00
this . internal _set _value ( instance . web . parse _value ( this . $textarea . val ( ) , this ) ) ;
2012-12-10 14:38:08 +00:00
} ,
2012-03-19 15:18:23 +00:00
render _value : function ( ) {
2013-03-06 15:13:06 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
var show _value = instance . web . format _value ( this . get ( 'value' ) , this , '' ) ;
if ( show _value === '' ) {
2013-07-25 10:07:49 +00:00
this . $textarea . css ( 'height' , parseInt ( this . default _height , 10 ) + "px" ) ;
2013-03-06 15:13:06 +00:00
}
this . $textarea . val ( show _value ) ;
if ( ! this . auto _sized ) {
this . auto _sized = true ;
this . $textarea . autosize ( ) ;
} else {
this . $textarea . trigger ( "autosize" ) ;
}
2012-12-13 15:06:53 +00:00
} else {
2013-03-14 13:51:41 +00:00
var txt = this . get ( "value" ) || '' ;
2013-03-06 15:13:06 +00:00
this . $ ( ".oe_form_text_content" ) . text ( txt ) ;
2012-12-13 15:06:53 +00:00
}
2011-04-05 09:55:49 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _syntax _valid : function ( ) {
2012-10-12 14:43:52 +00:00
if ( ! this . get ( "effective_readonly" ) && this . $textarea ) {
2012-03-19 15:18:23 +00:00
try {
2012-12-10 14:38:08 +00:00
instance . web . parse _value ( this . $textarea . val ( ) , this , '' ) ;
2012-04-18 09:50:43 +00:00
return true ;
2012-03-19 15:18:23 +00:00
} catch ( e ) {
2012-04-18 09:16:13 +00:00
return false ;
2012-03-19 15:18:23 +00:00
}
2011-04-11 11:35:16 +00:00
}
2012-04-18 09:16:13 +00:00
return true ;
2011-06-20 18:25:49 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _false : function ( ) {
2012-06-07 14:31:04 +00:00
return this . get ( 'value' ) === '' || this . _super ( ) ;
2011-06-20 18:25:49 +00:00
} ,
2012-08-24 18:27:07 +00:00
focus : function ( $el ) {
2013-05-01 05:41:29 +00:00
var input = ! this . get ( "effective_readonly" ) && this . $textarea && this . $textarea [ 0 ] ;
return input ? input . focus ( ) : false ;
2011-12-21 17:16:02 +00:00
} ,
2012-10-18 14:57:12 +00:00
set _dimensions : function ( height , width ) {
2012-11-07 13:21:52 +00:00
this . _super ( height , width ) ;
2013-03-06 15:13:06 +00:00
if ( ! this . get ( "effective_readonly" ) && this . $textarea ) {
this . $textarea . css ( {
width : width ,
minHeight : height
} ) ;
}
2012-10-18 14:57:12 +00:00
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2012-06-15 14:35:20 +00:00
/ * *
* FieldTextHtml Widget
* Intended for FieldText widgets meant to display HTML content . This
* widget will instantiate the CLEditor ( see cleditor in static / src / lib )
* To find more information about CLEditor configutation : go to
* http : //premiumsoftware.net/cleditor/docs/GettingStarted.html
* /
2012-08-13 15:22:27 +00:00
instance . web . form . FieldTextHtml = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
template : 'FieldTextHtml' ,
2012-09-10 13:57:47 +00:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
} ,
2012-07-06 15:51:13 +00:00
initialize _content : function ( ) {
2012-08-13 15:40:11 +00:00
var self = this ;
if ( ! this . get ( "effective_readonly" ) ) {
self . _updating _editor = false ;
2012-08-24 18:27:07 +00:00
this . $textarea = this . $el . find ( 'textarea' ) ;
2012-10-26 16:43:27 +00:00
var width = ( ( this . node . attrs || { } ) . editor _width || '100%' ) ;
2012-08-21 10:16:32 +00:00
var height = ( ( this . node . attrs || { } ) . editor _height || 250 ) ;
2012-08-13 15:40:11 +00:00
this . $textarea . cleditor ( {
width : width , // width not including margins, borders or padding
height : height , // height not including margins, borders or padding
controls : // controls to add to the toolbar
"bold italic underline strikethrough " +
"| removeformat | bullets numbering | outdent " +
"indent | link unlink | source" ,
bodyStyle : // style to assign to document body contained within the editor
2013-03-11 14:08:38 +00:00
"margin:4px; color:#4c4c4c; font-size:13px; font-family:'Lucida Grande',Helvetica,Verdana,Arial,sans-serif; cursor:text"
2012-08-13 15:40:11 +00:00
} ) ;
this . $cleditor = this . $textarea . cleditor ( ) [ 0 ] ;
this . $cleditor . change ( function ( ) {
if ( ! self . _updating _editor ) {
self . $cleditor . updateTextArea ( ) ;
2012-10-11 15:21:40 +00:00
self . internal _set _value ( self . $textarea . val ( ) ) ;
2012-08-13 15:40:11 +00:00
}
} ) ;
2013-06-07 10:15:17 +00:00
if ( this . field . translate ) {
var $img = $ ( '<img class="oe_field_translate oe_input_icon" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>' )
. click ( this . on _translate ) ;
this . $cleditor . $toolbar . append ( $img ) ;
}
2012-08-13 15:40:11 +00:00
}
2012-07-06 15:51:13 +00:00
} ,
render _value : function ( ) {
2012-08-13 15:40:11 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
2012-09-12 14:46:26 +00:00
this . $textarea . val ( this . get ( 'value' ) || '' ) ;
2012-08-13 15:40:11 +00:00
this . _updating _editor = true ;
this . $cleditor . updateFrame ( ) ;
this . _updating _editor = false ;
} else {
2012-08-24 18:27:07 +00:00
this . $el . html ( this . get ( 'value' ) ) ;
2012-08-13 15:40:11 +00:00
}
2012-07-06 07:44:35 +00:00
} ,
2012-06-15 14:35:20 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldBoolean = instance . web . form . AbstractField . extend ( {
2012-03-13 20:28:23 +00:00
template : 'FieldBoolean' ,
2011-04-05 09:55:49 +00:00
start : function ( ) {
2012-06-27 10:01:51 +00:00
var self = this ;
2012-08-24 18:27:07 +00:00
this . $checkbox = $ ( "input" , this . $el ) ;
2012-06-25 13:52:15 +00:00
this . setupFocus ( this . $checkbox ) ;
2012-08-24 18:27:07 +00:00
this . $el . click ( _ . bind ( function ( ) {
2012-10-11 15:21:40 +00:00
this . internal _set _value ( this . $checkbox . is ( ':checked' ) ) ;
2012-04-17 15:45:05 +00:00
} , this ) ) ;
2012-03-16 11:52:43 +00:00
var check _readonly = function ( ) {
2012-06-27 10:01:51 +00:00
self . $checkbox . prop ( 'disabled' , self . get ( "effective_readonly" ) ) ;
2013-02-28 13:47:40 +00:00
self . click _disabled _boolean ( ) ;
2012-03-16 11:52:43 +00:00
} ;
this . on ( "change:effective_readonly" , this , check _readonly ) ;
2012-06-27 10:01:51 +00:00
check _readonly . call ( this ) ;
2011-04-05 14:34:25 +00:00
this . _super . apply ( this , arguments ) ;
2011-04-11 11:35:16 +00:00
} ,
2012-10-11 15:21:40 +00:00
render _value : function ( ) {
this . $checkbox [ 0 ] . checked = this . get ( 'value' ) ;
2011-04-05 14:34:25 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = this . $checkbox && this . $checkbox [ 0 ] ;
return input ? input . focus ( ) : false ;
2013-02-28 13:47:40 +00:00
} ,
click _disabled _boolean : function ( ) {
2013-05-01 05:56:18 +00:00
var $disabled = this . $el . find ( 'input[type=checkbox]:disabled' ) ;
2013-02-28 13:47:40 +00:00
$disabled . each ( function ( ) {
2013-05-01 05:56:18 +00:00
$ ( this ) . next ( 'div' ) . remove ( ) ;
2013-05-02 07:20:52 +00:00
$ ( this ) . closest ( "span" ) . append ( $ ( '<div class="boolean"></div>' ) ) ;
2013-02-28 13:47:40 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
}
} ) ;
2012-11-09 13:49:58 +00:00
/ * *
The progressbar field expect a float from 0 to 100.
* /
2012-04-17 12:09:49 +00:00
instance . web . form . FieldProgressBar = instance . web . form . AbstractField . extend ( {
2012-03-15 16:21:07 +00:00
template : 'FieldProgressBar' ,
2012-11-09 13:49:58 +00:00
render _value : function ( ) {
2012-08-24 18:27:07 +00:00
this . $el . progressbar ( {
2012-11-09 13:49:58 +00:00
value : this . get ( 'value' ) || 0 ,
2012-03-20 15:51:11 +00:00
disabled : this . get ( "effective_readonly" )
2011-04-12 09:26:31 +00:00
} ) ;
2012-11-09 13:49:58 +00:00
var formatted _value = instance . web . format _value ( this . get ( 'value' ) || 0 , { type : 'float' } ) ;
this . $ ( 'span' ) . html ( formatted _value + '%' ) ;
2011-04-12 09:26:31 +00:00
}
} ) ;
2011-03-30 14:00:48 +00:00
2012-06-21 23:56:41 +00:00
instance . web . form . FieldSelection = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-03-13 17:46:19 +00:00
template : 'FieldSelection' ,
2012-12-10 14:38:08 +00:00
events : {
'change select' : 'store_dom_value' ,
} ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
2011-09-07 16:33:15 +00:00
var self = this ;
2012-04-18 12:45:20 +00:00
this . _super ( field _manager , node ) ;
2012-12-06 13:51:14 +00:00
this . values = _ ( this . field . selection ) . chain ( )
. reject ( function ( v ) { return v [ 0 ] === false && v [ 1 ] === '' ; } )
. unshift ( [ false , '' ] )
. value ( ) ;
2011-03-30 14:00:48 +00:00
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2011-07-08 12:38:53 +00:00
// Flag indicating whether we're in an event chain containing a change
// event on the select, in order to know what to do on keyup[RETURN]:
// * If the user presses [RETURN] as part of changing the value of a
// selection, we should just let the value change and not let the
// event broadcast further (e.g. to validating the current state of
// the form in editable list view, which would lead to saving the
// current row or switching to the next one)
// * If the user presses [RETURN] with a select closed (side-effect:
// also if the user opened the select and pressed [RETURN] without
// changing the selected value), takes the action as validating the
// row
var ischanging = false ;
2012-08-24 18:27:07 +00:00
var $select = this . $el . find ( 'select' )
2011-07-08 12:38:53 +00:00
. change ( function ( ) { ischanging = true ; } )
. click ( function ( ) { ischanging = false ; } )
. keyup ( function ( e ) {
if ( e . which !== 13 || ! ischanging ) { return ; }
e . stopPropagation ( ) ;
ischanging = false ;
} ) ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
this . setupFocus ( $select ) ;
2011-04-05 14:34:25 +00:00
} ,
2012-12-10 14:38:08 +00:00
commit _value : function ( ) {
this . store _dom _value ( ) ;
return this . _super ( ) ;
} ,
store _dom _value : function ( ) {
2012-12-11 09:06:10 +00:00
if ( ! this . get ( 'effective_readonly' ) && this . $ ( 'select' ) . length ) {
2012-12-10 14:38:08 +00:00
this . internal _set _value (
this . values [ this . $ ( 'select' ) [ 0 ] . selectedIndex ] [ 0 ] ) ;
}
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
value _ = value _ === null ? false : value _ ;
value _ = value _ instanceof Array ? value _ [ 0 ] : value _ ;
this . _super ( value _ ) ;
2011-04-11 11:35:16 +00:00
} ,
2012-03-16 12:23:31 +00:00
render _value : function ( ) {
if ( ! this . get ( "effective_readonly" ) ) {
var index = 0 ;
for ( var i = 0 , ii = this . values . length ; i < ii ; i ++ ) {
2012-04-17 14:32:27 +00:00
if ( this . values [ i ] [ 0 ] === this . get ( 'value' ) ) index = i ;
2012-03-16 12:23:31 +00:00
}
2012-08-24 18:27:07 +00:00
this . $el . find ( 'select' ) [ 0 ] . selectedIndex = index ;
2012-03-16 12:23:31 +00:00
} else {
var self = this ;
var option = _ ( this . values )
2012-07-12 12:56:37 +00:00
. detect ( function ( record ) { return record [ 0 ] === self . get ( 'value' ) ; } ) ;
2012-08-24 18:27:07 +00:00
this . $el . text ( option ? option [ 1 ] : this . values [ 0 ] [ 1 ] ) ;
2011-09-07 16:33:15 +00:00
}
2011-04-05 14:34:25 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = this . $ ( 'select:first' ) [ 0 ] ;
return input ? input . focus ( ) : false ;
2012-11-07 13:21:52 +00:00
} ,
set _dimensions : function ( height , width ) {
this . _super ( height , width ) ;
this . $ ( 'select' ) . css ( {
height : height ,
width : width
} ) ;
2011-03-30 14:00:48 +00:00
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2013-03-02 21:38:49 +00:00
instance . web . form . FieldRadio = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
template : 'FieldRadio' ,
2013-04-10 16:09:17 +00:00
events : {
'click input' : 'click_change_value'
} ,
2013-03-02 21:38:49 +00:00
init : function ( field _manager , node ) {
2013-03-04 09:04:27 +00:00
/ * R a d i o b u t t o n w i d g e t : A t t r i b u t e s o p t i o n s :
* - "horizontal" to display in column
* - "no_radiolabel" don ' t display text values
* /
2013-03-02 21:38:49 +00:00
this . _super ( field _manager , node ) ;
2013-04-08 17:17:02 +00:00
this . selection = _ . clone ( this . field . selection ) || [ ] ;
2013-03-29 11:38:27 +00:00
this . domain = false ;
2013-03-02 21:38:49 +00:00
} ,
2013-03-21 15:04:05 +00:00
initialize _content : function ( ) {
2013-04-10 16:09:17 +00:00
this . uniqueId = _ . uniqueId ( "radio" ) ;
2013-04-10 13:56:43 +00:00
this . on ( "change:effective_readonly" , this , this . render _value ) ;
2013-03-29 11:38:27 +00:00
this . field _manager . on ( "view_content_has_changed" , this , this . get _selection ) ;
2013-04-08 17:17:02 +00:00
this . get _selection ( ) ;
2013-03-29 11:38:27 +00:00
} ,
2013-04-10 16:09:17 +00:00
click _change _value : function ( event ) {
var val = $ ( event . target ) . val ( ) ;
2013-04-15 10:30:41 +00:00
val = this . field . type == "selection" ? val : + val ;
2013-04-10 16:09:17 +00:00
if ( val == this . get _value ( ) ) {
this . set _value ( false ) ;
} else {
this . set _value ( val ) ;
2013-03-29 11:38:27 +00:00
}
} ,
/ * * G e t t h e s e l e c t i o n a n d r e n d e r i t
* selection : [ [ identifier , value _to _display ] , ... ]
* For selection fields : this is directly given by this . field . selection
* For many2one fields : perform a search on the relation of the many2one field
* /
get _selection : function ( ) {
var self = this ;
var selection = [ ] ;
var def = $ . Deferred ( ) ;
if ( self . field . type == "many2one" ) {
var domain = instance . web . pyeval . eval ( 'domain' , this . build _domain ( ) ) || [ ] ;
2013-04-08 17:17:02 +00:00
if ( ! _ . isEqual ( self . domain , domain ) ) {
2013-03-29 11:38:27 +00:00
self . domain = domain ;
2013-05-16 13:14:16 +00:00
var ds = new instance . web . DataSetStatic ( self , self . field . relation , self . build _context ( ) ) ;
2013-03-29 14:10:38 +00:00
ds . call ( 'search' , [ self . domain ] )
2013-03-29 11:38:27 +00:00
. then ( function ( records ) {
2013-03-29 14:10:38 +00:00
ds . name _get ( records ) . then ( function ( records ) {
selection = records ;
def . resolve ( ) ;
} ) ;
2013-03-29 11:38:27 +00:00
} ) ;
2013-04-15 10:30:41 +00:00
} else {
selection = self . selection ;
def . resolve ( ) ;
2013-03-29 11:38:27 +00:00
}
}
else if ( self . field . type == "selection" ) {
selection = self . field . selection || [ ] ;
def . resolve ( ) ;
}
2013-04-08 17:17:02 +00:00
return def . then ( function ( ) {
if ( ! _ . isEqual ( selection , self . selection ) ) {
self . selection = _ . clone ( selection ) ;
2013-04-15 10:30:41 +00:00
self . renderElement ( ) ;
2013-04-08 17:17:02 +00:00
self . render _value ( ) ;
2013-03-02 21:38:49 +00:00
}
} ) ;
} ,
2013-04-10 13:56:43 +00:00
set _value : function ( value _ ) {
2013-04-15 10:30:41 +00:00
if ( value _ ) {
if ( this . field . type == "selection" ) {
2013-07-25 10:33:01 +00:00
value _ = _ . find ( this . field . selection , function ( sel ) { return sel [ 0 ] == value _ ; } ) ;
2013-04-15 10:30:41 +00:00
}
else if ( ! this . selection . length ) {
this . selection = [ value _ ] ;
}
2013-04-10 13:56:43 +00:00
}
this . _super ( value _ ) ;
} ,
2013-04-08 17:17:02 +00:00
get _value : function ( ) {
2013-04-10 13:56:43 +00:00
var value = this . get ( 'value' ) ;
return value instanceof Array ? value [ 0 ] : value ;
2013-04-08 17:17:02 +00:00
} ,
2013-03-02 21:38:49 +00:00
render _value : function ( ) {
2013-04-15 10:30:41 +00:00
var self = this ;
2013-04-11 09:33:19 +00:00
this . $el . toggleClass ( "oe_readonly" , this . get ( 'effective_readonly' ) ) ;
2013-04-15 10:30:41 +00:00
this . $ ( "input:checked" ) . prop ( "checked" , false ) ;
2013-04-10 16:09:17 +00:00
if ( this . get _value ( ) ) {
2013-07-25 10:33:01 +00:00
this . $ ( "input" ) . filter ( function ( ) { return this . value == self . get _value ( ) ; } ) . prop ( "checked" , true ) ;
2013-04-15 10:30:41 +00:00
this . $ ( ".oe_radio_readonly" ) . text ( this . get ( 'value' ) ? this . get ( 'value' ) [ 1 ] : "" ) ;
2013-04-10 16:09:17 +00:00
}
2013-03-02 21:38:49 +00:00
}
} ) ;
2011-03-30 14:00:48 +00:00
2012-08-29 15:37:56 +00:00
// jquery autocomplete tweak to allow html and classnames
2011-06-20 14:43:48 +00:00
( function ( ) {
2011-06-10 13:22:37 +00:00
var proto = $ . ui . autocomplete . prototype ,
initSource = proto . _initSource ;
2011-06-20 14:43:48 +00:00
2011-06-10 13:22:37 +00:00
function filter ( array , term ) {
var matcher = new RegExp ( $ . ui . autocomplete . escapeRegex ( term ) , "i" ) ;
2012-04-17 14:32:27 +00:00
return $ . grep ( array , function ( value _ ) {
return matcher . test ( $ ( "<div>" ) . html ( value _ . label || value _ . value || value _ ) . text ( ) ) ;
2011-06-10 13:22:37 +00:00
} ) ;
2011-06-10 10:31:55 +00:00
}
2011-06-20 14:43:48 +00:00
2011-06-10 13:22:37 +00:00
$ . extend ( proto , {
_initSource : function ( ) {
if ( this . options . html && $ . isArray ( this . options . source ) ) {
this . source = function ( request , response ) {
response ( filter ( this . options . source , request . term ) ) ;
} ;
} else {
initSource . call ( this ) ;
}
} ,
2011-06-20 14:43:48 +00:00
2011-06-10 13:22:37 +00:00
_renderItem : function ( ul , item ) {
return $ ( "<li></li>" )
. data ( "item.autocomplete" , item )
. append ( $ ( "<a></a>" ) [ this . options . html ? "html" : "text" ] ( item . label ) )
2012-08-29 15:37:56 +00:00
. appendTo ( ul )
. addClass ( item . classname ) ;
2011-06-10 13:22:37 +00:00
}
} ) ;
2011-06-20 14:43:48 +00:00
} ) ( ) ;
2011-06-10 10:31:55 +00:00
2012-05-07 12:22:46 +00:00
/ * *
2013-08-22 10:00:30 +00:00
A mixin containing some useful methods to handle completion inputs .
The widget containing this option can have these arguments in its widget options :
- no _quick _create : if true , it will disable the quick create
* /
2012-05-07 12:22:46 +00:00
instance . web . form . CompletionFieldMixin = {
init : function ( ) {
this . limit = 7 ;
this . orderer = new instance . web . DropMisordered ( ) ;
} ,
/ * *
* Call this method to search using a string .
* /
2012-05-07 12:37:28 +00:00
get _search _result : function ( search _val ) {
2012-05-07 12:22:46 +00:00
var self = this ;
var dataset = new instance . web . DataSet ( this , this . field . relation , self . build _context ( ) ) ;
2012-05-30 09:39:16 +00:00
var blacklist = this . get _search _blacklist ( ) ;
2012-09-18 14:59:25 +00:00
this . last _query = search _val ;
2012-05-07 12:22:46 +00:00
2012-05-07 12:37:28 +00:00
return this . orderer . add ( dataset . name _search (
2012-05-30 09:39:16 +00:00
search _val , new instance . web . CompoundDomain ( self . build _domain ( ) , [ [ "id" , "not in" , blacklist ] ] ) ,
2012-10-30 14:06:30 +00:00
'ilike' , this . limit + 1 , self . build _context ( ) ) ) . then ( function ( data ) {
2012-05-07 12:22:46 +00:00
self . last _search = data ;
// possible selections for the m2o
var values = _ . map ( data , function ( x ) {
2012-06-28 13:08:08 +00:00
x [ 1 ] = x [ 1 ] . split ( "\n" ) [ 0 ] ;
2012-05-07 12:22:46 +00:00
return {
label : _ . str . escapeHTML ( x [ 1 ] ) ,
2012-06-28 13:08:08 +00:00
value : x [ 1 ] ,
name : x [ 1 ] ,
id : x [ 0 ] ,
2012-05-07 12:22:46 +00:00
} ;
} ) ;
// search more... if more results that max
if ( values . length > self . limit ) {
values = values . slice ( 0 , self . limit ) ;
2012-08-29 15:37:56 +00:00
values . push ( {
label : _t ( "Search More..." ) ,
action : function ( ) {
2012-10-30 14:06:30 +00:00
dataset . name _search ( search _val , self . build _domain ( ) , 'ilike' , false ) . done ( function ( data ) {
2012-08-29 15:37:56 +00:00
self . _search _create _popup ( "search" , data ) ;
} ) ;
} ,
classname : 'oe_m2o_dropdown_option'
} ) ;
2012-05-07 12:22:46 +00:00
}
// quick create
var raw _result = _ ( data . result ) . map ( function ( x ) { return x [ 1 ] ; } ) ;
2013-08-22 10:00:30 +00:00
if ( search _val . length > 0 && ! _ . include ( raw _result , search _val ) &&
! ( self . options && self . options . no _quick _create ) ) {
2012-08-29 15:37:56 +00:00
values . push ( {
label : _ . str . sprintf ( _t ( 'Create "<strong>%s</strong>"' ) ,
$ ( '<span />' ) . text ( search _val ) . html ( ) ) ,
action : function ( ) {
self . _quick _create ( search _val ) ;
} ,
classname : 'oe_m2o_dropdown_option'
} ) ;
2012-05-07 12:22:46 +00:00
}
// create...
2012-08-29 15:37:56 +00:00
values . push ( {
label : _t ( "Create and Edit..." ) ,
action : function ( ) {
self . _search _create _popup ( "form" , undefined , self . _create _context ( search _val ) ) ;
} ,
classname : 'oe_m2o_dropdown_option'
} ) ;
2012-05-07 12:22:46 +00:00
2012-05-07 12:37:28 +00:00
return values ;
2012-05-07 12:22:46 +00:00
} ) ;
} ,
2012-05-30 09:39:16 +00:00
get _search _blacklist : function ( ) {
return [ ] ;
} ,
2012-05-07 12:22:46 +00:00
_quick _create : function ( name ) {
var self = this ;
var slow _create = function ( ) {
2012-08-24 17:26:22 +00:00
self . _search _create _popup ( "form" , undefined , self . _create _context ( name ) ) ;
2012-05-07 12:22:46 +00:00
} ;
2012-08-18 20:16:32 +00:00
if ( self . options . quick _create === undefined || self . options . quick _create ) {
2012-05-07 12:22:46 +00:00
new instance . web . DataSet ( this , this . field . relation , self . build _context ( ) )
2012-10-30 14:06:30 +00:00
. name _create ( name ) . done ( function ( data ) {
2012-05-09 15:32:46 +00:00
self . add _id ( data [ 0 ] ) ;
2012-05-07 12:22:46 +00:00
} ) . fail ( function ( error , event ) {
event . preventDefault ( ) ;
slow _create ( ) ;
} ) ;
} else
slow _create ( ) ;
} ,
// all search/create popup handling
_search _create _popup : function ( view , ids , context ) {
var self = this ;
var pop = new instance . web . form . SelectCreatePopup ( this ) ;
pop . select _element (
self . field . relation ,
{
2012-06-29 15:02:25 +00:00
title : ( view === 'search' ? _t ( "Search: " ) : _t ( "Create: " ) ) + this . string ,
2013-07-25 10:33:01 +00:00
initial _ids : ids ? _ . map ( ids , function ( x ) { return x [ 0 ] ; } ) : undefined ,
2012-05-07 12:22:46 +00:00
initial _view : view ,
disable _multiple _selection : true
} ,
self . build _domain ( ) ,
new instance . web . CompoundContext ( self . build _context ( ) , context || { } )
) ;
2012-10-12 13:10:44 +00:00
pop . on ( "elements_selected" , self , function ( element _ids ) {
2012-05-09 15:32:46 +00:00
self . add _id ( element _ids [ 0 ] ) ;
2012-06-25 13:52:15 +00:00
self . focus ( ) ;
2012-05-07 12:22:46 +00:00
} ) ;
} ,
2012-05-09 15:32:46 +00:00
/ * *
* To implement .
* /
add _id : function ( id ) { } ,
2012-08-24 17:26:22 +00:00
_create _context : function ( name ) {
var tmp = { } ;
var field = ( this . options || { } ) . create _name _field ;
2012-09-12 12:01:55 +00:00
if ( field === undefined )
field = "name" ;
if ( field !== false && name && ( this . options || { } ) . quick _create !== false )
tmp [ "default_" + field ] = name ;
2012-08-24 17:26:22 +00:00
return tmp ;
} ,
2012-05-07 12:22:46 +00:00
} ;
2012-09-18 14:59:25 +00:00
instance . web . form . M2ODialog = instance . web . Dialog . extend ( {
template : "M2ODialog" ,
init : function ( parent ) {
this . _super ( parent , {
title : _ . str . sprintf ( _t ( "Add %s" ) , parent . string ) ,
width : 312 ,
} ) ;
} ,
start : function ( ) {
var self = this ;
this . $buttons . html ( QWeb . render ( "M2ODialog.buttons" ) ) ;
this . $ ( "input" ) . val ( this . getParent ( ) . last _query ) ;
this . $buttons . find ( ".oe_form_m2o_qc_button" ) . click ( function ( ) {
self . getParent ( ) . _quick _create ( self . $ ( "input" ) . val ( ) ) ;
self . destroy ( ) ;
} ) ;
this . $buttons . find ( ".oe_form_m2o_sc_button" ) . click ( function ( ) {
self . getParent ( ) . _search _create _popup ( "form" , undefined , self . getParent ( ) . _create _context ( self . $ ( "input" ) . val ( ) ) ) ;
self . destroy ( ) ;
} ) ;
this . $buttons . find ( ".oe_form_m2o_cancel_button" ) . click ( function ( ) {
self . destroy ( ) ;
} ) ;
} ,
} ) ;
2012-06-21 23:56:41 +00:00
instance . web . form . FieldMany2One = instance . web . form . AbstractField . extend ( instance . web . form . CompletionFieldMixin , instance . web . form . ReinitializeFieldMixin , {
2012-03-20 10:26:50 +00:00
template : "FieldMany2One" ,
2012-12-10 11:22:03 +00:00
events : {
'keydown input' : function ( e ) {
switch ( e . which ) {
case $ . ui . keyCode . UP :
case $ . ui . keyCode . DOWN :
e . stopPropagation ( ) ;
}
2013-02-18 10:45:29 +00:00
} ,
2012-12-10 11:22:03 +00:00
} ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2012-05-07 12:22:46 +00:00
instance . web . form . CompletionFieldMixin . init . call ( this ) ;
2012-04-17 14:32:27 +00:00
this . set ( { 'value' : false } ) ;
2012-04-05 14:41:18 +00:00
this . display _value = { } ;
2013-05-30 08:02:18 +00:00
this . display _value _backup = { } ;
2011-06-10 13:22:37 +00:00
this . last _search = [ ] ;
2012-04-05 14:41:18 +00:00
this . floating = false ;
2012-07-09 11:57:27 +00:00
this . current _display = null ;
2012-10-11 15:35:06 +00:00
this . is _started = false ;
2011-04-27 12:20:51 +00:00
} ,
2012-10-12 12:56:20 +00:00
reinit _value : function ( val ) {
this . internal _set _value ( val ) ;
this . floating = false ;
if ( this . is _started )
2012-04-05 14:41:18 +00:00
this . render _value ( ) ;
2012-10-12 12:56:20 +00:00
} ,
initialize _field : function ( ) {
2012-10-11 15:35:06 +00:00
this . is _started = true ;
2012-08-16 12:55:40 +00:00
instance . web . bus . on ( 'click' , this , function ( ) {
if ( ! this . get ( "effective_readonly" ) && this . $input && this . $input . autocomplete ( 'widget' ) . is ( ':visible' ) ) {
this . $input . autocomplete ( "close" ) ;
}
} ) ;
2012-10-12 12:56:20 +00:00
instance . web . form . ReinitializeFieldMixin . initialize _field . call ( this ) ;
2012-03-16 09:54:59 +00:00
} ,
2012-03-20 10:26:50 +00:00
initialize _content : function ( ) {
2012-03-15 16:43:26 +00:00
if ( ! this . get ( "effective_readonly" ) )
2012-03-13 15:14:35 +00:00
this . render _editable ( ) ;
} ,
2013-03-06 14:55:27 +00:00
destroy _content : function ( ) {
if ( this . $drop _down ) {
this . $drop _down . off ( 'click' ) ;
delete this . $drop _down ;
}
if ( this . $input ) {
this . $input . closest ( ".ui-dialog .ui-dialog-content" ) . off ( 'scroll' ) ;
this . $input . off ( 'keyup blur autocompleteclose autocompleteopen ' +
'focus focusout change keydown' ) ;
delete this . $input ;
}
if ( this . $follow _button ) {
this . $follow _button . off ( 'blur focus click' ) ;
delete this . $follow _button ;
}
} ,
destroy : function ( ) {
this . destroy _content ( ) ;
return this . _super ( ) ;
} ,
2012-09-18 12:43:32 +00:00
init _error _displayer : function ( ) {
2012-09-18 14:59:25 +00:00
// nothing
2012-09-18 12:43:32 +00:00
} ,
hide _error _displayer : function ( ) {
2012-09-18 14:59:25 +00:00
// doesn't work
2012-09-18 12:43:32 +00:00
} ,
show _error _displayer : function ( ) {
2012-09-18 14:59:25 +00:00
new instance . web . form . M2ODialog ( this ) . open ( ) ;
2012-09-18 12:43:32 +00:00
} ,
render _editable : function ( ) {
var self = this ;
this . $input = this . $el . find ( "input" ) ;
this . init _error _displayer ( ) ;
2012-08-06 14:00:44 +00:00
self . $input . on ( 'focus' , function ( ) {
2012-09-18 12:43:32 +00:00
self . hide _error _displayer ( ) ;
2012-04-05 12:44:33 +00:00
} ) ;
2012-07-12 12:56:37 +00:00
2012-08-24 18:27:07 +00:00
this . $drop _down = this . $el . find ( ".oe_m2o_drop_down_button" ) ;
this . $follow _button = $ ( ".oe_m2o_cm_button" , this . $el ) ;
2012-07-12 12:56:37 +00:00
2012-09-12 13:36:56 +00:00
this . $follow _button . click ( function ( ev ) {
ev . preventDefault ( ) ;
2012-04-05 14:41:18 +00:00
if ( ! self . get ( 'value' ) ) {
2012-06-25 13:52:15 +00:00
self . focus ( ) ;
2012-04-05 12:07:18 +00:00
return ;
}
2012-10-04 15:28:37 +00:00
var pop = new instance . web . form . FormOpenPopup ( self ) ;
2012-04-05 12:07:18 +00:00
pop . show _element (
self . field . relation ,
2012-04-05 14:41:18 +00:00
self . get ( "value" ) ,
2012-04-05 12:07:18 +00:00
self . build _context ( ) ,
{
2012-06-29 15:02:25 +00:00
title : _t ( "Open: " ) + self . string
2012-04-05 12:07:18 +00:00
}
) ;
2012-10-10 10:12:46 +00:00
pop . on ( 'write_completed' , self , function ( ) {
2012-04-05 14:41:18 +00:00
self . display _value = { } ;
2013-05-30 08:02:18 +00:00
self . display _value _backup = { } ;
2012-04-05 14:41:18 +00:00
self . render _value ( ) ;
2012-06-25 13:52:15 +00:00
self . focus ( ) ;
2013-01-22 10:33:58 +00:00
self . view . do _onchange ( self ) ;
2011-08-25 14:21:26 +00:00
} ) ;
2011-06-10 13:22:37 +00:00
} ) ;
2011-06-20 14:43:48 +00:00
2011-06-10 10:31:55 +00:00
// some behavior for input
2012-08-08 14:13:01 +00:00
var input _changed = function ( ) {
2012-07-09 11:57:27 +00:00
if ( self . current _display !== self . $input . val ( ) ) {
self . current _display = self . $input . val ( ) ;
if ( self . $input . val ( ) === "" ) {
2012-10-11 15:35:06 +00:00
self . internal _set _value ( false ) ;
2012-07-10 08:54:41 +00:00
self . floating = false ;
2012-07-09 11:57:27 +00:00
} else {
self . floating = true ;
}
2011-06-08 15:29:44 +00:00
}
2012-08-08 14:13:01 +00:00
} ;
this . $input . keydown ( input _changed ) ;
this . $input . change ( input _changed ) ;
2011-06-09 17:36:44 +00:00
this . $drop _down . click ( function ( ) {
2013-07-25 10:07:49 +00:00
self . $input . focus ( ) ;
2011-06-08 15:47:44 +00:00
if ( self . $input . autocomplete ( "widget" ) . is ( ":visible" ) ) {
2013-02-15 11:25:14 +00:00
self . $input . autocomplete ( "close" ) ;
2011-06-08 15:29:44 +00:00
} else {
2012-04-05 14:41:18 +00:00
if ( self . get ( "value" ) && ! self . floating ) {
2011-06-10 13:55:26 +00:00
self . $input . autocomplete ( "search" , "" ) ;
} else {
self . $input . autocomplete ( "search" ) ;
}
2011-06-08 15:29:44 +00:00
}
2011-06-06 16:50:43 +00:00
} ) ;
2013-02-26 09:33:46 +00:00
2013-02-21 09:48:53 +00:00
// Autocomplete close on dialog content scroll
2013-02-26 09:33:46 +00:00
var close _autocomplete = _ . debounce ( function ( ) {
if ( self . $input . autocomplete ( "widget" ) . is ( ":visible" ) ) {
self . $input . autocomplete ( "close" ) ;
2013-01-22 07:03:10 +00:00
}
2013-02-26 09:33:46 +00:00
} , 50 ) ;
2013-02-21 09:48:53 +00:00
this . $input . closest ( ".ui-dialog .ui-dialog-content" ) . on ( 'scroll' , this , close _autocomplete ) ;
2013-02-26 09:33:46 +00:00
2012-09-18 12:43:32 +00:00
self . ed _def = $ . Deferred ( ) ;
self . uned _def = $ . Deferred ( ) ;
var ed _delay = 200 ;
var ed _duration = 15000 ;
2012-11-02 14:13:48 +00:00
var anyoneLoosesFocus = function ( e ) {
2012-06-14 14:23:09 +00:00
var used = false ;
2012-04-05 14:41:18 +00:00
if ( self . floating ) {
if ( self . last _search . length > 0 ) {
if ( self . last _search [ 0 ] [ 0 ] != self . get ( "value" ) ) {
self . display _value = { } ;
2013-05-30 08:02:18 +00:00
self . display _value _backup = { } ;
2012-04-05 14:41:18 +00:00
self . display _value [ "" + self . last _search [ 0 ] [ 0 ] ] = self . last _search [ 0 ] [ 1 ] ;
2012-10-11 15:35:06 +00:00
self . reinit _value ( self . last _search [ 0 ] [ 0 ] ) ;
2012-04-05 14:41:18 +00:00
} else {
2012-06-14 14:23:09 +00:00
used = true ;
2012-04-05 14:41:18 +00:00
self . render _value ( ) ;
}
2011-06-10 13:22:37 +00:00
} else {
2012-06-14 14:23:09 +00:00
used = true ;
2012-10-11 15:35:06 +00:00
self . reinit _value ( false ) ;
2011-06-10 13:22:37 +00:00
}
2012-06-14 14:23:09 +00:00
self . floating = false ;
2011-06-10 13:22:37 +00:00
}
2012-09-18 12:43:32 +00:00
if ( used && self . get ( "value" ) === false && ! self . no _ed ) {
self . ed _def . reject ( ) ;
self . uned _def . reject ( ) ;
self . ed _def = $ . Deferred ( ) ;
2012-10-30 14:06:30 +00:00
self . ed _def . done ( function ( ) {
2012-09-18 12:43:32 +00:00
self . show _error _displayer ( ) ;
2012-11-02 14:13:48 +00:00
ignore _blur = false ;
self . trigger ( 'focused' ) ;
2012-04-05 12:44:33 +00:00
} ) ;
2012-11-02 14:13:48 +00:00
ignore _blur = true ;
2012-04-05 12:44:33 +00:00
setTimeout ( function ( ) {
2012-09-18 12:43:32 +00:00
self . ed _def . resolve ( ) ;
self . uned _def . reject ( ) ;
self . uned _def = $ . Deferred ( ) ;
2012-10-30 14:06:30 +00:00
self . uned _def . done ( function ( ) {
2012-09-18 12:43:32 +00:00
self . hide _error _displayer ( ) ;
2012-04-05 12:44:33 +00:00
} ) ;
2012-09-18 12:43:32 +00:00
setTimeout ( function ( ) { self . uned _def . resolve ( ) ; } , ed _duration ) ;
} , ed _delay ) ;
2012-04-05 12:44:33 +00:00
} else {
2012-09-18 12:43:32 +00:00
self . no _ed = false ;
self . ed _def . reject ( ) ;
2012-04-05 12:44:33 +00:00
}
2011-09-06 08:58:53 +00:00
} ;
2012-09-05 12:04:55 +00:00
var ignore _blur = false ;
this . $input . on ( {
focusout : anyoneLoosesFocus ,
focus : function ( ) { self . trigger ( 'focused' ) ; } ,
autocompleteopen : function ( ) { ignore _blur = true ; } ,
autocompleteclose : function ( ) { ignore _blur = false ; } ,
blur : function ( ) {
// autocomplete open
if ( ignore _blur ) { return ; }
if ( _ ( self . getChildren ( ) ) . any ( function ( child ) {
return child instanceof instance . web . form . AbstractFormPopup ;
} ) ) { return ; }
self . trigger ( 'blurred' ) ;
}
} ) ;
2011-06-20 14:43:48 +00:00
2011-07-12 14:16:10 +00:00
var isSelecting = false ;
2011-06-10 10:31:55 +00:00
// autocomplete
2011-06-06 16:50:43 +00:00
this . $input . autocomplete ( {
2012-05-07 12:37:28 +00:00
source : function ( req , resp ) {
2012-10-30 14:06:30 +00:00
self . get _search _result ( req . term ) . done ( function ( result ) {
2012-05-07 12:37:28 +00:00
resp ( result ) ;
} ) ;
} ,
2011-06-09 13:20:04 +00:00
select : function ( event , ui ) {
2011-07-12 14:16:10 +00:00
isSelecting = true ;
2011-06-08 15:29:44 +00:00
var item = ui . item ;
if ( item . id ) {
2012-04-05 14:41:18 +00:00
self . display _value = { } ;
2013-05-30 08:02:18 +00:00
self . display _value _backup = { } ;
2012-04-05 14:41:18 +00:00
self . display _value [ "" + item . id ] = item . name ;
2012-10-11 15:35:06 +00:00
self . reinit _value ( item . id ) ;
2011-06-08 15:29:44 +00:00
} else if ( item . action ) {
item . action ( ) ;
2012-08-02 12:02:30 +00:00
// Cancel widget blurring, to avoid form blur event
self . trigger ( 'focused' ) ;
2011-06-08 15:29:44 +00:00
return false ;
}
2011-06-10 10:31:55 +00:00
} ,
2011-06-10 12:15:45 +00:00
focus : function ( e , ui ) {
e . preventDefault ( ) ;
} ,
2011-06-10 13:22:37 +00:00
html : true ,
2012-06-14 14:23:09 +00:00
// disabled to solve a bug, but may cause others
//close: anyoneLoosesFocus,
2011-06-10 13:58:35 +00:00
minLength : 0 ,
delay : 0
2011-06-06 16:50:43 +00:00
} ) ;
2012-11-15 16:41:32 +00:00
this . $input . autocomplete ( "widget" ) . openerpClass ( ) ;
2011-07-12 14:16:10 +00:00
// used to correct a bug when selecting an element by pushing 'enter' in an editable list
this . $input . keyup ( function ( e ) {
2012-07-09 11:57:27 +00:00
if ( e . which === 13 ) { // ENTER
2011-07-12 14:16:10 +00:00
if ( isSelecting )
e . stopPropagation ( ) ;
}
isSelecting = false ;
} ) ;
2012-09-05 12:04:55 +00:00
this . setupFocus ( this . $follow _button ) ;
2011-06-06 16:50:43 +00:00
} ,
2012-04-05 14:41:18 +00:00
render _value : function ( no _recurse ) {
var self = this ;
if ( ! this . get ( "value" ) ) {
this . display _string ( "" ) ;
return ;
2011-06-28 16:22:06 +00:00
}
2012-04-05 14:41:18 +00:00
var display = this . display _value [ "" + this . get ( "value" ) ] ;
if ( display ) {
this . display _string ( display ) ;
2011-06-28 16:22:06 +00:00
return ;
}
2012-04-05 14:41:18 +00:00
if ( ! no _recurse ) {
2012-06-28 12:52:42 +00:00
var dataset = new instance . web . DataSetStatic ( this , this . field . relation , self . build _context ( ) ) ;
2013-05-01 05:41:29 +00:00
this . alive ( dataset . name _get ( [ self . get ( "value" ) ] ) ) . done ( function ( data ) {
2012-04-05 14:41:18 +00:00
self . display _value [ "" + self . get ( "value" ) ] = data [ 0 ] [ 1 ] ;
self . render _value ( true ) ;
2013-05-27 14:49:27 +00:00
} ) . fail ( function ( data , event ) {
2013-05-30 08:02:18 +00:00
// avoid displaying crash errors as many2One should be name_get compliant
event . preventDefault ( ) ;
self . display _value [ "" + self . get ( "value" ) ] = self . display _value _backup [ "" + self . get ( "value" ) ] ;
self . render _value ( true ) ;
2012-04-05 14:41:18 +00:00
} ) ;
2011-04-05 14:34:25 +00:00
}
2011-05-03 08:50:44 +00:00
} ,
2012-04-05 14:41:18 +00:00
display _string : function ( str ) {
2011-06-23 12:40:16 +00:00
var self = this ;
2012-03-15 16:43:26 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
2012-06-28 12:36:21 +00:00
this . $input . val ( str . split ( "\n" ) [ 0 ] ) ;
2012-07-09 11:57:27 +00:00
this . current _display = this . $input . val ( ) ;
2012-10-22 16:14:26 +00:00
if ( this . is _false ( ) ) {
2012-09-27 13:17:06 +00:00
this . $ ( '.oe_m2o_cm_button' ) . css ( { 'display' : 'none' } ) ;
2012-10-22 16:14:26 +00:00
} else {
this . $ ( '.oe_m2o_cm_button' ) . css ( { 'display' : 'inline' } ) ;
2012-09-27 13:17:06 +00:00
}
2011-06-23 12:40:16 +00:00
} else {
2012-07-18 10:17:29 +00:00
var lines = _ . escape ( str ) . split ( "\n" ) ;
var link = "" ;
var follow = "" ;
2012-09-12 17:16:24 +00:00
link = lines [ 0 ] ;
follow = _ . rest ( lines ) . join ( "<br />" ) ;
if ( follow )
link += "<br />" ;
2012-08-24 18:27:07 +00:00
var $link = this . $el . find ( '.oe_form_uri' )
2012-03-13 15:14:35 +00:00
. unbind ( 'click' )
2012-07-25 12:35:43 +00:00
. html ( link ) ;
2012-08-18 20:16:32 +00:00
if ( ! this . options . no _open )
2012-07-25 12:35:43 +00:00
$link . click ( function ( ) {
2012-03-13 15:14:35 +00:00
self . do _action ( {
type : 'ir.actions.act_window' ,
res _model : self . field . relation ,
2012-04-05 14:41:18 +00:00
res _id : self . get ( "value" ) ,
2012-04-09 21:30:43 +00:00
views : [ [ false , 'form' ] ] ,
2013-03-19 10:27:19 +00:00
target : 'current' ,
context : self . build _context ( ) . eval ( ) ,
2012-03-13 15:14:35 +00:00
} ) ;
return false ;
} ) ;
2012-08-24 18:27:07 +00:00
$ ( ".oe_form_m2o_follow" , this . $el ) . html ( follow ) ;
2011-06-10 14:58:01 +00:00
}
2011-08-25 17:04:10 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
2011-08-25 17:04:10 +00:00
var self = this ;
2012-04-17 14:32:27 +00:00
if ( value _ instanceof Array ) {
2012-04-05 14:41:18 +00:00
this . display _value = { } ;
2013-07-25 10:33:01 +00:00
this . display _value _backup = { } ;
2012-08-18 20:16:32 +00:00
if ( ! this . options . always _reload ) {
2012-06-28 12:52:42 +00:00
this . display _value [ "" + value _ [ 0 ] ] = value _ [ 1 ] ;
}
2013-05-30 08:02:18 +00:00
else {
this . display _value _backup [ "" + value _ [ 0 ] ] = value _ [ 1 ] ;
}
2012-04-17 14:32:27 +00:00
value _ = value _ [ 0 ] ;
2011-06-23 12:40:16 +00:00
}
2012-04-17 14:32:27 +00:00
value _ = value _ || false ;
2012-10-11 15:35:06 +00:00
this . reinit _value ( value _ ) ;
2011-10-06 12:04:25 +00:00
} ,
2012-07-19 08:19:14 +00:00
get _displayed : function ( ) {
return this . display _value [ "" + this . get ( "value" ) ] ;
} ,
2012-05-09 15:32:46 +00:00
add _id : function ( id ) {
this . display _value = { } ;
2013-05-30 08:02:18 +00:00
this . display _value _backup = { } ;
2012-10-11 15:35:06 +00:00
this . reinit _value ( id ) ;
2012-05-09 15:32:46 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _false : function ( ) {
return ! this . get ( "value" ) ;
2011-10-24 15:20:56 +00:00
} ,
2012-04-18 12:37:04 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = ! this . get ( 'effective_readonly' ) && this . $input && this . $input [ 0 ] ;
return input ? input . focus ( ) : false ;
2012-08-10 13:48:15 +00:00
} ,
_quick _create : function ( ) {
2012-09-18 12:43:32 +00:00
this . no _ed = true ;
this . ed _def . reject ( ) ;
2012-08-10 13:48:15 +00:00
return instance . web . form . CompletionFieldMixin . _quick _create . apply ( this , arguments ) ;
} ,
_search _create _popup : function ( ) {
2012-09-18 12:43:32 +00:00
this . no _ed = true ;
this . ed _def . reject ( ) ;
2012-08-10 13:48:15 +00:00
return instance . web . form . CompletionFieldMixin . _search _create _popup . apply ( this , arguments ) ;
} ,
2012-11-07 13:21:52 +00:00
set _dimensions : function ( height , width ) {
this . _super ( height , width ) ;
this . $input . css ( 'height' , height ) ;
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2012-11-05 13:02:32 +00:00
instance . web . form . Many2OneButton = instance . web . form . AbstractField . extend ( {
template : 'Many2OneButton' ,
init : function ( field _manager , node ) {
this . _super . apply ( this , arguments ) ;
} ,
start : function ( ) {
this . _super . apply ( this , arguments ) ;
this . set _button ( ) ;
} ,
set _button : function ( ) {
var self = this ;
if ( this . $button ) {
this . $button . remove ( ) ;
}
2012-12-03 15:15:25 +00:00
this . string = '' ;
2012-11-05 13:02:32 +00:00
this . node . attrs . icon = this . get ( 'value' ) ? '/web/static/src/img/icons/gtk-yes.png' : '/web/static/src/img/icons/gtk-no.png' ;
this . $button = $ ( QWeb . render ( 'WidgetButton' , { 'widget' : this } ) ) ;
2012-12-03 15:15:25 +00:00
this . $button . addClass ( 'oe_link' ) . css ( { 'padding' : '4px' } ) ;
2012-11-05 13:02:32 +00:00
this . $el . append ( this . $button ) ;
this . $button . on ( 'click' , self . on _click ) ;
} ,
on _click : function ( ev ) {
var self = this ;
2012-11-07 08:17:38 +00:00
this . popup = new instance . web . form . FormOpenPopup ( this ) ;
this . popup . show _element (
2012-11-05 13:02:32 +00:00
this . field . relation ,
this . get ( 'value' ) ,
this . build _context ( ) ,
2012-11-07 15:19:54 +00:00
{ title : this . string }
2012-11-05 13:02:32 +00:00
) ;
2012-11-08 15:42:15 +00:00
this . popup . on ( 'create_completed' , self , function ( r ) {
2012-11-05 13:02:32 +00:00
self . set _value ( r ) ;
} ) ;
} ,
set _value : function ( value _ ) {
var self = this ;
if ( value _ instanceof Array ) {
value _ = value _ [ 0 ] ;
}
value _ = value _ || false ;
this . set ( 'value' , value _ ) ;
this . set _button ( ) ;
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2011-06-21 12:12:22 +00:00
/ *
# Values : ( 0 , 0 , { fields } ) create
# ( 1 , ID , { fields } ) update
# ( 2 , ID ) remove ( delete )
# ( 3 , ID ) unlink one ( target id or target of relation )
# ( 4 , ID ) link
# ( 5 ) unlink all ( only valid for one2many )
* /
2011-06-28 08:22:55 +00:00
var commands = {
// (0, _, {values})
CREATE : 0 ,
2011-06-28 08:30:50 +00:00
'create' : function ( values ) {
return [ commands . CREATE , false , values ] ;
} ,
2011-06-28 08:22:55 +00:00
// (1, id, {values})
UPDATE : 1 ,
2011-06-28 08:30:50 +00:00
'update' : function ( id , values ) {
return [ commands . UPDATE , id , values ] ;
} ,
2011-06-28 08:22:55 +00:00
// (2, id[, _])
DELETE : 2 ,
2011-06-28 08:30:50 +00:00
'delete' : function ( id ) {
return [ commands . DELETE , id , false ] ;
} ,
2011-06-28 08:22:55 +00:00
// (3, id[, _]) removes relation, but not linked record itself
FORGET : 3 ,
2011-06-28 08:30:50 +00:00
'forget' : function ( id ) {
return [ commands . FORGET , id , false ] ;
} ,
2011-06-28 08:22:55 +00:00
// (4, id[, _])
LINK _TO : 4 ,
2011-06-28 08:30:50 +00:00
'link_to' : function ( id ) {
return [ commands . LINK _TO , id , false ] ;
} ,
2011-06-28 08:22:55 +00:00
// (5[, _[, _]])
2011-06-29 15:35:26 +00:00
DELETE _ALL : 5 ,
'delete_all' : function ( ) {
2011-06-28 08:30:50 +00:00
return [ 5 , false , false ] ;
} ,
2011-06-28 08:22:55 +00:00
// (6, _, ids) replaces all linked records with provided ids
2011-06-28 08:30:50 +00:00
REPLACE _WITH : 6 ,
'replace_with' : function ( ids ) {
return [ 6 , false , ids ] ;
}
2011-06-28 08:22:55 +00:00
} ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldOne2Many = instance . web . form . AbstractField . extend ( {
2011-07-04 15:00:17 +00:00
multi _selection : false ,
2012-03-29 10:03:08 +00:00
disable _utility _classes : true ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2012-04-06 12:30:28 +00:00
lazy _build _o2m _kanban _view ( ) ;
2011-10-26 15:31:09 +00:00
this . is _loaded = $ . Deferred ( ) ;
this . initial _is _loaded = this . is _loaded ;
2011-07-18 15:28:07 +00:00
this . form _last _update = $ . Deferred ( ) ;
2011-10-12 16:13:22 +00:00
this . init _form _last _update = this . form _last _update ;
2012-10-11 16:29:18 +00:00
this . is _started = false ;
2012-04-17 12:09:49 +00:00
this . dataset = new instance . web . form . One2ManyDataSet ( this , this . field . relation ) ;
2011-06-29 14:35:06 +00:00
this . dataset . o2m = this ;
this . dataset . parent _view = this . view ;
2011-12-19 17:30:55 +00:00
this . dataset . child _name = this . name ;
2012-10-11 16:29:18 +00:00
var self = this ;
2012-10-12 12:19:11 +00:00
this . dataset . on ( 'dataset_changed' , this , function ( ) {
2012-01-03 17:17:13 +00:00
self . trigger _on _change ( ) ;
2011-05-31 14:11:19 +00:00
} ) ;
2012-10-11 16:29:18 +00:00
this . set _value ( [ ] ) ;
} ,
start : function ( ) {
this . _super . apply ( this , arguments ) ;
this . $el . addClass ( 'oe_form_field oe_form_field_one2many' ) ;
2011-06-20 14:43:48 +00:00
2012-10-11 16:29:18 +00:00
var self = this ;
2011-06-20 14:43:48 +00:00
2012-10-12 08:43:37 +00:00
self . load _views ( ) ;
2012-10-30 14:06:30 +00:00
this . is _loaded . done ( function ( ) {
2012-03-16 10:48:59 +00:00
self . on ( "change:effective_readonly" , self , function ( ) {
2012-10-30 14:06:30 +00:00
self . is _loaded = self . is _loaded . then ( function ( ) {
2012-03-16 10:48:59 +00:00
self . viewmanager . destroy ( ) ;
2012-10-30 14:06:30 +00:00
return $ . when ( self . load _views ( ) ) . done ( function ( ) {
2012-03-16 10:48:59 +00:00
self . reload _current _view ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2012-10-11 16:29:18 +00:00
this . is _started = true ;
this . reload _current _view ( ) ;
2011-10-26 12:55:24 +00:00
} ,
2012-01-03 17:17:13 +00:00
trigger _on _change : function ( ) {
2012-04-18 12:23:41 +00:00
this . trigger ( 'changed_value' ) ;
2012-01-03 17:17:13 +00:00
} ,
2011-10-26 12:55:24 +00:00
load _views : function ( ) {
var self = this ;
2012-07-12 12:56:37 +00:00
2011-06-06 07:04:51 +00:00
var modes = this . node . attrs . mode ;
2011-10-25 12:42:51 +00:00
modes = ! ! modes ? modes . split ( "," ) : [ "tree" ] ;
2011-06-06 07:04:51 +00:00
var views = [ ] ;
_ . each ( modes , function ( mode ) {
2012-06-11 16:07:29 +00:00
if ( ! _ . include ( [ "list" , "tree" , "graph" , "kanban" ] , mode ) ) {
2012-11-29 00:22:00 +00:00
throw new Error ( _ . str . sprintf ( _t ( "View type '%s' is not supported in One2Many." ) , mode ) ) ;
2012-06-11 16:07:29 +00:00
}
2011-08-08 17:32:30 +00:00
var view = {
view _id : false ,
view _type : mode == "tree" ? "list" : mode ,
2012-04-18 14:24:39 +00:00
options : { }
2011-08-08 17:32:30 +00:00
} ;
2011-06-06 07:04:51 +00:00
if ( self . field . views && self . field . views [ mode ] ) {
2011-06-16 14:25:30 +00:00
view . embedded _view = self . field . views [ mode ] ;
}
if ( view . view _type === "list" ) {
2012-07-02 16:09:51 +00:00
_ . extend ( view . options , {
2012-07-26 15:55:10 +00:00
addable : null ,
2012-07-02 16:09:51 +00:00
selectable : self . multi _selection ,
sortable : false ,
import _enabled : false ,
2012-07-11 14:26:04 +00:00
deletable : true
2012-07-02 16:09:51 +00:00
} ) ;
2012-03-16 10:48:59 +00:00
if ( self . get ( "effective_readonly" ) ) {
2012-07-02 16:09:51 +00:00
_ . extend ( view . options , {
deletable : null ,
reorderable : false ,
} ) ;
2011-10-26 14:11:48 +00:00
}
2011-09-30 15:46:12 +00:00
} else if ( view . view _type === "form" ) {
2012-03-16 10:48:59 +00:00
if ( self . get ( "effective_readonly" ) ) {
2012-04-09 21:30:43 +00:00
view . view _type = 'form' ;
2011-12-07 09:42:42 +00:00
}
2012-07-02 16:09:51 +00:00
_ . extend ( view . options , {
not _interactible _on _create : true ,
} ) ;
2012-05-14 15:28:46 +00:00
} else if ( view . view _type === "kanban" ) {
2012-07-02 16:09:51 +00:00
_ . extend ( view . options , {
confirm _on _delete : false ,
} ) ;
2012-05-14 15:28:46 +00:00
if ( self . get ( "effective_readonly" ) ) {
2012-07-02 16:09:51 +00:00
_ . extend ( view . options , {
action _buttons : false ,
quick _creatable : false ,
creatable : false ,
read _only _mode : true ,
} ) ;
2012-05-14 15:28:46 +00:00
}
2011-06-06 07:04:51 +00:00
}
views . push ( view ) ;
} ) ;
2011-06-16 16:37:09 +00:00
this . views = views ;
2011-12-07 09:42:42 +00:00
2012-05-16 10:16:34 +00:00
this . viewmanager = new instance . web . form . One2ManyViewManager ( this , this . dataset , views , { } ) ;
this . viewmanager . o2m = self ;
2012-10-30 14:06:30 +00:00
var once = $ . Deferred ( ) . done ( function ( ) {
2011-10-12 16:13:22 +00:00
self . init _form _last _update . resolve ( ) ;
2011-06-28 08:22:28 +00:00
} ) ;
2012-10-30 14:06:30 +00:00
var def = $ . Deferred ( ) . done ( function ( ) {
2011-10-26 15:31:09 +00:00
self . initial _is _loaded . resolve ( ) ;
2011-10-26 12:55:24 +00:00
} ) ;
2012-10-11 10:43:41 +00:00
this . viewmanager . on ( "controller_inited" , self , function ( view _type , controller ) {
2012-04-06 12:30:28 +00:00
controller . o2m = self ;
2011-05-31 15:28:07 +00:00
if ( view _type == "list" ) {
2012-07-24 17:05:50 +00:00
if ( self . get ( "effective_readonly" ) ) {
controller . on ( 'edit:before' , self , function ( e ) {
e . cancel = true ;
} ) ;
2012-10-22 10:39:35 +00:00
_ ( controller . columns ) . find ( function ( column ) {
2012-10-31 10:32:33 +00:00
if ( ! ( column instanceof instance . web . list . Handle ) ) {
2012-10-19 10:07:25 +00:00
return false ;
}
2012-10-22 10:39:35 +00:00
column . modifiers . invisible = true ;
2012-10-19 10:07:25 +00:00
return true ;
} ) ;
2012-07-24 17:05:50 +00:00
}
2012-04-10 14:29:01 +00:00
} else if ( view _type === "form" ) {
if ( self . get ( "effective_readonly" ) ) {
2012-08-24 18:27:07 +00:00
$ ( ".oe_form_buttons" , controller . $el ) . children ( ) . remove ( ) ;
2011-12-23 11:12:11 +00:00
}
2012-10-10 10:02:33 +00:00
controller . on ( "load_record" , self , function ( ) {
2012-10-04 12:27:11 +00:00
once . resolve ( ) ;
} ) ;
2012-10-12 06:20:04 +00:00
controller . on ( 'pager_action_executed' , self , self . save _any _view ) ;
2011-10-07 16:21:56 +00:00
} else if ( view _type == "graph" ) {
2013-07-25 10:33:01 +00:00
self . reload _current _view ( ) ;
2011-05-31 13:01:54 +00:00
}
2011-10-26 12:55:24 +00:00
def . resolve ( ) ;
2011-05-31 13:01:54 +00:00
} ) ;
2012-10-10 09:37:37 +00:00
this . viewmanager . on ( "switch_mode" , self , function ( n _mode , b , c , d , e ) {
2012-10-30 14:06:30 +00:00
$ . when ( self . save _any _view ( ) ) . done ( function ( ) {
2012-10-09 14:51:13 +00:00
if ( n _mode === "list" ) {
2012-10-30 14:06:30 +00:00
$ . async _when ( ) . done ( function ( ) {
2012-10-09 14:51:13 +00:00
self . reload _current _view ( ) ;
} ) ;
}
2011-10-26 15:39:44 +00:00
} ) ;
2011-07-27 14:03:32 +00:00
} ) ;
2012-10-30 14:06:30 +00:00
$ . async _when ( ) . done ( function ( ) {
2012-10-12 08:43:37 +00:00
self . viewmanager . appendTo ( self . $el ) ;
2011-10-17 16:22:28 +00:00
} ) ;
2011-10-26 12:55:24 +00:00
return def ;
2011-04-04 15:52:09 +00:00
} ,
2011-06-16 16:37:09 +00:00
reload _current _view : function ( ) {
var self = this ;
2013-07-25 10:07:49 +00:00
self . is _loaded = self . is _loaded . then ( function ( ) {
2011-12-07 09:42:42 +00:00
var active _view = self . viewmanager . active _view ;
var view = self . viewmanager . views [ active _view ] . controller ;
if ( active _view === "list" ) {
2011-10-26 15:31:09 +00:00
return view . reload _content ( ) ;
2012-04-10 14:29:01 +00:00
} else if ( active _view === "form" ) {
2011-10-26 15:31:09 +00:00
if ( self . dataset . index === null && self . dataset . ids . length >= 1 ) {
self . dataset . index = 0 ;
}
var act = function ( ) {
return view . do _show ( ) ;
2011-12-07 09:42:42 +00:00
} ;
2012-10-30 14:06:30 +00:00
self . form _last _update = self . form _last _update . then ( act , act ) ;
2011-10-26 15:31:09 +00:00
return self . form _last _update ;
2012-04-06 12:03:47 +00:00
} else if ( view . do _search ) {
2011-10-26 15:31:09 +00:00
return view . do _search ( self . build _domain ( ) , self . dataset . get _context ( ) , [ ] ) ;
2011-10-12 12:49:23 +00:00
}
2011-12-07 09:42:42 +00:00
} , undefined ) ;
2013-07-25 10:07:49 +00:00
return self . is _loaded ;
2011-06-16 16:37:09 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
value _ = value _ || [ ] ;
2011-06-23 10:42:22 +00:00
var self = this ;
2011-06-29 15:35:26 +00:00
this . dataset . reset _ids ( [ ] ) ;
2013-07-25 10:07:49 +00:00
var ids ;
2012-04-17 14:32:27 +00:00
if ( value _ . length >= 1 && value _ [ 0 ] instanceof Array ) {
2013-07-25 10:07:49 +00:00
ids = [ ] ;
2012-04-17 14:32:27 +00:00
_ . each ( value _ , function ( command ) {
2011-06-28 08:22:55 +00:00
var obj = { values : command [ 2 ] } ;
switch ( command [ 0 ] ) {
case commands . CREATE :
obj [ 'id' ] = _ . uniqueId ( self . dataset . virtual _id _prefix ) ;
2011-09-28 11:55:37 +00:00
obj . defaults = { } ;
2011-06-28 08:22:55 +00:00
self . dataset . to _create . push ( obj ) ;
2012-02-14 16:15:58 +00:00
self . dataset . cache . push ( _ . extend ( _ . clone ( obj ) , { values : _ . clone ( command [ 2 ] ) } ) ) ;
2011-06-28 08:22:55 +00:00
ids . push ( obj . id ) ;
return ;
case commands . UPDATE :
obj [ 'id' ] = command [ 1 ] ;
self . dataset . to _write . push ( obj ) ;
2012-02-14 16:15:58 +00:00
self . dataset . cache . push ( _ . extend ( _ . clone ( obj ) , { values : _ . clone ( command [ 2 ] ) } ) ) ;
2011-06-28 08:22:55 +00:00
ids . push ( obj . id ) ;
return ;
case commands . DELETE :
self . dataset . to _delete . push ( { id : command [ 1 ] } ) ;
return ;
case commands . LINK _TO :
ids . push ( command [ 1 ] ) ;
return ;
2011-06-29 15:35:26 +00:00
case commands . DELETE _ALL :
self . dataset . delete _all = true ;
return ;
2011-06-27 09:05:32 +00:00
}
} ) ;
this . _super ( ids ) ;
this . dataset . set _ids ( ids ) ;
2012-04-17 14:32:27 +00:00
} else if ( value _ . length >= 1 && typeof ( value _ [ 0 ] ) === "object" ) {
2013-07-25 10:07:49 +00:00
ids = [ ] ;
2011-06-30 09:14:39 +00:00
this . dataset . delete _all = true ;
2012-04-17 14:32:27 +00:00
_ . each ( value _ , function ( command ) {
2011-06-30 09:14:39 +00:00
var obj = { values : command } ;
obj [ 'id' ] = _ . uniqueId ( self . dataset . virtual _id _prefix ) ;
2011-09-28 11:55:37 +00:00
obj . defaults = { } ;
2011-06-30 09:14:39 +00:00
self . dataset . to _create . push ( obj ) ;
self . dataset . cache . push ( _ . clone ( obj ) ) ;
ids . push ( obj . id ) ;
} ) ;
this . _super ( ids ) ;
this . dataset . set _ids ( ids ) ;
2011-06-27 09:05:32 +00:00
} else {
2012-04-17 14:32:27 +00:00
this . _super ( value _ ) ;
this . dataset . reset _ids ( value _ ) ;
2011-06-27 09:05:32 +00:00
}
2011-07-27 09:09:05 +00:00
if ( this . dataset . index === null && this . dataset . ids . length > 0 ) {
this . dataset . index = 0 ;
}
2012-09-24 16:07:21 +00:00
this . trigger _on _change ( ) ;
2012-10-11 16:29:18 +00:00
if ( this . is _started ) {
return self . reload _current _view ( ) ;
} else {
return $ . when ( ) ;
}
2011-05-31 13:38:17 +00:00
} ,
2011-06-21 12:12:22 +00:00
get _value : function ( ) {
2011-06-27 09:05:32 +00:00
var self = this ;
2011-06-29 14:35:06 +00:00
if ( ! this . dataset )
return [ ] ;
2011-06-29 15:35:26 +00:00
var val = this . dataset . delete _all ? [ commands . delete _all ( ) ] : [ ] ;
val = val . concat ( _ . map ( this . dataset . ids , function ( id ) {
2011-06-27 09:05:32 +00:00
var alter _order = _ . detect ( self . dataset . to _create , function ( x ) { return x . id === id ; } ) ;
if ( alter _order ) {
2011-06-28 08:30:50 +00:00
return commands . create ( alter _order . values ) ;
2011-06-27 09:05:32 +00:00
}
alter _order = _ . detect ( self . dataset . to _write , function ( x ) { return x . id === id ; } ) ;
if ( alter _order ) {
2011-06-28 08:30:50 +00:00
return commands . update ( alter _order . id , alter _order . values ) ;
2011-06-27 09:05:32 +00:00
}
2011-06-28 08:30:50 +00:00
return commands . link _to ( id ) ;
2011-06-29 15:35:26 +00:00
} ) ) ;
2011-06-28 08:30:50 +00:00
return val . concat ( _ . map (
this . dataset . to _delete , function ( x ) {
return commands [ 'delete' ] ( x . id ) ; } ) ) ;
2011-06-21 12:12:22 +00:00
} ,
2012-11-05 17:14:12 +00:00
commit _value : function ( ) {
return this . save _any _view ( ) ;
} ,
2011-11-10 11:02:06 +00:00
save _any _view : function ( ) {
2012-11-05 17:14:12 +00:00
if ( this . viewmanager && this . viewmanager . views && this . viewmanager . active _view &&
this . viewmanager . views [ this . viewmanager . active _view ] &&
this . viewmanager . views [ this . viewmanager . active _view ] . controller ) {
var view = this . viewmanager . views [ this . viewmanager . active _view ] . controller ;
if ( this . viewmanager . active _view === "form" ) {
2013-07-25 10:07:49 +00:00
if ( view . is _initialized . state ( ) !== 'resolved' ) {
2012-11-05 17:14:12 +00:00
return $ . when ( false ) ;
2012-07-16 11:13:24 +00:00
}
2012-11-05 17:14:12 +00:00
return $ . when ( view . save ( ) ) ;
} else if ( this . viewmanager . active _view === "list" ) {
return $ . when ( view . ensure _saved ( ) ) ;
2012-07-16 11:13:24 +00:00
}
2012-11-05 17:14:12 +00:00
}
return $ . when ( false ) ;
2011-07-26 15:37:47 +00:00
} ,
2012-04-18 09:50:43 +00:00
is _syntax _valid : function ( ) {
2012-09-24 16:30:21 +00:00
if ( ! this . viewmanager || ! this . viewmanager . views [ this . viewmanager . active _view ] )
2012-04-18 09:16:13 +00:00
return true ;
2011-09-16 13:22:28 +00:00
var view = this . viewmanager . views [ this . viewmanager . active _view ] . controller ;
2012-06-13 10:08:19 +00:00
switch ( this . viewmanager . active _view ) {
case 'form' :
return _ ( view . fields ) . chain ( )
. invoke ( 'is_valid' )
. all ( _ . identity )
. value ( ) ;
case 'list' :
return view . is _valid ( ) ;
2011-07-26 15:37:47 +00:00
}
2012-04-18 09:16:13 +00:00
return true ;
2011-07-27 13:36:28 +00:00
} ,
2011-03-30 14:00:48 +00:00
} ) ;
2012-05-16 10:16:34 +00:00
instance . web . form . One2ManyViewManager = instance . web . ViewManager . extend ( {
template : 'One2Many.viewmanager' ,
init : function ( parent , dataset , views , flags ) {
this . _super ( parent , dataset , views , _ . extend ( { } , flags , { $sidebar : false } ) ) ;
this . registry = this . registry . extend ( {
list : 'instance.web.form.One2ManyListView' ,
form : 'instance.web.form.One2ManyFormView' ,
kanban : 'instance.web.form.One2ManyKanbanView' ,
} ) ;
2012-07-10 07:39:28 +00:00
this . _ _ignore _blur = false ;
2012-05-16 10:16:34 +00:00
} ,
2012-10-10 12:08:49 +00:00
switch _mode : function ( mode , unused ) {
2012-05-16 10:52:51 +00:00
if ( mode !== 'form' ) {
return this . _super ( mode , unused ) ;
}
var self = this ;
2012-05-16 11:58:56 +00:00
var id = self . o2m . dataset . index !== null ? self . o2m . dataset . ids [ self . o2m . dataset . index ] : null ;
2012-10-04 15:28:37 +00:00
var pop = new instance . web . form . FormOpenPopup ( this ) ;
2012-05-16 10:52:51 +00:00
pop . show _element ( self . o2m . field . relation , id , self . o2m . build _context ( ) , {
2012-06-29 15:10:01 +00:00
title : _t ( "Open: " ) + self . o2m . string ,
2013-03-08 10:40:50 +00:00
create _function : function ( data , options ) {
return self . o2m . dataset . create ( data , options ) . done ( function ( r ) {
2012-10-01 22:02:48 +00:00
self . o2m . dataset . set _ids ( self . o2m . dataset . ids . concat ( [ r ] ) ) ;
2012-10-12 12:19:11 +00:00
self . o2m . dataset . trigger ( "dataset_changed" , r ) ;
2012-05-25 13:40:31 +00:00
} ) ;
} ,
2012-05-16 13:01:42 +00:00
write _function : function ( id , data , options ) {
2012-10-30 14:06:30 +00:00
return self . o2m . dataset . write ( id , data , { } ) . done ( function ( ) {
2012-05-16 13:01:42 +00:00
self . o2m . reload _current _view ( ) ;
} ) ;
} ,
2012-05-16 10:52:51 +00:00
alternative _form _view : self . o2m . field . views ? self . o2m . field . views [ "form" ] : undefined ,
parent _view : self . o2m . view ,
child _name : self . o2m . name ,
read _function : function ( ) {
return self . o2m . dataset . read _ids . apply ( self . o2m . dataset , arguments ) ;
} ,
form _view _options : { 'not_interactible_on_create' : true } ,
readonly : self . o2m . get ( "effective_readonly" )
} ) ;
2012-10-12 13:10:44 +00:00
pop . on ( "elements_selected" , self , function ( ) {
2012-05-25 13:40:31 +00:00
self . o2m . reload _current _view ( ) ;
} ) ;
2012-05-16 10:16:34 +00:00
} ,
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . One2ManyDataSet = instance . web . BufferedDataSet . extend ( {
2011-06-29 14:35:06 +00:00
get _context : function ( ) {
2012-11-08 10:38:56 +00:00
this . context = this . o2m . build _context ( ) ;
2011-06-29 14:35:06 +00:00
return this . context ;
}
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . One2ManyListView = instance . web . ListView . extend ( {
2011-12-13 14:49:55 +00:00
_template : 'One2Many.listview' ,
2012-06-14 12:37:31 +00:00
init : function ( parent , dataset , view _id , options ) {
this . _super ( parent , dataset , view _id , _ . extend ( options || { } , {
2012-10-19 10:07:25 +00:00
GroupsType : instance . web . form . One2ManyGroups ,
2012-06-25 13:52:15 +00:00
ListType : instance . web . form . One2ManyList
2012-06-14 12:37:31 +00:00
} ) ) ;
2012-07-17 13:23:08 +00:00
this . on ( 'edit:before' , this , this . proxy ( '_before_edit' ) ) ;
2012-08-07 07:26:50 +00:00
this . on ( 'edit:after' , this , this . proxy ( '_after_edit' ) ) ;
2012-07-17 13:23:08 +00:00
this . on ( 'save:before cancel:before' , this , this . proxy ( '_before_unedit' ) ) ;
2012-07-11 14:14:02 +00:00
this . records
2012-07-17 13:23:08 +00:00
. bind ( 'add' , this . proxy ( "changed_records" ) )
. bind ( 'edit' , this . proxy ( "changed_records" ) )
. bind ( 'remove' , this . proxy ( "changed_records" ) ) ;
2012-07-10 07:39:28 +00:00
} ,
start : function ( ) {
var ret = this . _super ( ) ;
2012-08-24 18:27:07 +00:00
this . $el
2012-07-10 07:39:28 +00:00
. off ( 'mousedown.handleButtons' )
2012-07-17 13:23:08 +00:00
. on ( 'mousedown.handleButtons' , 'table button' , this . proxy ( '_button_down' ) ) ;
2012-07-10 07:39:28 +00:00
return ret ;
2012-06-14 12:37:31 +00:00
} ,
2012-07-17 13:23:08 +00:00
changed _records : function ( ) {
2012-07-11 14:14:02 +00:00
this . o2m . trigger _on _change ( ) ;
} ,
2012-06-13 10:08:19 +00:00
is _valid : function ( ) {
2013-03-12 11:22:44 +00:00
var editor = this . editor ;
var form = editor . form ;
// If no edition is pending, the listview can not be invalid (?)
if ( ! editor . record ) {
2013-07-25 10:33:01 +00:00
return true ;
2013-03-12 11:22:44 +00:00
}
2012-06-13 15:35:55 +00:00
// If the form has not been modified, the view can only be valid
// NB: is_dirty will also be set on defaults/onchanges/whatever?
// oe_form_dirty seems to only be set on actual user actions
2012-08-24 18:27:07 +00:00
if ( ! form . $el . is ( '.oe_form_dirty' ) ) {
2012-06-13 15:35:55 +00:00
return true ;
}
2012-07-19 08:23:52 +00:00
this . o2m . _dirty _flag = true ;
2012-06-13 10:08:19 +00:00
// Otherwise validate internal form
return _ ( form . fields ) . chain ( )
. invoke ( function ( ) {
2012-07-09 11:04:26 +00:00
this . _check _css _flags ( ) ;
2012-06-13 10:08:19 +00:00
return this . is _valid ( ) ;
} )
. all ( _ . identity )
. value ( ) ;
} ,
2011-06-16 16:37:09 +00:00
do _add _record : function ( ) {
2012-07-24 17:05:50 +00:00
if ( this . editable ( ) ) {
2011-07-04 08:38:58 +00:00
this . _super . apply ( this , arguments ) ;
} else {
var self = this ;
2012-04-17 12:09:49 +00:00
var pop = new instance . web . form . SelectCreatePopup ( this ) ;
2011-12-22 09:40:12 +00:00
pop . select _element (
self . o2m . field . relation ,
{
2012-06-29 15:10:01 +00:00
title : _t ( "Create: " ) + self . o2m . string ,
2011-12-22 09:40:12 +00:00
initial _view : "form" ,
alternative _form _view : self . o2m . field . views ? self . o2m . field . views [ "form" ] : undefined ,
2013-03-08 10:40:50 +00:00
create _function : function ( data , options ) {
return self . o2m . dataset . create ( data , options ) . done ( function ( r ) {
2012-10-01 22:02:48 +00:00
self . o2m . dataset . set _ids ( self . o2m . dataset . ids . concat ( [ r ] ) ) ;
2012-10-12 12:19:11 +00:00
self . o2m . dataset . trigger ( "dataset_changed" , r ) ;
2013-03-08 10:40:50 +00:00
} ) ;
2011-12-22 09:40:12 +00:00
} ,
read _function : function ( ) {
return self . o2m . dataset . read _ids . apply ( self . o2m . dataset , arguments ) ;
} ,
parent _view : self . o2m . view ,
2012-01-03 16:34:42 +00:00
child _name : self . o2m . name ,
2011-12-22 09:40:12 +00:00
form _view _options : { 'not_interactible_on_create' : true }
2011-10-10 12:45:16 +00:00
} ,
2011-12-22 09:40:12 +00:00
self . o2m . build _domain ( ) ,
self . o2m . build _context ( )
) ;
2012-10-12 13:10:44 +00:00
pop . on ( "elements_selected" , self , function ( ) {
2011-08-11 16:03:47 +00:00
self . o2m . reload _current _view ( ) ;
2011-06-23 17:07:34 +00:00
} ) ;
2011-07-04 08:38:58 +00:00
}
2011-07-13 11:05:32 +00:00
} ,
do _activate _record : function ( index , id ) {
var self = this ;
2012-10-04 15:28:37 +00:00
var pop = new instance . web . form . FormOpenPopup ( self ) ;
2011-12-22 09:52:48 +00:00
pop . show _element ( self . o2m . field . relation , id , self . o2m . build _context ( ) , {
2012-06-29 15:10:01 +00:00
title : _t ( "Open: " ) + self . o2m . string ,
2012-05-16 13:01:42 +00:00
write _function : function ( id , data ) {
2012-10-30 14:06:30 +00:00
return self . o2m . dataset . write ( id , data , { } ) . done ( function ( ) {
2012-05-16 13:01:42 +00:00
self . o2m . reload _current _view ( ) ;
} ) ;
} ,
2011-07-13 11:05:32 +00:00
alternative _form _view : self . o2m . field . views ? self . o2m . field . views [ "form" ] : undefined ,
2011-08-29 12:13:30 +00:00
parent _view : self . o2m . view ,
2011-12-19 17:30:55 +00:00
child _name : self . o2m . name ,
2011-08-29 12:13:30 +00:00
read _function : function ( ) {
return self . o2m . dataset . read _ids . apply ( self . o2m . dataset , arguments ) ;
2011-09-30 15:46:12 +00:00
} ,
2011-10-31 10:43:04 +00:00
form _view _options : { 'not_interactible_on_create' : true } ,
2012-09-04 14:11:55 +00:00
readonly : ! this . is _action _enabled ( 'edit' ) || self . o2m . get ( "effective_readonly" )
2011-07-13 11:05:32 +00:00
} ) ;
2011-12-22 13:24:47 +00:00
} ,
2012-10-23 12:52:13 +00:00
do _button _action : function ( name , id , callback ) {
2012-07-11 14:14:02 +00:00
if ( ! _ . isNumber ( id ) ) {
instance . webclient . notification . warn (
_t ( "Action Button" ) ,
_t ( "The o2m record must be saved before an action can be used" ) ) ;
return ;
}
2012-07-09 11:01:12 +00:00
var parent _form = this . o2m . view ;
2012-07-11 14:14:02 +00:00
var self = this ;
2012-10-30 14:06:30 +00:00
this . ensure _saved ( ) . then ( function ( ) {
2012-10-04 15:28:37 +00:00
if ( parent _form )
2012-10-23 12:52:13 +00:00
return parent _form . save ( ) ;
2012-10-04 15:28:37 +00:00
else
return $ . when ( ) ;
2012-10-30 14:06:30 +00:00
} ) . done ( function ( ) {
2013-03-12 13:47:48 +00:00
if ( ! self . o2m . options . reload _on _button ) {
2013-03-13 05:10:42 +00:00
self . handle _button ( name , id , callback ) ;
2013-03-12 13:47:48 +00:00
} else {
self . handle _button ( name , id , function ( ) {
self . o2m . view . reload ( ) ;
} ) ;
}
2012-06-22 08:54:32 +00:00
} ) ;
2012-07-10 07:39:28 +00:00
} ,
2012-10-23 12:52:13 +00:00
2012-07-17 13:23:08 +00:00
_before _edit : function ( ) {
2012-07-10 07:39:28 +00:00
this . _ _ignore _blur = false ;
2012-07-17 13:23:08 +00:00
this . editor . form . on ( 'blurred' , this , this . _on _form _blur ) ;
2012-07-10 07:39:28 +00:00
} ,
2012-08-07 07:26:50 +00:00
_after _edit : function ( ) {
// The form's blur thing may be jiggered during the edition setup,
// potentially leading to the o2m instasaving the row. Cancel any
// blurring triggered the edition startup here
this . editor . form . widgetFocused ( ) ;
} ,
2012-07-17 13:23:08 +00:00
_before _unedit : function ( ) {
this . editor . form . off ( 'blurred' , this , this . _on _form _blur ) ;
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
} ,
2012-07-17 13:23:08 +00:00
_button _down : function ( ) {
2012-07-10 07:39:28 +00:00
// If a button is clicked (usually some sort of action button), it's
// the button's responsibility to ensure the editable list is in the
// correct state -> ignore form blurring
this . _ _ignore _blur = true ;
} ,
/ * *
* Handles blurring of the nested form ( saves the currently edited row ) ,
* unless the flag to ignore the event is set to ` ` true ` `
2012-07-18 13:46:07 +00:00
*
* Makes the internal form go away
2012-07-10 07:39:28 +00:00
* /
2012-07-17 13:23:08 +00:00
_on _form _blur : function ( ) {
2012-07-10 07:39:28 +00:00
if ( this . _ _ignore _blur ) {
this . _ _ignore _blur = false ;
return ;
2012-06-19 11:03:50 +00:00
}
2012-07-18 13:46:07 +00:00
// FIXME: why isn't there an API for this?
2012-08-24 18:27:07 +00:00
if ( this . editor . form . $el . hasClass ( 'oe_form_dirty' ) ) {
2012-11-06 10:38:28 +00:00
this . ensure _saved ( ) ;
2012-07-18 13:46:07 +00:00
return ;
}
this . cancel _edition ( ) ;
2012-07-10 07:39:28 +00:00
} ,
keyup _ENTER : function ( ) {
// blurring caused by hitting the [Return] key, should skip the
// autosave-on-blur and let the handler for [Return] do its thing (save
// the current row *anyway*, then create a new one/edit the next one)
this . _ _ignore _blur = true ;
this . _super . apply ( this , arguments ) ;
2012-08-06 14:34:10 +00:00
} ,
do _delete : function ( ids ) {
2012-11-16 16:44:16 +00:00
var confirm = window . confirm ;
window . confirm = function ( ) { return true ; } ;
try {
return this . _super ( ids ) ;
} finally {
window . confirm = confirm ;
}
2012-01-17 13:28:43 +00:00
}
2011-06-16 16:37:09 +00:00
} ) ;
2012-10-19 10:07:25 +00:00
instance . web . form . One2ManyGroups = instance . web . ListView . Groups . extend ( {
setup _resequence _rows : function ( ) {
if ( ! this . view . o2m . get ( 'effective_readonly' ) ) {
this . _super . apply ( this , arguments ) ;
}
}
} ) ;
2012-07-26 15:55:10 +00:00
instance . web . form . One2ManyList = instance . web . ListView . List . extend ( {
pad _table _to : function ( count ) {
2012-09-04 14:30:24 +00:00
if ( ! this . view . is _action _enabled ( 'create' ) ) {
this . _super ( count ) ;
} else {
this . _super ( count > 0 ? count - 1 : 0 ) ;
}
2012-07-26 15:55:10 +00:00
// magical invocation of wtf does that do
if ( this . view . o2m . get ( 'effective_readonly' ) ) {
return ;
}
var self = this ;
var columns = _ ( this . columns ) . filter ( function ( column ) {
return column . invisible !== '1' ;
} ) . length ;
if ( this . options . selectable ) { columns ++ ; }
if ( this . options . deletable ) { columns ++ ; }
2012-08-06 13:52:48 +00:00
2012-09-04 14:30:24 +00:00
if ( ! this . view . is _action _enabled ( 'create' ) ) {
return ;
}
2012-07-26 15:55:10 +00:00
var $cell = $ ( '<td>' , {
colspan : columns ,
'class' : 'oe_form_field_one2many_list_row_add'
2012-08-06 13:55:36 +00:00
} ) . append (
2012-10-10 21:23:52 +00:00
$ ( '<a>' , { href : '#' } ) . text ( _t ( "Add an item" ) )
2012-08-06 13:55:36 +00:00
. mousedown ( function ( ) {
// FIXME: needs to be an official API somehow
if ( self . view . editor . is _editing ( ) ) {
self . view . _ _ignore _blur = true ;
}
} )
. click ( function ( e ) {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
// FIXME: there should also be an API for that one
if ( self . view . editor . form . _ _blur _timeout ) {
clearTimeout ( self . view . editor . form . _ _blur _timeout ) ;
self . view . editor . form . _ _blur _timeout = false ;
}
2012-10-30 14:06:30 +00:00
self . view . ensure _saved ( ) . done ( function ( ) {
2012-08-06 13:55:36 +00:00
self . view . do _add _record ( ) ;
} ) ;
} ) ) ;
2012-08-06 13:52:48 +00:00
var $padding = this . $current . find ( 'tr:not([data-id]):first' ) ;
var $newrow = $ ( '<tr>' ) . append ( $cell ) ;
if ( $padding . length ) {
$padding . before ( $newrow ) ;
} else {
2013-07-25 10:33:01 +00:00
this . $current . append ( $newrow ) ;
2012-08-06 13:52:48 +00:00
}
2012-07-26 15:55:10 +00:00
}
} ) ;
2011-06-16 16:37:09 +00:00
2012-04-17 12:09:49 +00:00
instance . web . form . One2ManyFormView = instance . web . FormView . extend ( {
2011-12-21 16:43:35 +00:00
form _template : 'One2Many.formview' ,
2012-10-18 11:49:50 +00:00
load _form : function ( data ) {
2011-12-21 16:43:35 +00:00
this . _super ( data ) ;
2012-01-11 14:37:12 +00:00
var self = this ;
2012-04-18 15:17:05 +00:00
this . $buttons . find ( 'button.oe_form_button_create' ) . click ( function ( ) {
2012-10-30 14:06:30 +00:00
self . save ( ) . done ( self . on _button _new ) ;
2012-01-11 14:37:12 +00:00
} ) ;
2012-02-15 10:34:05 +00:00
} ,
do _notify _change : function ( ) {
if ( this . dataset . parent _view ) {
this . dataset . parent _view . do _notify _change ( ) ;
} else {
this . _super . apply ( this , arguments ) ;
}
2011-12-21 16:43:35 +00:00
}
} ) ;
2012-04-06 12:30:28 +00:00
var lazy _build _o2m _kanban _view = function ( ) {
2012-11-07 16:19:55 +00:00
if ( ! instance . web _kanban || instance . web . form . One2ManyKanbanView )
return ;
instance . web . form . One2ManyKanbanView = instance . web _kanban . KanbanView . extend ( {
} ) ;
} ;
2012-04-06 12:30:28 +00:00
2012-06-21 23:56:41 +00:00
instance . web . form . FieldMany2ManyTags = instance . web . form . AbstractField . extend ( instance . web . form . CompletionFieldMixin , instance . web . form . ReinitializeFieldMixin , {
2012-05-07 12:54:34 +00:00
template : "FieldMany2ManyTags" ,
2012-05-07 12:22:46 +00:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
2012-05-07 15:15:48 +00:00
instance . web . form . CompletionFieldMixin . init . call ( this ) ;
this . set ( { "value" : [ ] } ) ;
2012-05-10 08:59:13 +00:00
this . _display _orderer = new instance . web . DropMisordered ( ) ;
this . _drop _shown = false ;
2012-05-07 12:22:46 +00:00
} ,
2012-05-07 15:15:48 +00:00
initialize _content : function ( ) {
if ( this . get ( "effective_readonly" ) )
return ;
2012-05-07 12:22:46 +00:00
var self = this ;
2013-03-12 13:14:12 +00:00
var ignore _blur = false ;
2012-11-07 16:19:55 +00:00
self . $text = this . $ ( "textarea" ) ;
2012-05-07 15:15:48 +00:00
self . $text . textext ( {
2012-05-09 13:24:19 +00:00
plugins : 'tags arrow autocomplete' ,
2012-05-04 11:06:15 +00:00
autocomplete : {
render : function ( suggestion ) {
2012-05-09 13:24:19 +00:00
return $ ( '<span class="text-label"/>' ) .
data ( 'index' , suggestion [ 'index' ] ) . html ( suggestion [ 'label' ] ) ;
2012-05-04 11:06:15 +00:00
}
} ,
2012-05-07 12:22:46 +00:00
ext : {
autocomplete : {
2012-05-10 08:59:13 +00:00
selectFromDropdown : function ( ) {
2013-06-07 13:22:03 +00:00
this . trigger ( 'hideDropdown' ) ;
2012-05-07 15:15:48 +00:00
var index = Number ( this . selectedSuggestionElement ( ) . children ( ) . children ( ) . data ( 'index' ) ) ;
var data = self . search _result [ index ] ;
2012-05-09 15:32:46 +00:00
if ( data . id ) {
self . add _id ( data . id ) ;
} else {
2013-03-12 13:14:12 +00:00
ignore _blur = true ;
2012-05-09 15:32:46 +00:00
data . action ( ) ;
}
2013-06-07 13:22:03 +00:00
this . trigger ( 'setSuggestions' , { result : [ ] } ) ;
2012-05-07 15:15:48 +00:00
} ,
} ,
tags : {
isTagAllowed : function ( tag ) {
2012-11-07 16:19:55 +00:00
return ! ! tag . name ;
2012-05-07 15:15:48 +00:00
} ,
2012-05-08 15:03:11 +00:00
removeTag : function ( tag ) {
var id = tag . data ( "id" ) ;
self . set ( { "value" : _ . without ( self . get ( "value" ) , id ) } ) ;
} ,
renderTag : function ( stuff ) {
return $ . fn . textext . TextExtTags . prototype . renderTag .
call ( this , stuff ) . data ( "id" , stuff . id ) ;
} ,
2012-05-07 15:15:48 +00:00
} ,
itemManager : {
itemToString : function ( item ) {
return item . name ;
2012-05-07 12:22:46 +00:00
} ,
} ,
2012-12-04 10:23:04 +00:00
core : {
onSetInputData : function ( e , data ) {
2013-07-25 10:07:49 +00:00
if ( data === '' ) {
2012-12-04 10:23:04 +00:00
this . _plugins . autocomplete . _suggestions = null ;
}
this . input ( ) . val ( data ) ;
} ,
} ,
2012-05-07 12:22:46 +00:00
} ,
2012-05-04 11:06:15 +00:00
} ) . bind ( 'getSuggestions' , function ( e , data ) {
2012-05-07 12:54:34 +00:00
var _this = this ;
2012-05-07 12:22:46 +00:00
var str = ! ! data ? data . query || '' : '' ;
2012-10-30 14:06:30 +00:00
self . get _search _result ( str ) . done ( function ( result ) {
2012-05-07 12:54:34 +00:00
self . search _result = result ;
$ ( _this ) . trigger ( 'setSuggestions' , { result : _ . map ( result , function ( el , i ) {
return _ . extend ( el , { index : i } ) ;
} ) } ) ;
2012-05-07 12:22:46 +00:00
} ) ;
2012-05-10 08:59:13 +00:00
} ) . bind ( 'hideDropdown' , function ( ) {
self . _drop _shown = false ;
2012-05-25 12:52:39 +00:00
} ) . bind ( 'showDropdown' , function ( ) {
2012-05-10 08:59:13 +00:00
self . _drop _shown = true ;
2012-05-04 11:06:15 +00:00
} ) ;
2012-05-07 15:15:48 +00:00
self . tags = self . $text . textext ( ) [ 0 ] . tags ( ) ;
2012-11-14 11:45:08 +00:00
self . $text
. focusin ( function ( ) {
self . trigger ( 'focused' ) ;
2013-03-12 13:14:12 +00:00
ignore _blur = false ;
2012-11-14 11:45:08 +00:00
} )
. focusout ( function ( ) {
self . $text . trigger ( "setInputData" , "" ) ;
2013-03-12 13:14:12 +00:00
if ( ! ignore _blur ) {
self . trigger ( 'blurred' ) ;
}
2012-11-14 11:45:08 +00:00
} ) . keydown ( function ( e ) {
if ( e . which === $ . ui . keyCode . TAB && self . _drop _shown ) {
self . $text . textext ( ) [ 0 ] . autocomplete ( ) . selectFromDropdown ( ) ;
}
} ) ;
2012-05-07 15:15:48 +00:00
} ,
set _value : function ( value _ ) {
value _ = value _ || [ ] ;
if ( value _ . length >= 1 && value _ [ 0 ] instanceof Array ) {
value _ = value _ [ 0 ] [ 2 ] ;
}
this . _super ( value _ ) ;
} ,
2012-11-19 12:24:13 +00:00
is _false : function ( ) {
return _ ( this . get ( "value" ) ) . isEmpty ( ) ;
} ,
2012-05-07 15:15:48 +00:00
get _value : function ( ) {
2012-05-08 15:03:11 +00:00
var tmp = [ commands . replace _with ( this . get ( "value" ) ) ] ;
2012-05-07 15:15:48 +00:00
return tmp ;
} ,
2012-05-30 09:39:16 +00:00
get _search _blacklist : function ( ) {
return this . get ( "value" ) ;
} ,
2012-05-07 15:15:48 +00:00
render _value : function ( ) {
var self = this ;
2012-10-04 14:13:51 +00:00
var dataset = new instance . web . DataSetStatic ( this , this . field . relation , self . build _context ( ) ) ;
2012-11-07 16:19:55 +00:00
var values = self . get ( "value" ) ;
2012-05-09 15:41:24 +00:00
var handle _names = function ( data ) {
2012-11-06 16:25:25 +00:00
if ( self . isDestroyed ( ) )
return ;
2012-05-08 10:00:14 +00:00
var indexed = { } ;
_ . each ( data , function ( el ) {
indexed [ el [ 0 ] ] = el ;
} ) ;
2012-07-25 14:31:50 +00:00
data = _ . map ( values , function ( el ) { return indexed [ el ] ; } ) ;
2012-05-07 15:15:48 +00:00
if ( ! self . get ( "effective_readonly" ) ) {
self . tags . containerElement ( ) . children ( ) . remove ( ) ;
2012-11-07 16:19:55 +00:00
self . $ ( 'textarea' ) . css ( "padding-left" , "3px" ) ;
2012-05-08 10:00:14 +00:00
self . tags . addTags ( _ . map ( data , function ( el ) { return { name : el [ 1 ] , id : el [ 0 ] } ; } ) ) ;
2012-05-07 15:15:48 +00:00
} else {
2012-08-24 18:27:07 +00:00
self . $el . html ( QWeb . render ( "FieldMany2ManyTag" , { elements : data } ) ) ;
2012-05-07 15:15:48 +00:00
}
2012-05-09 15:41:24 +00:00
} ;
2012-07-25 14:31:50 +00:00
if ( ! values || values . length > 0 ) {
2012-10-30 14:06:30 +00:00
this . _display _orderer . add ( dataset . name _get ( values ) ) . done ( handle _names ) ;
2012-05-09 15:41:24 +00:00
} else {
handle _names ( [ ] ) ;
}
2012-05-04 11:06:15 +00:00
} ,
2012-05-09 15:32:46 +00:00
add _id : function ( id ) {
this . set ( { 'value' : _ . uniq ( this . get ( 'value' ) . concat ( [ id ] ) ) } ) ;
} ,
2012-12-11 14:56:52 +00:00
focus : function ( ) {
2013-05-01 05:41:29 +00:00
var input = this . $text && this . $text [ 0 ] ;
return input ? input . focus ( ) : false ;
2012-12-11 14:56:52 +00:00
} ,
2013-02-15 11:09:27 +00:00
set _dimensions : function ( height , width ) {
this . _super ( height , width ) ;
this . $ ( "textarea" ) . css ( {
width : width ,
minHeight : height
} ) ;
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2012-05-04 11:06:15 +00:00
2012-10-23 12:59:57 +00:00
/ * *
widget options :
- reload _on _button : Reload the whole form view if click on a button in a list view .
If you see this options , do not use it , it ' s basically a dirty hack to make one
precise o2m to behave the way we want .
* /
2012-11-29 13:40:51 +00:00
instance . web . form . FieldMany2Many = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2011-07-04 15:00:17 +00:00
multi _selection : false ,
2012-03-29 10:03:08 +00:00
disable _utility _classes : true ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2011-10-26 15:23:05 +00:00
this . is _loaded = $ . Deferred ( ) ;
2012-05-04 13:31:11 +00:00
this . dataset = new instance . web . form . Many2ManyDataSet ( this , this . field . relation ) ;
2011-07-01 10:27:27 +00:00
this . dataset . m2m = this ;
2012-10-12 08:43:37 +00:00
var self = this ;
2012-10-10 14:36:07 +00:00
this . dataset . on ( 'unlink' , self , function ( ids ) {
2012-04-17 15:45:05 +00:00
self . dataset _changed ( ) ;
2011-05-31 14:11:19 +00:00
} ) ;
2012-10-12 08:43:37 +00:00
this . set _value ( [ ] ) ;
2012-11-29 13:40:51 +00:00
this . list _dm = new instance . web . DropMisordered ( ) ;
this . render _value _dm = new instance . web . DropMisordered ( ) ;
2012-10-12 08:43:37 +00:00
} ,
2012-11-29 13:40:51 +00:00
initialize _content : function ( ) {
2012-10-12 08:43:37 +00:00
var self = this ;
2012-11-29 13:40:51 +00:00
this . $el . addClass ( 'oe_form_field oe_form_field_many2many' ) ;
this . list _view = new instance . web . form . Many2ManyListView ( this , this . dataset , false , {
'addable' : this . get ( "effective_readonly" ) ? null : _t ( "Add" ) ,
'deletable' : this . get ( "effective_readonly" ) ? false : true ,
'selectable' : this . multi _selection ,
'sortable' : false ,
'reorderable' : false ,
'import_enabled' : false ,
2012-03-16 10:39:31 +00:00
} ) ;
2012-11-29 13:40:51 +00:00
var embedded = ( this . field . views || { } ) . tree ;
if ( embedded ) {
this . list _view . set _embedded _view ( embedded ) ;
}
this . list _view . m2m _field = this ;
var loaded = $ . Deferred ( ) ;
this . list _view . on ( "list_view_loaded" , this , function ( ) {
loaded . resolve ( ) ;
2012-06-12 13:15:43 +00:00
} ) ;
2012-11-29 13:40:51 +00:00
this . list _view . appendTo ( this . $el ) ;
var old _def = self . is _loaded ;
self . is _loaded = $ . Deferred ( ) . done ( function ( ) {
old _def . resolve ( ) ;
} ) ;
this . list _dm . add ( loaded ) . then ( function ( ) {
self . is _loaded . resolve ( ) ;
2012-06-12 13:15:43 +00:00
} ) ;
2012-11-29 13:40:51 +00:00
} ,
destroy _content : function ( ) {
this . list _view . destroy ( ) ;
this . list _view = undefined ;
2011-04-22 15:54:52 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
value _ = value _ || [ ] ;
if ( value _ . length >= 1 && value _ [ 0 ] instanceof Array ) {
value _ = value _ [ 0 ] [ 2 ] ;
2011-06-27 09:05:32 +00:00
}
2012-04-17 14:32:27 +00:00
this . _super ( value _ ) ;
2011-04-26 12:11:46 +00:00
} ,
2012-06-07 14:19:30 +00:00
get _value : function ( ) {
return [ commands . replace _with ( this . get ( 'value' ) ) ] ;
} ,
2012-06-25 13:52:15 +00:00
is _false : function ( ) {
2012-10-12 08:43:37 +00:00
return _ ( this . get ( "value" ) ) . isEmpty ( ) ;
2011-10-31 10:27:52 +00:00
} ,
2012-10-12 08:43:37 +00:00
render _value : function ( ) {
2011-10-26 15:23:05 +00:00
var self = this ;
2012-10-12 08:43:37 +00:00
this . dataset . set _ids ( this . get ( "value" ) ) ;
2012-11-29 13:40:51 +00:00
this . render _value _dm . add ( this . is _loaded ) . then ( function ( ) {
2011-10-26 15:23:05 +00:00
return self . list _view . reload _content ( ) ;
} ) ;
} ,
2012-04-17 15:45:05 +00:00
dataset _changed : function ( ) {
2012-10-12 08:43:37 +00:00
this . internal _set _value ( this . dataset . ids ) ;
2012-04-17 15:45:05 +00:00
} ,
2011-07-01 10:27:27 +00:00
} ) ;
2012-05-04 13:31:11 +00:00
instance . web . form . Many2ManyDataSet = instance . web . DataSetStatic . extend ( {
2011-07-01 10:27:27 +00:00
get _context : function ( ) {
this . context = this . m2m . build _context ( ) ;
return this . context ;
2011-03-30 14:00:48 +00:00
}
} ) ;
2011-09-12 11:43:50 +00:00
/ * *
* @ class
2012-04-17 12:09:49 +00:00
* @ extends instance . web . ListView
2011-09-12 11:43:50 +00:00
* /
2012-05-04 13:31:11 +00:00
instance . web . form . Many2ManyListView = instance . web . ListView . extend ( /** @lends instance.web.form.Many2ManyListView# */ {
2011-05-27 15:10:00 +00:00
do _add _record : function ( ) {
2012-04-17 12:09:49 +00:00
var pop = new instance . web . form . SelectCreatePopup ( this ) ;
2011-12-22 09:40:12 +00:00
pop . select _element (
this . model ,
{
2012-06-29 15:10:01 +00:00
title : _t ( "Add: " ) + this . m2m _field . string
2011-12-22 09:40:12 +00:00
} ,
2012-04-17 12:09:49 +00:00
new instance . web . CompoundDomain ( this . m2m _field . build _domain ( ) , [ "!" , [ "id" , "in" , this . m2m _field . dataset . ids ] ] ) ,
2011-12-22 09:40:12 +00:00
this . m2m _field . build _context ( )
) ;
2011-05-09 11:52:33 +00:00
var self = this ;
2012-10-12 13:10:44 +00:00
pop . on ( "elements_selected" , self , function ( element _ids ) {
2012-10-18 13:41:23 +00:00
var reload = false ;
_ ( element _ids ) . each ( function ( id ) {
if ( ! _ . detect ( self . dataset . ids , function ( x ) { return x == id ; } ) ) {
self . dataset . set _ids ( self . dataset . ids . concat ( [ id ] ) ) ;
2012-04-17 15:45:05 +00:00
self . m2m _field . dataset _changed ( ) ;
2012-10-18 13:41:23 +00:00
reload = true ;
2011-06-15 15:04:40 +00:00
}
} ) ;
2012-10-18 13:41:23 +00:00
if ( reload ) {
self . reload _content ( ) ;
}
2011-05-09 11:52:33 +00:00
} ) ;
2011-04-26 14:13:34 +00:00
} ,
2011-05-27 15:10:00 +00:00
do _activate _record : function ( index , id ) {
2011-07-13 09:59:49 +00:00
var self = this ;
2012-04-17 12:09:49 +00:00
var pop = new instance . web . form . FormOpenPopup ( this ) ;
2011-12-22 09:40:12 +00:00
pop . show _element ( this . dataset . model , id , this . m2m _field . build _context ( ) , {
2012-06-29 15:10:01 +00:00
title : _t ( "Open: " ) + this . m2m _field . string ,
2012-03-16 10:39:31 +00:00
readonly : this . getParent ( ) . get ( "effective_readonly" )
2011-12-22 09:40:12 +00:00
} ) ;
2012-10-10 10:12:46 +00:00
pop . on ( 'write_completed' , self , self . reload _content ) ;
2012-10-23 12:59:57 +00:00
} ,
do _button _action : function ( name , id , callback ) {
var self = this ;
var _sup = _ . bind ( this . _super , this ) ;
if ( ! this . m2m _field . options . reload _on _button ) {
return _sup ( name , id , callback ) ;
} else {
2012-10-30 14:06:30 +00:00
return this . m2m _field . view . save ( ) . then ( function ( ) {
2012-10-23 12:59:57 +00:00
return _sup ( name , id , function ( ) {
self . m2m _field . view . reload ( ) ;
} ) ;
} ) ;
}
} ,
2013-03-05 09:19:56 +00:00
is _action _enabled : function ( ) { return true ; } ,
2011-03-30 14:00:48 +00:00
} ) ;
2012-06-21 23:56:41 +00:00
instance . web . form . FieldMany2ManyKanban = instance . web . form . AbstractField . extend ( instance . web . form . CompletionFieldMixin , {
2012-05-24 12:59:35 +00:00
disable _utility _classes : true ,
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2012-05-25 12:52:39 +00:00
instance . web . form . CompletionFieldMixin . init . call ( this ) ;
2012-05-24 12:59:35 +00:00
m2m _kanban _lazy _init ( ) ;
this . is _loaded = $ . Deferred ( ) ;
this . initial _is _loaded = this . is _loaded ;
var self = this ;
this . dataset = new instance . web . form . Many2ManyDataSet ( this , this . field . relation ) ;
this . dataset . m2m = this ;
2012-10-10 14:36:07 +00:00
this . dataset . on ( 'unlink' , self , function ( ids ) {
2012-05-24 12:59:35 +00:00
self . dataset _changed ( ) ;
} ) ;
2012-10-12 09:18:20 +00:00
} ,
start : function ( ) {
this . _super . apply ( this , arguments ) ;
2012-07-12 12:56:37 +00:00
2012-10-12 09:18:20 +00:00
var self = this ;
self . load _view ( ) ;
2012-11-26 10:25:33 +00:00
self . on ( "change:effective_readonly" , self , function ( ) {
self . is _loaded = self . is _loaded . then ( function ( ) {
self . kanban _view . destroy ( ) ;
return $ . when ( self . load _view ( ) ) . done ( function ( ) {
self . render _value ( ) ;
2012-05-24 12:59:35 +00:00
} ) ;
} ) ;
2012-11-26 10:25:33 +00:00
} ) ;
2012-05-24 12:59:35 +00:00
} ,
set _value : function ( value _ ) {
value _ = value _ || [ ] ;
if ( value _ . length >= 1 && value _ [ 0 ] instanceof Array ) {
value _ = value _ [ 0 ] [ 2 ] ;
}
this . _super ( value _ ) ;
} ,
2012-10-22 14:40:21 +00:00
get _value : function ( ) {
return [ commands . replace _with ( this . get ( 'value' ) ) ] ;
} ,
2012-05-24 12:59:35 +00:00
load _view : function ( ) {
var self = this ;
this . kanban _view = new instance . web . form . Many2ManyKanbanView ( this , this . dataset , false , {
'create_text' : _t ( "Add" ) ,
'creatable' : self . get ( "effective_readonly" ) ? false : true ,
'quick_creatable' : self . get ( "effective_readonly" ) ? false : true ,
2012-06-04 10:37:35 +00:00
'read_only_mode' : self . get ( "effective_readonly" ) ? true : false ,
'confirm_on_delete' : false ,
2012-05-24 12:59:35 +00:00
} ) ;
var embedded = ( this . field . views || { } ) . kanban ;
if ( embedded ) {
this . kanban _view . set _embedded _view ( embedded ) ;
}
2012-05-25 12:52:39 +00:00
this . kanban _view . m2m = this ;
2012-05-24 12:59:35 +00:00
var loaded = $ . Deferred ( ) ;
2012-10-18 11:49:50 +00:00
this . kanban _view . on ( "kanban_view_loaded" , self , function ( ) {
2012-05-24 12:59:35 +00:00
self . initial _is _loaded . resolve ( ) ;
loaded . resolve ( ) ;
} ) ;
2012-10-10 12:08:49 +00:00
this . kanban _view . on ( 'switch_mode' , this , this . open _popup ) ;
2012-10-30 14:06:30 +00:00
$ . async _when ( ) . done ( function ( ) {
2012-08-24 18:27:07 +00:00
self . kanban _view . appendTo ( self . $el ) ;
2012-05-24 12:59:35 +00:00
} ) ;
return loaded ;
} ,
2012-10-12 09:18:20 +00:00
render _value : function ( ) {
2012-05-24 12:59:35 +00:00
var self = this ;
2012-10-22 14:40:21 +00:00
this . dataset . set _ids ( this . get ( "value" ) ) ;
2012-10-30 14:06:30 +00:00
this . is _loaded = this . is _loaded . then ( function ( ) {
2012-05-24 12:59:35 +00:00
return self . kanban _view . do _search ( self . build _domain ( ) , self . dataset . get _context ( ) , [ ] ) ;
} ) ;
} ,
dataset _changed : function ( ) {
2012-10-22 14:40:21 +00:00
this . set ( { 'value' : this . dataset . ids } ) ;
2012-05-24 12:59:35 +00:00
} ,
2012-05-24 14:42:51 +00:00
open _popup : function ( type , unused ) {
2012-05-24 12:59:35 +00:00
if ( type !== "form" )
return ;
var self = this ;
2013-07-25 10:07:49 +00:00
var pop ;
2012-05-24 14:42:51 +00:00
if ( this . dataset . index === null ) {
2013-07-25 10:07:49 +00:00
pop = new instance . web . form . SelectCreatePopup ( this ) ;
2012-05-24 14:42:51 +00:00
pop . select _element (
this . field . relation ,
{
2012-06-29 15:10:01 +00:00
title : _t ( "Add: " ) + this . string
2012-05-24 14:42:51 +00:00
} ,
new instance . web . CompoundDomain ( this . build _domain ( ) , [ "!" , [ "id" , "in" , this . dataset . ids ] ] ) ,
this . build _context ( )
) ;
2012-10-12 13:10:44 +00:00
pop . on ( "elements_selected" , self , function ( element _ids ) {
2012-05-24 14:42:51 +00:00
_ . each ( element _ids , function ( one _id ) {
if ( ! _ . detect ( self . dataset . ids , function ( x ) { return x == one _id ; } ) ) {
self . dataset . set _ids ( [ ] . concat ( self . dataset . ids , [ one _id ] ) ) ;
self . dataset _changed ( ) ;
2012-10-12 09:18:20 +00:00
self . render _value ( ) ;
2012-05-24 14:42:51 +00:00
}
} ) ;
2012-05-24 12:59:35 +00:00
} ) ;
2012-05-24 14:42:51 +00:00
} else {
var id = self . dataset . ids [ self . dataset . index ] ;
2013-07-25 10:07:49 +00:00
pop = new instance . web . form . FormOpenPopup ( this ) ;
2012-05-24 14:42:51 +00:00
pop . show _element ( self . field . relation , id , self . build _context ( ) , {
2012-06-29 15:10:01 +00:00
title : _t ( "Open: " ) + self . string ,
2012-05-24 14:42:51 +00:00
write _function : function ( id , data , options ) {
2012-10-30 14:06:30 +00:00
return self . dataset . write ( id , data , { } ) . done ( function ( ) {
2012-10-12 09:18:20 +00:00
self . render _value ( ) ;
2012-05-24 14:42:51 +00:00
} ) ;
} ,
alternative _form _view : self . field . views ? self . field . views [ "form" ] : undefined ,
parent _view : self . view ,
child _name : self . name ,
readonly : self . get ( "effective_readonly" )
} ) ;
}
2012-05-24 12:59:35 +00:00
} ,
2012-05-25 13:09:14 +00:00
add _id : function ( id ) {
this . quick _create . add _id ( id ) ;
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2012-05-24 12:59:35 +00:00
function m2m _kanban _lazy _init ( ) {
if ( instance . web . form . Many2ManyKanbanView )
return ;
instance . web . form . Many2ManyKanbanView = instance . web _kanban . KanbanView . extend ( {
2012-05-25 12:52:39 +00:00
quick _create _class : 'instance.web.form.Many2ManyQuickCreate' ,
2012-05-25 12:09:47 +00:00
_is _quick _create _enabled : function ( ) {
return this . _super ( ) && ! this . group _by ;
} ,
} ) ;
instance . web . form . Many2ManyQuickCreate = instance . web . Widget . extend ( {
template : 'Many2ManyKanban.quick_create' ,
2012-07-12 12:56:37 +00:00
2012-05-25 12:09:47 +00:00
/ * *
* close _btn : If true , the widget will display a "Close" button able to trigger
* a "close" event .
* /
init : function ( parent , dataset , context , buttons ) {
this . _super ( parent ) ;
this . m2m = this . getParent ( ) . view . m2m ;
2012-05-25 13:09:14 +00:00
this . m2m . quick _create = this ;
2012-05-25 12:09:47 +00:00
this . _dataset = dataset ;
this . _buttons = buttons || false ;
this . _context = context || { } ;
} ,
start : function ( ) {
var self = this ;
2012-08-24 18:27:07 +00:00
self . $text = this . $el . find ( 'input' ) . css ( "width" , "200px" ) ;
2012-05-25 12:52:39 +00:00
self . $text . textext ( {
plugins : 'arrow autocomplete' ,
autocomplete : {
render : function ( suggestion ) {
return $ ( '<span class="text-label"/>' ) .
data ( 'index' , suggestion [ 'index' ] ) . html ( suggestion [ 'label' ] ) ;
}
} ,
ext : {
autocomplete : {
selectFromDropdown : function ( ) {
$ ( this ) . trigger ( 'hideDropdown' ) ;
var index = Number ( this . selectedSuggestionElement ( ) . children ( ) . children ( ) . data ( 'index' ) ) ;
var data = self . search _result [ index ] ;
if ( data . id ) {
self . add _id ( data . id ) ;
} else {
data . action ( ) ;
}
} ,
} ,
itemManager : {
itemToString : function ( item ) {
return item . name ;
} ,
} ,
} ,
} ) . bind ( 'getSuggestions' , function ( e , data ) {
var _this = this ;
var str = ! ! data ? data . query || '' : '' ;
2012-10-30 14:06:30 +00:00
self . m2m . get _search _result ( str ) . done ( function ( result ) {
2012-05-25 12:52:39 +00:00
self . search _result = result ;
$ ( _this ) . trigger ( 'setSuggestions' , { result : _ . map ( result , function ( el , i ) {
return _ . extend ( el , { index : i } ) ;
} ) } ) ;
} ) ;
} ) ;
self . $text . focusout ( function ( ) {
self . $text . val ( "" ) ;
} ) ;
2012-05-25 12:09:47 +00:00
} ,
focus : function ( ) {
2012-12-11 14:56:52 +00:00
this . $text [ 0 ] . focus ( ) ;
2012-05-25 12:09:47 +00:00
} ,
2012-05-25 12:52:39 +00:00
add _id : function ( id ) {
2012-05-25 13:09:14 +00:00
var self = this ;
self . $text . val ( "" ) ;
2012-05-25 12:52:39 +00:00
self . trigger ( 'added' , id ) ;
2012-06-04 12:36:09 +00:00
this . m2m . dataset _changed ( ) ;
2012-05-25 12:52:39 +00:00
} ,
2012-05-24 12:59:35 +00:00
} ) ;
}
2012-05-16 14:06:22 +00:00
/ * *
* Class with everything which is common between FormOpenPopup and SelectCreatePopup .
* /
2012-08-14 13:42:46 +00:00
instance . web . form . AbstractFormPopup = instance . web . Widget . extend ( {
2012-05-16 11:58:56 +00:00
template : "AbstractFormPopup.render" ,
/ * *
* options :
2012-05-16 13:01:42 +00:00
* - readonly : only applicable when not in creation mode , default to false
2012-05-16 14:06:22 +00:00
* - alternative _form _view
2013-02-04 12:43:48 +00:00
* - view _id
2012-05-16 14:06:22 +00:00
* - write _function
* - read _function
* - create _function
* - parent _view
* - child _name
* - form _view _options
2012-05-16 11:58:56 +00:00
* /
init _popup : function ( model , row _id , domain , context , options ) {
this . row _id = row _id ;
this . model = model ;
this . domain = domain || [ ] ;
this . context = context || { } ;
this . options = options ;
_ . defaults ( this . options , {
} ) ;
} ,
2012-05-16 13:01:42 +00:00
init _dataset : function ( ) {
var self = this ;
2012-05-16 14:01:19 +00:00
this . created _elements = [ ] ;
2012-05-16 13:01:42 +00:00
this . dataset = new instance . web . ProxyDataSet ( this , this . model , this . context ) ;
this . dataset . read _function = this . options . read _function ;
2013-03-08 10:40:50 +00:00
this . dataset . create _function = function ( data , options , sup ) {
2012-05-16 13:01:42 +00:00
var fct = self . options . create _function || sup ;
2013-03-08 10:40:50 +00:00
return fct . call ( this , data , options ) . done ( function ( r ) {
2012-10-25 14:11:40 +00:00
self . trigger ( 'create_completed saved' , r ) ;
2012-10-04 07:00:55 +00:00
self . created _elements . push ( r ) ;
2012-05-16 13:01:42 +00:00
} ) ;
} ;
this . dataset . write _function = function ( id , data , options , sup ) {
var fct = self . options . write _function || sup ;
2012-11-08 15:22:31 +00:00
return fct . call ( this , id , data , options ) . done ( function ( r ) {
self . trigger ( 'write_completed saved' , r ) ;
2012-10-08 11:40:26 +00:00
} ) ;
2012-05-16 13:01:42 +00:00
} ;
this . dataset . parent _view = this . options . parent _view ;
this . dataset . child _name = this . options . child _name ;
} ,
display _popup : function ( ) {
2012-05-16 14:01:19 +00:00
var self = this ;
2012-05-16 13:01:42 +00:00
this . renderElement ( ) ;
2012-07-20 12:35:28 +00:00
var dialog = new instance . web . Dialog ( this , {
2012-05-16 14:13:28 +00:00
min _width : '800px' ,
2012-07-20 12:35:28 +00:00
dialogClass : 'oe_act_window' ,
2012-05-16 13:01:42 +00:00
close : function ( ) {
2012-06-04 12:36:09 +00:00
self . check _exit ( true ) ;
2012-05-16 13:01:42 +00:00
} ,
2012-05-16 14:13:28 +00:00
title : this . options . title || "" ,
2012-08-24 18:27:07 +00:00
} , this . $el ) . open ( ) ;
2012-10-15 13:24:44 +00:00
this . $buttonpane = dialog . $buttons ;
2012-05-16 13:01:42 +00:00
this . start ( ) ;
} ,
2012-05-16 11:58:56 +00:00
setup _form _view : function ( ) {
var self = this ;
2012-05-16 14:01:19 +00:00
if ( this . row _id ) {
this . dataset . ids = [ this . row _id ] ;
this . dataset . index = 0 ;
} else {
this . dataset . index = null ;
}
2012-05-16 11:58:56 +00:00
var options = _ . clone ( self . options . form _view _options ) || { } ;
2013-06-17 16:28:27 +00:00
if ( this . row _id !== null ) {
options . initial _mode = this . options . readonly ? "view" : "edit" ;
}
2012-07-20 12:35:28 +00:00
_ . extend ( options , {
$buttons : this . $buttonpane ,
} ) ;
2013-02-04 12:43:48 +00:00
this . view _form = new instance . web . FormView ( this , this . dataset , this . options . view _id || false , options ) ;
2012-05-16 11:58:56 +00:00
if ( this . options . alternative _form _view ) {
this . view _form . set _embedded _view ( this . options . alternative _form _view ) ;
}
2012-08-24 18:27:07 +00:00
this . view _form . appendTo ( this . $el . find ( ".oe_popup_form" ) ) ;
2012-10-18 11:49:50 +00:00
this . view _form . on ( "form_view_loaded" , self , function ( ) {
2012-05-16 11:58:56 +00:00
var multi _select = self . row _id === null && ! self . options . disable _multiple _selection ;
2012-08-10 14:50:48 +00:00
self . $buttonpane . html ( QWeb . render ( "AbstractFormPopup.buttons" , {
multi _select : multi _select ,
readonly : self . row _id !== null && self . options . readonly ,
} ) ) ;
2012-07-20 12:35:28 +00:00
var $snbutton = self . $buttonpane . find ( ".oe_abstractformpopup-form-save-new" ) ;
2012-05-16 11:58:56 +00:00
$snbutton . click ( function ( ) {
2012-10-30 14:06:30 +00:00
$ . when ( self . view _form . save ( ) ) . done ( function ( ) {
2012-05-16 11:58:56 +00:00
self . view _form . reload _mutex . exec ( function ( ) {
self . view _form . on _button _new ( ) ;
} ) ;
} ) ;
} ) ;
2012-07-20 12:35:28 +00:00
var $sbutton = self . $buttonpane . find ( ".oe_abstractformpopup-form-save" ) ;
2012-05-16 11:58:56 +00:00
$sbutton . click ( function ( ) {
2012-10-30 14:06:30 +00:00
$ . when ( self . view _form . save ( ) ) . done ( function ( ) {
2012-05-16 11:58:56 +00:00
self . view _form . reload _mutex . exec ( function ( ) {
self . check _exit ( ) ;
} ) ;
} ) ;
} ) ;
2012-07-20 12:35:28 +00:00
var $cbutton = self . $buttonpane . find ( ".oe_abstractformpopup-form-close" ) ;
2012-05-16 11:58:56 +00:00
$cbutton . click ( function ( ) {
2013-02-19 14:32:15 +00:00
self . view _form . trigger ( 'on_button_cancel' ) ;
2012-05-16 11:58:56 +00:00
self . check _exit ( ) ;
} ) ;
self . view _form . do _show ( ) ;
} ) ;
} ,
2012-10-12 13:10:44 +00:00
select _elements : function ( element _ids ) {
this . trigger ( "elements_selected" , element _ids ) ;
2012-05-16 14:01:19 +00:00
} ,
2012-06-04 12:36:09 +00:00
check _exit : function ( no _destroy ) {
2012-05-16 14:01:19 +00:00
if ( this . created _elements . length > 0 ) {
2012-10-12 13:10:44 +00:00
this . select _elements ( this . created _elements ) ;
2012-06-04 12:36:09 +00:00
this . created _elements = [ ] ;
2012-05-16 14:01:19 +00:00
}
2012-10-25 14:11:40 +00:00
this . trigger ( 'closed' ) ;
2012-05-16 11:58:56 +00:00
this . destroy ( ) ;
} ,
2012-11-06 13:41:45 +00:00
destroy : function ( ) {
2012-11-06 14:59:40 +00:00
this . trigger ( 'closed' ) ;
2012-11-06 13:41:45 +00:00
if ( this . $el . is ( ":data(dialog)" ) ) {
this . $el . dialog ( 'close' ) ;
}
this . _super ( ) ;
} ,
2012-05-16 11:58:56 +00:00
} ) ;
2011-09-12 11:43:50 +00:00
/ * *
2012-05-16 14:06:22 +00:00
* Class to display a popup containing a form view .
2011-09-12 11:43:50 +00:00
* /
2012-05-16 14:06:22 +00:00
instance . web . form . FormOpenPopup = instance . web . form . AbstractFormPopup . extend ( {
show _element : function ( model , row _id , context , options ) {
this . init _popup ( model , row _id , [ ] , context , options ) ;
_ . defaults ( this . options , {
} ) ;
this . display _popup ( ) ;
} ,
start : function ( ) {
this . _super ( ) ;
this . init _dataset ( ) ;
this . setup _form _view ( ) ;
} ,
} ) ;
/ * *
* Class to display a popup to display a list to search a row . It also allows
* to switch to a form view to create a new row .
* /
instance . web . form . SelectCreatePopup = instance . web . form . AbstractFormPopup . extend ( {
2011-06-15 15:04:40 +00:00
/ * *
* options :
* - initial _ids
* - initial _view : form or search ( default search )
* - disable _multiple _selection
2011-09-30 15:46:12 +00:00
* - list _view _options
2011-06-15 15:04:40 +00:00
* /
2011-06-17 08:41:33 +00:00
select _element : function ( model , options , domain , context ) {
2012-05-16 13:01:42 +00:00
this . init _popup ( model , null , domain , context , options ) ;
2011-08-11 16:03:47 +00:00
var self = this ;
2012-05-16 11:58:56 +00:00
_ . defaults ( this . options , {
2012-05-16 13:01:42 +00:00
initial _view : "search" ,
2012-05-16 11:58:56 +00:00
} ) ;
2011-06-15 15:04:40 +00:00
this . initial _ids = this . options . initial _ids ;
2012-05-16 13:01:42 +00:00
this . display _popup ( ) ;
2011-05-09 10:05:41 +00:00
} ,
start : function ( ) {
2011-10-10 09:44:38 +00:00
var self = this ;
2012-05-16 13:01:42 +00:00
this . init _dataset ( ) ;
2011-06-23 16:57:17 +00:00
if ( this . options . initial _view == "search" ) {
2012-11-23 11:39:32 +00:00
instance . web . pyeval . eval _domains _and _contexts ( {
2011-11-24 10:43:05 +00:00
domains : [ ] ,
contexts : [ this . context ]
2012-10-30 14:06:30 +00:00
} ) . done ( function ( results ) {
2011-11-24 10:43:05 +00:00
var search _defaults = { } ;
2012-04-17 14:32:27 +00:00
_ . each ( results . context , function ( value _ , key ) {
2011-11-24 10:43:05 +00:00
var match = /^search_default_(.*)$/ . exec ( key ) ;
if ( match ) {
2012-04-17 14:32:27 +00:00
search _defaults [ match [ 1 ] ] = value _ ;
2011-11-24 10:43:05 +00:00
}
} ) ;
self . setup _search _view ( search _defaults ) ;
2011-11-23 10:30:00 +00:00
} ) ;
2011-06-09 13:20:04 +00:00
} else { // "form"
this . new _object ( ) ;
2011-05-16 11:02:42 +00:00
}
2011-05-09 10:05:41 +00:00
} ,
2011-11-22 10:41:45 +00:00
setup _search _view : function ( search _defaults ) {
2011-05-09 10:05:41 +00:00
var self = this ;
if ( this . searchview ) {
2012-02-21 16:29:12 +00:00
this . searchview . destroy ( ) ;
2011-05-09 10:05:41 +00:00
}
2012-04-17 12:09:49 +00:00
this . searchview = new instance . web . SearchView ( this ,
2011-11-22 10:41:45 +00:00
this . dataset , false , search _defaults ) ;
2012-10-18 12:46:07 +00:00
this . searchview . on ( 'search_data' , self , function ( domains , contexts , groupbys ) {
2011-06-09 13:20:04 +00:00
if ( self . initial _ids ) {
2011-10-06 09:22:47 +00:00
self . do _search ( domains . concat ( [ [ [ "id" , "in" , self . initial _ids ] ] , self . domain ] ) ,
2011-06-17 14:19:45 +00:00
contexts , groupbys ) ;
2011-06-09 13:20:04 +00:00
self . initial _ids = undefined ;
} else {
2012-01-27 11:20:50 +00:00
self . do _search ( domains . concat ( [ self . domain ] ) , contexts . concat ( self . context ) , groupbys ) ;
2011-06-09 13:20:04 +00:00
}
2011-05-09 11:52:33 +00:00
} ) ;
2012-10-18 08:50:28 +00:00
this . searchview . on ( "search_view_loaded" , self , function ( ) {
2012-04-17 12:09:49 +00:00
self . view _list = new instance . web . form . SelectCreateListView ( self ,
2011-09-14 15:22:08 +00:00
self . dataset , false ,
2011-10-31 15:49:07 +00:00
_ . extend ( { 'deletable' : false ,
2012-06-07 15:23:01 +00:00
'selectable' : ! self . options . disable _multiple _selection ,
2012-07-02 16:09:51 +00:00
'import_enabled' : false ,
2012-07-20 12:35:28 +00:00
'$buttons' : self . $buttonpane ,
2012-11-20 15:39:58 +00:00
'disable_editable_mode' : true ,
2012-11-22 13:35:55 +00:00
'$pager' : self . $ ( '.oe_popup_list_pager' ) ,
2011-10-31 15:49:07 +00:00
} , self . options . list _view _options || { } ) ) ;
2012-07-24 17:05:50 +00:00
self . view _list . on ( 'edit:before' , self , function ( e ) {
e . cancel = true ;
} ) ;
2011-05-10 12:15:51 +00:00
self . view _list . popup = self ;
2012-10-30 14:06:30 +00:00
self . view _list . appendTo ( $ ( ".oe_popup_list" , self . $el ) ) . then ( function ( ) {
2011-09-15 10:08:08 +00:00
self . view _list . do _show ( ) ;
2012-10-30 14:06:30 +00:00
} ) . then ( function ( ) {
2011-06-09 13:20:04 +00:00
self . searchview . do _search ( ) ;
2011-05-10 12:15:51 +00:00
} ) ;
2012-10-18 11:49:50 +00:00
self . view _list . on ( "list_view_loaded" , self , function ( ) {
2012-07-20 12:44:30 +00:00
self . $buttonpane . html ( QWeb . render ( "SelectCreatePopup.search.buttons" , { widget : self } ) ) ;
2012-07-20 12:35:28 +00:00
var $cbutton = self . $buttonpane . find ( ".oe_selectcreatepopup-search-close" ) ;
2011-12-28 15:53:33 +00:00
$cbutton . click ( function ( ) {
2012-02-21 16:29:12 +00:00
self . destroy ( ) ;
2011-12-28 15:53:33 +00:00
} ) ;
2012-07-20 12:35:28 +00:00
var $sbutton = self . $buttonpane . find ( ".oe_selectcreatepopup-search-select" ) ;
2011-12-28 15:53:33 +00:00
$sbutton . click ( function ( ) {
2012-10-12 13:10:44 +00:00
self . select _elements ( self . selected _ids ) ;
2012-02-21 16:29:12 +00:00
self . destroy ( ) ;
2011-12-28 15:53:33 +00:00
} ) ;
2013-07-25 10:07:49 +00:00
$cbutton = self . $buttonpane . find ( ".oe_selectcreatepopup-search-create" ) ;
2012-10-25 08:35:09 +00:00
$cbutton . click ( function ( ) {
self . new _object ( ) ;
} ) ;
2011-12-28 15:53:33 +00:00
} ) ;
2011-05-10 10:30:46 +00:00
} ) ;
2012-10-19 11:08:04 +00:00
this . searchview . appendTo ( $ ( ".oe_popup_search" , self . $el ) ) ;
2011-05-09 10:05:41 +00:00
} ,
2011-10-06 09:22:47 +00:00
do _search : function ( domains , contexts , groupbys ) {
var self = this ;
2012-11-23 11:39:32 +00:00
instance . web . pyeval . eval _domains _and _contexts ( {
2011-10-06 09:22:47 +00:00
domains : domains || [ ] ,
contexts : contexts || [ ] ,
group _by _seq : groupbys || [ ]
2012-10-30 14:06:30 +00:00
} ) . done ( function ( results ) {
2011-10-06 09:22:47 +00:00
self . view _list . do _search ( results . domain , results . context , results . group _by ) ;
} ) ;
} ,
2011-06-15 15:04:40 +00:00
on _click _element : function ( ids ) {
2012-08-10 14:22:53 +00:00
var self = this ;
2011-06-15 15:04:40 +00:00
this . selected _ids = ids || [ ] ;
if ( this . selected _ids . length > 0 ) {
2012-08-10 14:22:53 +00:00
self . $buttonpane . find ( ".oe_selectcreatepopup-search-select" ) . removeAttr ( 'disabled' ) ;
2011-06-15 15:04:40 +00:00
} else {
2012-08-10 14:22:53 +00:00
self . $buttonpane . find ( ".oe_selectcreatepopup-search-select" ) . attr ( 'disabled' , "disabled" ) ;
2011-06-15 15:04:40 +00:00
}
2011-05-10 10:30:46 +00:00
} ,
new _object : function ( ) {
2011-06-09 13:20:04 +00:00
if ( this . searchview ) {
this . searchview . hide ( ) ;
}
if ( this . view _list ) {
2013-01-23 10:58:38 +00:00
this . view _list . do _hide ( ) ;
2011-06-09 13:20:04 +00:00
}
2012-05-16 11:58:56 +00:00
this . setup _form _view ( ) ;
2011-08-11 16:03:47 +00:00
} ,
2011-05-03 16:17:25 +00:00
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . SelectCreateListView = instance . web . ListView . extend ( {
2011-06-15 15:06:58 +00:00
do _add _record : function ( ) {
this . popup . new _object ( ) ;
} ,
2011-05-24 08:35:58 +00:00
select _record : function ( index ) {
2012-10-12 13:10:44 +00:00
this . popup . select _elements ( [ this . dataset . ids [ index ] ] ) ;
2012-02-21 16:29:12 +00:00
this . popup . destroy ( ) ;
2011-06-15 15:04:40 +00:00
} ,
do _select : function ( ids , records ) {
this . _super ( ids , records ) ;
this . popup . on _click _element ( ids ) ;
2011-05-09 11:52:33 +00:00
}
} ) ;
2012-06-21 23:56:41 +00:00
instance . web . form . FieldReference = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-03-15 16:21:07 +00:00
template : 'FieldReference' ,
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
2011-12-08 12:28:51 +00:00
this . reference _ready = true ;
2011-08-18 17:45:08 +00:00
} ,
2012-03-20 10:17:47 +00:00
destroy _content : function ( ) {
2012-10-05 09:19:13 +00:00
if ( this . fm ) {
this . fm . destroy ( ) ;
2012-10-12 09:06:44 +00:00
this . fm = undefined ;
2012-03-19 13:09:52 +00:00
}
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
[FIX] handling of focus on m2o fields (in editable list row)
* Throw out focusin/focusout: the m2o widget's completion list is
created at the page top (body) so the editable listview can't
generically handle arbitrary widgets via mere focusin/focusout.
* Move responsibility of focus/blur events to the form view and its
widgets.
* Events could not just be named ``focus`` and ``blur`` due to usage
of jquery's event system: jquery will automatically call a method of
the event's name if it exists on the object, which conflicts with
.web.form.Field#focus and leads to an infinite loop (as Field#focus
focuses the field's root element, which triggers the focus event,
which calls the focus method,...) => form-* and widget-*, can be
switched back in trunk
* m2o mess kind-of complex, basically:
- the core input and the menu button behave as blur/focus triggers
- when the autocompletion list is clicked, it will temporarily
remove the focus from the input (blurring it), and put it back
later... on a timer. Issue is the timer, we don't want to rely on
having a bigger timer (as later revisions of the library may
change our timings and it's iffy to rely on timers conserving
order perfectly); on the other hand we know the focus *will* come
back to the input eventually. So we can just avoid propagating
blur iif the blur is the consequence of having clicked on the
completion list.
- roughly the same thing happens when clicking on $drop_down (after
fixing the handling of its final focus to be consistent, as
$drop_down would not re-focus the input if it was *closing* the
completion list)
- pretty sure the menu thing does *not work at all*, but I don't
have the courage of fixing it before committing this part.
Date/datetime widget remains to be handled, basically the core focus
handling is the same as in e.g. a charfield *but* needs to handle (and
ignore) loss of focus from clicking inside the picker
widget. Expecting the level of suck to reach unknown heights.
bzr revid: xmo@openerp.com-20120619072518-lsrhzij5asxt2aea
2012-06-19 07:25:18 +00:00
var self = this ;
2012-10-04 16:29:28 +00:00
var fm = new instance . web . form . DefaultFieldManager ( this ) ;
2012-10-05 09:19:13 +00:00
this . fm = fm ;
2012-10-04 16:29:28 +00:00
fm . extend _field _desc ( {
"selection" : {
selection : this . field _manager . get _field _desc ( this . name ) . selection ,
type : "selection" ,
} ,
"m2o" : {
relation : null ,
type : "many2one" ,
} ,
} ) ;
this . selection = new instance . web . form . FieldSelection ( fm , { attrs : {
2012-09-28 10:17:16 +00:00
name : 'selection' ,
modifiers : JSON . stringify ( { readonly : this . get ( 'effective_readonly' ) } ) ,
2012-04-10 11:58:08 +00:00
} } ) ;
2012-04-17 15:45:05 +00:00
this . selection . on ( "change:value" , this , this . on _selection _changed ) ;
2012-10-12 09:06:44 +00:00
this . selection . appendTo ( this . $ ( ".oe_form_view_reference_selection" ) ) ;
2012-06-25 14:40:13 +00:00
this . selection
2013-07-25 10:33:01 +00:00
. on ( 'focused' , null , function ( ) { self . trigger ( 'focused' ) ; } )
. on ( 'blurred' , null , function ( ) { self . trigger ( 'blurred' ) ; } ) ;
2012-04-10 11:58:08 +00:00
2012-10-04 16:29:28 +00:00
this . m2o = new instance . web . form . FieldMany2One ( fm , { attrs : {
2012-09-28 10:17:16 +00:00
name : 'm2o' ,
modifiers : JSON . stringify ( { readonly : this . get ( 'effective_readonly' ) } ) ,
2012-03-19 13:09:52 +00:00
} } ) ;
2012-04-17 15:45:05 +00:00
this . m2o . on ( "change:value" , this , this . data _changed ) ;
2012-10-12 09:06:44 +00:00
this . m2o . appendTo ( this . $ ( ".oe_form_view_reference_m2o" ) ) ;
2012-06-25 14:40:13 +00:00
this . m2o
2013-07-25 10:33:01 +00:00
. on ( 'focused' , null , function ( ) { self . trigger ( 'focused' ) ; } )
. on ( 'blurred' , null , function ( ) { self . trigger ( 'blurred' ) ; } ) ;
2011-08-18 17:45:08 +00:00
} ,
2012-10-23 12:40:42 +00:00
on _selection _changed : function ( ) {
if ( this . reference _ready ) {
this . internal _set _value ( [ this . selection . get _value ( ) , false ] ) ;
this . render _value ( ) ;
}
} ,
data _changed : function ( ) {
if ( this . reference _ready ) {
this . internal _set _value ( [ this . selection . get _value ( ) , this . m2o . get _value ( ) ] ) ;
}
} ,
set _value : function ( val ) {
if ( val ) {
val = val . split ( ',' ) ;
val [ 0 ] = val [ 0 ] || false ;
val [ 1 ] = val [ 0 ] ? ( val [ 1 ] ? parseInt ( val [ 1 ] , 10 ) : val [ 1 ] ) : false ;
}
this . _super ( val || [ false , false ] ) ;
} ,
get _value : function ( ) {
return this . get ( 'value' ) [ 0 ] && this . get ( 'value' ) [ 1 ] ? ( this . get ( 'value' ) [ 0 ] + ',' + this . get ( 'value' ) [ 1 ] ) : false ;
2011-08-18 17:45:08 +00:00
} ,
2012-03-19 13:09:52 +00:00
render _value : function ( ) {
2011-12-08 12:28:51 +00:00
this . reference _ready = false ;
2012-03-19 13:09:52 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
2012-10-23 12:40:42 +00:00
this . selection . set _value ( this . get ( 'value' ) [ 0 ] ) ;
2012-03-19 13:09:52 +00:00
}
2012-10-23 12:40:42 +00:00
this . m2o . field . relation = this . get ( 'value' ) [ 0 ] ;
this . m2o . set _value ( this . get ( 'value' ) [ 1 ] ) ;
this . m2o . $el . toggle ( ! ! this . get ( 'value' ) [ 0 ] ) ;
2011-12-08 12:28:51 +00:00
this . reference _ready = true ;
2011-08-18 17:45:08 +00:00
} ,
2012-06-21 23:56:41 +00:00
} ) ;
2011-08-18 17:45:08 +00:00
2012-06-21 23:56:41 +00:00
instance . web . form . FieldBinary = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
2012-04-18 12:45:20 +00:00
init : function ( field _manager , node ) {
2012-06-13 10:05:16 +00:00
var self = this ;
2012-04-18 12:45:20 +00:00
this . _super ( field _manager , node ) ;
2011-05-19 12:58:45 +00:00
this . binary _value = false ;
2012-10-18 14:37:30 +00:00
this . useFileAPI = ! ! window . FileReader ;
2012-11-21 10:43:29 +00:00
this . max _upload _size = 25 * 1024 * 1024 ; // 25Mo
2012-10-18 14:37:30 +00:00
if ( ! this . useFileAPI ) {
this . fileupload _id = _ . uniqueId ( 'oe_fileupload' ) ;
$ ( window ) . on ( this . fileupload _id , function ( ) {
var args = [ ] . slice . call ( arguments ) . slice ( 1 ) ;
self . on _file _uploaded . apply ( self , args ) ;
} ) ;
}
2012-06-13 10:05:16 +00:00
} ,
stop : function ( ) {
2012-10-18 14:37:30 +00:00
if ( ! this . useFileAPI ) {
$ ( window ) . off ( this . fileupload _id ) ;
}
2012-06-13 10:05:16 +00:00
this . _super . apply ( this , arguments ) ;
2011-05-12 15:22:48 +00:00
} ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-08-24 18:27:07 +00:00
this . $el . find ( 'input.oe_form_binary_file' ) . change ( this . on _file _change ) ;
this . $el . find ( 'button.oe_form_binary_file_save' ) . click ( this . on _save _as ) ;
this . $el . find ( '.oe_form_binary_file_clear' ) . click ( this . on _clear ) ;
2011-05-18 15:33:56 +00:00
} ,
2011-05-23 13:38:40 +00:00
on _file _change : function ( e ) {
2012-10-18 14:37:30 +00:00
var self = this ;
var file _node = e . target ;
if ( ( this . useFileAPI && file _node . files . length ) || ( ! this . useFileAPI && $ ( file _node ) . val ( ) !== '' ) ) {
if ( this . useFileAPI ) {
var file = file _node . files [ 0 ] ;
2012-11-21 10:43:29 +00:00
if ( file . size > this . max _upload _size ) {
var msg = _t ( "The selected file exceed the maximum file size of %s." ) ;
instance . webclient . notification . warn ( _t ( "File upload" ) , _ . str . sprintf ( msg , instance . web . human _size ( this . max _upload _size ) ) ) ;
return false ;
}
2012-10-18 14:37:30 +00:00
var filereader = new FileReader ( ) ;
filereader . readAsDataURL ( file ) ;
filereader . onloadend = function ( upload ) {
var data = upload . target . result ;
data = data . split ( ',' ) [ 1 ] ;
self . on _file _uploaded ( file . size , file . name , file . type , data ) ;
} ;
} else {
this . $el . find ( 'form.oe_form_binary_form input[name=session_id]' ) . val ( this . session . session _id ) ;
this . $el . find ( 'form.oe_form_binary_form' ) . submit ( ) ;
}
2012-08-24 18:27:07 +00:00
this . $el . find ( '.oe_form_binary_progress' ) . show ( ) ;
this . $el . find ( '.oe_form_binary' ) . hide ( ) ;
2011-05-23 13:38:40 +00:00
}
2011-05-18 22:36:16 +00:00
} ,
2011-09-06 11:49:21 +00:00
on _file _uploaded : function ( size , name , content _type , file _base64 ) {
2011-05-18 22:36:16 +00:00
if ( size === false ) {
2012-11-29 00:22:00 +00:00
this . do _warn ( _t ( "File Upload" ) , _t ( "There was a problem while uploading your file" ) ) ;
2011-08-11 02:42:46 +00:00
// TODO: use openerp web crashmanager
2011-09-12 13:56:03 +00:00
console . warn ( "Error while uploading file : " , name ) ;
2011-05-18 22:36:16 +00:00
} else {
2012-06-14 15:00:10 +00:00
this . filename = name ;
2011-05-19 12:58:45 +00:00
this . on _file _uploaded _and _valid . apply ( this , arguments ) ;
2011-05-18 22:36:16 +00:00
}
2012-08-24 18:27:07 +00:00
this . $el . find ( '.oe_form_binary_progress' ) . hide ( ) ;
this . $el . find ( '.oe_form_binary' ) . show ( ) ;
2011-05-18 22:36:16 +00:00
} ,
2011-09-06 11:49:21 +00:00
on _file _uploaded _and _valid : function ( size , name , content _type , file _base64 ) {
2011-05-19 12:58:45 +00:00
} ,
2012-06-14 15:00:10 +00:00
on _save _as : function ( ev ) {
var value = this . get ( 'value' ) ;
if ( ! value ) {
this . do _warn ( _t ( "Save As..." ) , _t ( "The field is empty, there's nothing to save !" ) ) ;
ev . stopPropagation ( ) ;
} else {
2012-07-24 14:12:20 +00:00
instance . web . blockUI ( ) ;
2012-11-14 13:06:00 +00:00
var c = instance . webclient . crashmanager ;
2012-06-14 15:00:10 +00:00
this . session . get _file ( {
url : '/web/binary/saveas_ajax' ,
data : { data : JSON . stringify ( {
model : this . view . dataset . model ,
id : ( this . view . datarecord . id || '' ) ,
field : this . name ,
filename _field : ( this . node . attrs . filename || '' ) ,
2012-12-11 10:33:57 +00:00
data : instance . web . form . is _bin _size ( value ) ? null : value ,
2012-06-14 15:00:10 +00:00
context : this . view . dataset . get _context ( )
} ) } ,
2012-07-24 14:12:20 +00:00
complete : instance . web . unblockUI ,
2012-11-14 13:06:00 +00:00
error : c . rpc _error . bind ( c )
2012-06-14 15:00:10 +00:00
} ) ;
ev . stopPropagation ( ) ;
return false ;
}
2011-05-23 13:38:40 +00:00
} ,
2012-04-05 11:26:19 +00:00
set _filename : function ( value ) {
var filename = this . node . attrs . filename ;
2012-10-04 15:28:37 +00:00
if ( filename ) {
var tmp = { } ;
tmp [ filename ] = value ;
this . field _manager . set _values ( tmp ) ;
2012-04-05 11:26:19 +00:00
}
} ,
2011-05-18 15:33:56 +00:00
on _clear : function ( ) {
2012-04-17 14:32:27 +00:00
if ( this . get ( 'value' ) !== false ) {
2011-05-19 12:58:45 +00:00
this . binary _value = false ;
2012-10-11 15:47:00 +00:00
this . internal _set _value ( false ) ;
2011-05-18 15:33:56 +00:00
}
2011-05-19 10:17:26 +00:00
return false ;
2011-05-19 12:58:45 +00:00
}
2012-06-21 23:56:41 +00:00
} ) ;
2011-05-19 12:58:45 +00:00
2012-04-17 12:09:49 +00:00
instance . web . form . FieldBinaryFile = instance . web . form . FieldBinary . extend ( {
2012-03-15 16:21:07 +00:00
template : 'FieldBinaryFile' ,
2012-03-20 10:17:47 +00:00
initialize _content : function ( ) {
2012-03-19 16:18:56 +00:00
this . _super ( ) ;
2012-03-19 16:13:58 +00:00
if ( this . get ( "effective_readonly" ) ) {
var self = this ;
2012-09-28 06:37:48 +00:00
this . $el . find ( 'a' ) . click ( function ( ev ) {
2012-04-17 14:32:27 +00:00
if ( self . get ( 'value' ) ) {
2012-09-28 06:37:48 +00:00
self . on _save _as ( ev ) ;
2012-03-19 16:13:58 +00:00
}
return false ;
} ) ;
}
2011-10-10 13:33:52 +00:00
} ,
2012-03-19 16:13:58 +00:00
render _value : function ( ) {
2013-07-25 10:07:49 +00:00
var show _value ;
2012-03-19 16:13:58 +00:00
if ( ! this . get ( "effective_readonly" ) ) {
if ( this . node . attrs . filename ) {
show _value = this . view . datarecord [ this . node . attrs . filename ] || '' ;
} else {
2013-07-25 10:07:49 +00:00
show _value = ( this . get ( 'value' ) !== null && this . get ( 'value' ) !== undefined && this . get ( 'value' ) !== false ) ? this . get ( 'value' ) : '' ;
2012-03-19 16:13:58 +00:00
}
2012-08-24 18:27:07 +00:00
this . $el . find ( 'input' ) . eq ( 0 ) . val ( show _value ) ;
2011-12-15 12:04:15 +00:00
} else {
2013-01-07 16:18:07 +00:00
this . $el . find ( 'a' ) . toggle ( ! ! this . get ( 'value' ) ) ;
2012-04-17 14:32:27 +00:00
if ( this . get ( 'value' ) ) {
2013-07-25 10:33:01 +00:00
show _value = _t ( "Download" ) ;
2012-10-04 15:28:37 +00:00
if ( this . view )
show _value += " " + ( this . view . datarecord [ this . node . attrs . filename ] || '' ) ;
2012-08-24 18:27:07 +00:00
this . $el . find ( 'a' ) . text ( show _value ) ;
2012-03-19 16:13:58 +00:00
}
2011-12-15 12:04:15 +00:00
}
2011-05-19 12:58:45 +00:00
} ,
2011-09-06 11:49:21 +00:00
on _file _uploaded _and _valid : function ( size , name , content _type , file _base64 ) {
2011-05-19 12:58:45 +00:00
this . binary _value = true ;
2012-10-11 15:47:00 +00:00
this . internal _set _value ( file _base64 ) ;
2012-11-12 17:11:28 +00:00
var show _value = name + " (" + instance . web . human _size ( size ) + ")" ;
2012-08-24 18:27:07 +00:00
this . $el . find ( 'input' ) . eq ( 0 ) . val ( show _value ) ;
2011-05-19 12:58:45 +00:00
this . set _filename ( name ) ;
} ,
on _clear : function ( ) {
this . _super . apply ( this , arguments ) ;
2012-08-24 18:27:07 +00:00
this . $el . find ( 'input' ) . eq ( 0 ) . val ( '' ) ;
2011-05-19 12:58:45 +00:00
this . set _filename ( '' ) ;
}
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldBinaryImage = instance . web . form . FieldBinary . extend ( {
2012-03-15 16:21:07 +00:00
template : 'FieldBinaryImage' ,
2012-11-06 17:20:36 +00:00
placeholder : "/web/static/src/img/placeholder.png" ,
2012-03-19 16:13:58 +00:00
render _value : function ( ) {
2012-08-21 16:15:17 +00:00
var self = this ;
2012-03-08 14:06:36 +00:00
var url ;
2012-12-11 10:33:57 +00:00
if ( this . get ( 'value' ) && ! instance . web . form . is _bin _size ( this . get ( 'value' ) ) ) {
2012-04-17 14:32:27 +00:00
url = 'data:image/png;base64,' + this . get ( 'value' ) ;
} else if ( this . get ( 'value' ) ) {
2012-11-15 18:23:31 +00:00
var id = JSON . stringify ( this . view . datarecord . id || null ) ;
2012-08-21 16:15:17 +00:00
var field = this . name ;
if ( this . options . preview _image )
field = this . options . preview _image ;
2012-11-14 17:41:50 +00:00
url = this . session . url ( '/web/binary/image' , {
model : this . view . dataset . model ,
id : id ,
field : field ,
t : ( new Date ( ) . getTime ( ) ) ,
} ) ;
2012-03-23 15:04:48 +00:00
} else {
2012-11-06 17:20:36 +00:00
url = this . placeholder ;
2012-03-08 14:06:36 +00:00
}
2012-08-21 16:15:17 +00:00
var $img = $ ( QWeb . render ( "FieldBinaryImage-img" , { widget : this , url : url } ) ) ;
2013-02-28 05:49:10 +00:00
$ ( $img ) . click ( function ( e ) {
if ( self . view . get ( "actual_mode" ) == "view" ) {
var $button = $ ( ".oe_form_button_edit" ) ;
$button . openerpBounce ( ) ;
e . stopPropagation ( ) ;
}
} ) ;
2012-08-24 18:27:07 +00:00
this . $el . find ( '> img' ) . remove ( ) ;
this . $el . prepend ( $img ) ;
2012-08-21 16:15:17 +00:00
$img . load ( function ( ) {
if ( ! self . options . size )
return ;
$img . css ( "max-width" , "" + self . options . size [ 0 ] + "px" ) ;
$img . css ( "max-height" , "" + self . options . size [ 1 ] + "px" ) ;
$img . css ( "margin-left" , "" + ( self . options . size [ 0 ] - $img . width ( ) ) / 2 + "px" ) ;
$img . css ( "margin-top" , "" + ( self . options . size [ 1 ] - $img . height ( ) ) / 2 + "px" ) ;
} ) ;
2012-11-06 17:20:36 +00:00
$img . on ( 'error' , function ( ) {
$img . attr ( 'src' , self . placeholder ) ;
instance . webclient . notification . warn ( _t ( "Image" ) , _t ( "Could not display the selected image." ) ) ;
} ) ;
2011-05-19 12:58:45 +00:00
} ,
2011-09-06 11:49:21 +00:00
on _file _uploaded _and _valid : function ( size , name , content _type , file _base64 ) {
2012-10-11 15:47:00 +00:00
this . internal _set _value ( file _base64 ) ;
2011-05-19 12:58:45 +00:00
this . binary _value = true ;
2012-03-23 15:04:48 +00:00
this . render _value ( ) ;
2012-10-04 15:28:37 +00:00
this . set _filename ( name ) ;
2011-05-19 12:58:45 +00:00
} ,
on _clear : function ( ) {
this . _super . apply ( this , arguments ) ;
2012-03-23 15:04:48 +00:00
this . render _value ( ) ;
2012-10-04 15:28:37 +00:00
this . set _filename ( '' ) ;
2011-05-12 15:22:48 +00:00
}
} ) ;
2012-10-24 09:14:21 +00:00
/ * *
2013-02-28 11:11:35 +00:00
* Widget for ( many2many field ) to upload one or more file in same time and display in list .
2012-10-24 09:14:21 +00:00
* The user can delete his files .
* Options on attribute ; "blockui" { Boolean } block the UI or not
* during the file is uploading
* /
2012-11-16 11:25:17 +00:00
instance . web . form . FieldMany2ManyBinaryMultiFiles = instance . web . form . AbstractField . extend ( {
2012-10-24 09:14:21 +00:00
template : "FieldBinaryFileUploader" ,
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
this . field _manager = field _manager ;
this . node = node ;
2012-11-16 11:25:17 +00:00
if ( this . field . type != "many2many" || this . field . relation != 'ir.attachment' ) {
2012-11-29 00:22:00 +00:00
throw _ . str . sprintf ( _t ( "The type of the field '%s' must be a many2many field with a relation to 'ir.attachment' model." ) , this . field . string ) ;
2012-10-24 09:14:21 +00:00
}
2012-12-11 12:43:11 +00:00
this . data = { } ;
this . set _value ( [ ] ) ;
2012-10-24 09:14:21 +00:00
this . ds _file = new instance . web . DataSetSearch ( this , 'ir.attachment' ) ;
this . fileupload _id = _ . uniqueId ( 'oe_fileupload_temp' ) ;
2012-10-26 13:58:34 +00:00
$ ( window ) . on ( this . fileupload _id , _ . bind ( this . on _file _loaded , this ) ) ;
2012-10-24 09:14:21 +00:00
} ,
start : function ( ) {
this . _super ( this ) ;
this . $el . on ( 'change' , 'input.oe_form_binary_file' , this . on _file _change ) ;
} ,
2012-11-15 09:21:49 +00:00
set _value : function ( value _ ) {
2013-02-28 11:11:35 +00:00
value _ = value _ || [ ] ;
if ( value _ . length >= 1 && value _ [ 0 ] instanceof Array ) {
value _ = value _ [ 0 ] [ 2 ] ;
2012-12-11 12:43:11 +00:00
}
2013-02-28 11:11:35 +00:00
this . _super ( value _ ) ;
2012-11-15 09:21:49 +00:00
} ,
2012-10-24 09:14:21 +00:00
get _value : function ( ) {
2013-02-28 11:11:35 +00:00
var tmp = [ commands . replace _with ( this . get ( "value" ) ) ] ;
return tmp ;
2012-10-24 09:14:21 +00:00
} ,
get _file _url : function ( attachment ) {
2012-11-14 17:41:50 +00:00
return this . session . url ( '/web/binary/saveas' , { model : 'ir.attachment' , field : 'datas' , filename _field : 'datas_fname' , id : attachment [ 'id' ] } ) ;
2012-10-24 09:14:21 +00:00
} ,
2012-11-15 12:28:34 +00:00
read _name _values : function ( ) {
var self = this ;
2012-12-11 12:43:11 +00:00
// don't reset know values
var _value = _ . filter ( this . get ( 'value' ) , function ( id ) { return typeof self . data [ id ] == 'undefined' ; } ) ;
2012-11-15 12:28:34 +00:00
// send request for get_name
2012-12-11 12:43:11 +00:00
if ( _value . length ) {
return this . ds _file . call ( 'read' , [ _value , [ 'id' , 'name' , 'datas_fname' ] ] ) . done ( function ( datas ) {
2012-11-15 12:28:34 +00:00
_ . each ( datas , function ( data ) {
data . no _unlink = true ;
data . url = self . session . url ( '/web/binary/saveas' , { model : 'ir.attachment' , field : 'datas' , filename _field : 'datas_fname' , id : data . id } ) ;
2012-12-11 12:43:11 +00:00
self . data [ data . id ] = data ;
2012-11-15 12:28:34 +00:00
} ) ;
} ) ;
} else {
2012-12-11 12:43:11 +00:00
return $ . when ( ) ;
2012-11-15 12:28:34 +00:00
}
} ,
2012-10-26 13:58:34 +00:00
render _value : function ( ) {
2012-11-15 12:28:34 +00:00
var self = this ;
2012-12-11 12:43:11 +00:00
this . read _name _values ( ) . then ( function ( ) {
2012-11-15 12:28:34 +00:00
var render = $ ( instance . web . qweb . render ( 'FieldBinaryFileUploader.files' , { 'widget' : self } ) ) ;
render . on ( 'click' , '.oe_delete' , _ . bind ( self . on _file _delete , self ) ) ;
self . $ ( '.oe_placeholder_files, .oe_attachments' ) . replaceWith ( render ) ;
// reinit input type file
var $input = self . $ ( 'input.oe_form_binary_file' ) ;
$input . after ( $input . clone ( true ) ) . remove ( ) ;
self . $ ( ".oe_fileupload" ) . show ( ) ;
} ) ;
2012-10-24 09:14:21 +00:00
} ,
on _file _change : function ( event ) {
event . stopPropagation ( ) ;
var self = this ;
var $target = $ ( event . target ) ;
if ( $target . val ( ) !== '' ) {
var filename = $target . val ( ) . replace ( /.*[\\\/]/ , '' ) ;
2012-12-11 12:43:11 +00:00
// don't uplode more of one file in same time
if ( self . data [ 0 ] && self . data [ 0 ] . upload ) {
2012-10-24 09:14:21 +00:00
return false ;
}
2012-12-11 12:43:11 +00:00
for ( var id in this . get ( 'value' ) ) {
// if the files exits, delete the file before upload (if it's a new file)
if ( self . data [ id ] && ( self . data [ id ] . filename || self . data [ id ] . name ) == filename && ! self . data [ id ] . no _unlink ) {
self . ds _file . unlink ( [ id ] ) ;
}
}
2012-10-24 09:14:21 +00:00
2012-10-26 13:58:34 +00:00
// block UI or not
2012-11-09 10:21:02 +00:00
if ( this . node . attrs . blockui > 0 ) {
2012-10-26 13:58:34 +00:00
instance . web . blockUI ( ) ;
}
2012-10-24 12:27:00 +00:00
// TODO : unactivate send on wizard and form
2012-10-24 09:14:21 +00:00
// submit file
2012-10-24 12:27:00 +00:00
this . $ ( 'form.oe_form_binary_form' ) . submit ( ) ;
2012-10-29 10:59:47 +00:00
this . $ ( ".oe_fileupload" ) . hide ( ) ;
2012-12-11 12:43:11 +00:00
// add file on data result
this . data [ 0 ] = {
2012-10-24 09:14:21 +00:00
'id' : 0 ,
'name' : filename ,
'filename' : filename ,
'url' : '' ,
'upload' : true
2012-12-11 12:43:11 +00:00
} ;
2012-10-24 09:14:21 +00:00
}
} ,
on _file _loaded : function ( event , result ) {
2012-11-30 09:03:47 +00:00
var files = this . get ( 'value' ) ;
2012-10-24 09:14:21 +00:00
// unblock UI
2012-11-09 10:21:02 +00:00
if ( this . node . attrs . blockui > 0 ) {
2012-10-24 09:14:21 +00:00
instance . web . unblockUI ( ) ;
}
2012-12-07 08:09:46 +00:00
if ( result . error || ! result . id ) {
2013-04-29 10:28:55 +00:00
this . do _warn ( _t ( 'Uploading Error' ) , result . error ) ;
2012-12-11 12:43:11 +00:00
delete this . data [ 0 ] ;
2012-11-30 09:03:47 +00:00
} else {
2012-12-11 12:43:11 +00:00
if ( this . data [ 0 ] && this . data [ 0 ] . filename == result . filename && this . data [ 0 ] . upload ) {
delete this . data [ 0 ] ;
this . data [ result . id ] = {
'id' : result . id ,
'name' : result . name ,
'filename' : result . filename ,
'url' : this . get _file _url ( result )
} ;
} else {
this . data [ result . id ] = {
2012-10-24 09:14:21 +00:00
'id' : result . id ,
'name' : result . name ,
'filename' : result . filename ,
'url' : this . get _file _url ( result )
} ;
}
2013-02-28 11:11:35 +00:00
var values = _ . clone ( this . get ( 'value' ) ) ;
2012-12-11 12:43:11 +00:00
values . push ( result . id ) ;
this . set ( { 'value' : values } ) ;
2012-10-24 09:14:21 +00:00
}
2013-07-25 10:33:01 +00:00
this . render _value ( ) ;
2012-10-24 09:14:21 +00:00
} ,
on _file _delete : function ( event ) {
event . stopPropagation ( ) ;
var file _id = $ ( event . target ) . data ( "id" ) ;
if ( file _id ) {
2012-12-11 12:43:11 +00:00
var files = _ . filter ( this . get ( 'value' ) , function ( id ) { return id != file _id ; } ) ;
if ( ! this . data [ file _id ] . no _unlink ) {
this . ds _file . unlink ( [ file _id ] ) ;
2012-10-24 09:14:21 +00:00
}
2012-10-26 13:58:34 +00:00
this . set ( { 'value' : files } ) ;
2012-10-24 09:14:21 +00:00
}
} ,
} ) ;
2012-04-17 12:09:49 +00:00
instance . web . form . FieldStatus = instance . web . form . AbstractField . extend ( {
2012-07-02 08:41:19 +00:00
template : "FieldStatus" ,
2012-08-18 22:51:51 +00:00
init : function ( field _manager , node ) {
this . _super ( field _manager , node ) ;
this . options . clickable = this . options . clickable || ( this . node . attrs || { } ) . clickable || false ;
this . options . visible = this . options . visible || ( this . node . attrs || { } ) . statusbar _visible || false ;
2012-10-11 16:18:16 +00:00
this . set ( { value : false } ) ;
2013-03-21 12:49:52 +00:00
this . selection = { 'unfolded' : [ ] , 'folded' : [ ] } ;
this . set ( "selection" , { 'unfolded' : [ ] , 'folded' : [ ] } ) ;
2013-02-26 17:45:09 +00:00
this . selection _dm = new instance . web . DropMisordered ( ) ;
2013-04-29 14:36:21 +00:00
this . dataset = new instance . web . DataSetStatic ( this , this . field . relation , this . build _context ( ) ) ;
2012-08-18 22:51:51 +00:00
} ,
2011-09-08 14:58:45 +00:00
start : function ( ) {
2013-02-26 17:45:09 +00:00
this . field _manager . on ( "view_content_has_changed" , this , this . calc _domain ) ;
this . calc _domain ( ) ;
this . on ( "change:evaluated_selection_domain" , this , this . get _selection ) ;
this . on ( "change:selection" , this , function ( ) {
this . selection = this . get ( "selection" ) ;
this . render _value ( ) ;
} ) ;
2013-03-04 23:02:53 +00:00
this . get _selection ( ) ;
2012-08-18 22:10:35 +00:00
if ( this . options . clickable ) {
2013-03-21 12:49:52 +00:00
this . $el . on ( 'click' , 'li:not(.oe_folded)' , this . on _click _stage ) ;
2012-08-18 22:10:35 +00:00
}
2012-08-24 18:27:07 +00:00
if ( this . $el . parent ( ) . is ( 'header' ) ) {
this . $el . after ( '<div class="oe_clear"/>' ) ;
2012-07-02 08:41:19 +00:00
}
2012-10-11 16:09:02 +00:00
this . _super ( ) ;
2011-09-08 14:58:45 +00:00
} ,
2012-04-17 14:32:27 +00:00
set _value : function ( value _ ) {
2012-10-11 16:09:02 +00:00
if ( value _ instanceof Array ) {
value _ = value _ [ 0 ] ;
2012-05-18 12:23:48 +00:00
}
2012-10-11 16:09:02 +00:00
this . _super ( value _ ) ;
2011-09-08 14:58:45 +00:00
} ,
2012-10-11 16:09:02 +00:00
render _value : function ( ) {
2012-10-11 16:18:16 +00:00
var self = this ;
2013-03-21 12:49:52 +00:00
var content = QWeb . render ( "FieldStatus.content" , {
'widget' : self ,
2013-07-25 10:33:01 +00:00
'value_folded' : _ . find ( self . selection . folded , function ( i ) { return i [ 0 ] === self . get ( 'value' ) ; } )
2013-03-21 12:49:52 +00:00
} ) ;
2013-02-26 17:45:09 +00:00
self . $el . html ( content ) ;
} ,
calc _domain : function ( ) {
var d = instance . web . pyeval . eval ( 'domain' , this . build _domain ( ) ) ;
2013-03-14 10:32:33 +00:00
var domain = [ ] ; //if there is no domain defined, fetch all the records
2013-04-23 14:09:42 +00:00
2013-03-14 10:32:33 +00:00
if ( d . length ) {
2013-03-13 14:25:54 +00:00
domain = [ '|' , [ 'id' , '=' , this . get ( 'value' ) ] ] . concat ( d ) ;
}
2013-04-23 14:09:42 +00:00
2013-02-26 17:45:09 +00:00
if ( ! _ . isEqual ( domain , this . get ( "evaluated_selection_domain" ) ) ) {
this . set ( "evaluated_selection_domain" , domain ) ;
}
2011-09-08 14:58:45 +00:00
} ,
2012-08-18 22:10:35 +00:00
/ * * G e t t h e s e l e c t i o n a n d r e n d e r i t
* selection : [ [ identifier , value _to _display ] , ... ]
2012-05-25 10:10:57 +00:00
* For selection fields : this is directly given by this . field . selection
2012-08-18 22:10:35 +00:00
* For many2one fields : perform a search on the relation of the many2one field
2012-05-25 10:10:57 +00:00
* /
2012-05-18 11:47:31 +00:00
get _selection : function ( ) {
2011-09-08 16:35:36 +00:00
var self = this ;
2013-03-21 12:49:52 +00:00
var selection _unfolded = [ ] ;
var selection _folded = [ ] ;
2013-02-26 17:45:09 +00:00
var calculation = _ . bind ( function ( ) {
if ( this . field . type == "many2one" ) {
2013-04-29 14:36:21 +00:00
return self . get _distant _fields ( ) . then ( function ( fields ) {
return new instance . web . DataSetSearch ( self , self . field . relation , self . build _context ( ) , self . get ( "evaluated_selection_domain" ) )
. read _slice ( fields . fold ? [ 'fold' ] : [ 'id' ] , { } ) . then ( function ( records ) {
2013-07-25 10:33:01 +00:00
var ids = _ . map ( records , function ( val ) { return val . id ; } ) ;
2013-04-29 14:36:21 +00:00
return self . dataset . name _get ( ids ) . then ( function ( records _name ) {
_ . each ( records , function ( record ) {
var name = _ . find ( records _name , function ( val ) { return val [ 0 ] == record . id ; } ) [ 1 ] ;
if ( record . fold && record . id != self . get ( 'value' ) ) {
selection _folded . push ( [ record . id , name ] ) ;
} else {
selection _unfolded . push ( [ record . id , name ] ) ;
}
} ) ;
2013-07-25 10:33:01 +00:00
} ) ;
2013-03-21 12:49:52 +00:00
} ) ;
2013-02-26 17:45:09 +00:00
} ) ;
} else {
// For field type selection filter values according to
// statusbar_visible attribute of the field. For example:
// statusbar_visible="draft,open".
var select = this . field . selection ;
for ( var i = 0 ; i < select . length ; i ++ ) {
var key = select [ i ] [ 0 ] ;
if ( key == this . get ( 'value' ) || ! this . options . visible || this . options . visible . indexOf ( key ) != - 1 ) {
2013-03-21 15:21:56 +00:00
selection _unfolded . push ( select [ i ] ) ;
2013-02-26 17:45:09 +00:00
}
2012-08-18 22:10:35 +00:00
}
2013-02-26 17:45:09 +00:00
return $ . when ( ) ;
2012-08-18 22:10:35 +00:00
}
2013-02-26 17:45:09 +00:00
} , this ) ;
this . selection _dm . add ( calculation ( ) ) . then ( function ( ) {
2013-03-21 12:49:52 +00:00
var selection = { 'unfolded' : selection _unfolded , 'folded' : selection _folded } ;
2013-02-26 17:45:09 +00:00
if ( ! _ . isEqual ( selection , self . get ( "selection" ) ) ) {
self . set ( "selection" , selection ) ;
}
} ) ;
2012-05-18 14:41:42 +00:00
} ,
2013-04-29 14:36:21 +00:00
get _distant _fields : function ( ) {
var self = this ;
if ( this . distant _fields ) {
return $ . when ( this . distant _fields ) ;
}
return new instance . web . Model ( self . field . relation ) . call ( "fields_get" , [ [ "fold" ] ] ) . then ( function ( fields ) {
self . distant _fields = fields ;
return fields ;
2013-07-25 10:33:01 +00:00
} ) ;
2013-04-29 14:36:21 +00:00
} ,
2012-08-18 22:10:35 +00:00
on _click _stage : function ( ev ) {
var self = this ;
var $li = $ ( ev . currentTarget ) ;
2013-07-25 10:07:49 +00:00
var val ;
2013-06-18 13:35:21 +00:00
if ( this . field . type == "many2one" ) {
2013-07-25 10:07:49 +00:00
val = parseInt ( $li . data ( "id" ) , 10 ) ;
2013-06-18 13:35:21 +00:00
}
else {
2013-07-25 10:07:49 +00:00
val = $li . data ( "id" ) ;
2013-06-18 13:35:21 +00:00
}
2012-10-11 16:18:16 +00:00
if ( val != self . get ( 'value' ) ) {
2012-10-30 14:06:30 +00:00
this . view . recursive _save ( ) . done ( function ( ) {
2012-08-18 22:10:35 +00:00
var change = { } ;
change [ self . name ] = val ;
2012-10-30 14:06:30 +00:00
self . view . dataset . write ( self . view . datarecord . id , change ) . done ( function ( ) {
2012-08-18 22:10:35 +00:00
self . view . reload ( ) ;
} ) ;
} ) ;
}
2012-08-18 20:16:32 +00:00
} ,
2011-09-08 14:58:45 +00:00
} ) ;
2012-10-08 15:28:31 +00:00
instance . web . form . FieldMonetary = instance . web . form . FieldFloat . extend ( {
template : "FieldMonetary" ,
2012-12-03 18:42:14 +00:00
widget _class : 'oe_form_field_float oe_form_field_monetary' ,
2012-10-08 15:28:31 +00:00
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . set ( { "currency" : false } ) ;
if ( this . options . currency _field ) {
this . field _manager . on ( "field_changed:" + this . options . currency _field , this , function ( ) {
this . set ( { "currency" : this . field _manager . get _field _value ( this . options . currency _field ) } ) ;
} ) ;
}
this . on ( "change:currency" , this , this . get _currency _info ) ;
this . get _currency _info ( ) ;
this . ci _dm = new instance . web . DropMisordered ( ) ;
} ,
start : function ( ) {
var tmp = this . _super ( ) ;
this . on ( "change:currency_info" , this , this . reinitialize ) ;
return tmp ;
} ,
get _currency _info : function ( ) {
var self = this ;
if ( this . get ( "currency" ) === false ) {
this . set ( { "currency_info" : null } ) ;
return ;
}
2013-02-27 11:31:32 +00:00
return this . ci _dm . add ( self . alive ( new instance . web . Model ( "res.currency" ) . query ( [ "symbol" , "position" ] )
. filter ( [ [ "id" , "=" , self . get ( "currency" ) ] ] ) . first ( ) ) ) . then ( function ( res ) {
2012-10-08 15:28:31 +00:00
self . set ( { "currency_info" : res } ) ;
} ) ;
} ,
2012-10-09 09:08:51 +00:00
parse _value : function ( val , def ) {
2013-02-28 16:51:17 +00:00
return instance . web . parse _value ( val , { type : "float" , digits : ( this . node . attrs || { } ) . digits || this . field . digits } , def ) ;
2012-10-09 09:08:51 +00:00
} ,
format _value : function ( val , def ) {
2013-02-28 16:51:17 +00:00
return instance . web . format _value ( val , { type : "float" , digits : ( this . node . attrs || { } ) . digits || this . field . digits } , def ) ;
2012-10-09 09:08:51 +00:00
} ,
2012-10-08 15:28:31 +00:00
} ) ;
2013-09-25 14:45:56 +00:00
/ *
2013-10-01 16:07:54 +00:00
This type of field display a list of checkboxes . It works only with m2ms . This field will display one checkbox for each
record existing in the model targeted by the relation , according to the given domain if one is specified . Checked records
will be added to the relation .
2013-09-25 14:45:56 +00:00
* /
instance . web . form . FieldMany2ManyCheckBoxes = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
className : "oe_form_many2many_checkboxes" ,
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . set ( "value" , { } ) ;
this . set ( "records" , [ ] ) ;
this . field _manager . on ( "view_content_has_changed" , this , function ( ) {
var domain = new openerp . web . CompoundDomain ( this . build _domain ( ) ) . eval ( ) ;
if ( ! _ . isEqual ( domain , this . get ( "domain" ) ) ) {
this . set ( "domain" , domain ) ;
}
} ) ;
this . records _orderer = new instance . web . DropMisordered ( ) ;
} ,
initialize _field : function ( ) {
instance . web . form . ReinitializeFieldMixin . initialize _field . call ( this )
this . on ( "change:domain" , this , this . query _records ) ;
this . set ( "domain" , new openerp . web . CompoundDomain ( this . build _domain ( ) ) . eval ( ) ) ;
this . on ( "change:records" , this , this . render _value ) ;
} ,
query _records : function ( ) {
var self = this ;
var model = new openerp . Model ( openerp . session , this . field . relation ) ;
this . records _orderer . add ( model . call ( "search" , [ this . get ( "domain" ) ] , { "context" : this . build _context ( ) } ) . then ( function ( record _ids ) {
return model . call ( "name_get" , [ record _ids ] , { "context" : self . build _context ( ) } ) ;
} ) ) . then ( function ( res ) {
self . set ( "records" , res ) ;
} ) ;
} ,
render _value : function ( ) {
this . $ ( ) . html ( QWeb . render ( "FieldMany2ManyCheckBoxes" , { widget : this , selected : this . get ( "value" ) } ) ) ;
var inputs = this . $ ( "input" ) ;
inputs . change ( _ . bind ( this . from _dom , this ) ) ;
if ( this . get ( "effective_readonly" ) )
inputs . attr ( "disabled" , "true" ) ;
} ,
from _dom : function ( ) {
var new _value = { } ;
this . $ ( "input" ) . each ( function ( ) {
var elem = $ ( this ) ;
new _value [ elem . data ( "record-id" ) ] = elem . attr ( "checked" ) ? true : undefined ;
} ) ;
if ( ! _ . isEqual ( new _value , this . get ( "value" ) ) )
this . internal _set _value ( new _value ) ;
} ,
set _value : function ( value ) {
value = value || [ ] ;
if ( value . length >= 1 && value [ 0 ] instanceof Array ) {
value = value [ 0 ] [ 2 ] ;
}
var formatted = { } ;
_ . each ( value , function ( el ) {
formatted [ JSON . stringify ( el ) ] = true ;
} ) ;
this . _super ( formatted ) ;
} ,
get _value : function ( ) {
var value = _ . filter ( _ . keys ( this . get ( "value" ) ) , function ( el ) {
return this . get ( "value" ) [ el ] ;
} , this ) ;
value = _ . map ( value , function ( el ) {
return JSON . parse ( el ) ;
} ) ;
return [ commands . replace _with ( value ) ] ;
} ,
} ) ;
2013-10-04 15:37:34 +00:00
instance . web . form . X2ManyCounter = instance . web . form . AbstractField . extend ( instance . web . form . ReinitializeFieldMixin , {
className : "oe_form_x2many_counter" ,
init : function ( ) {
this . _super . apply ( this , arguments ) ;
this . set ( "value" , [ ] ) ;
_ . defaults ( this . options , {
"views" : [ [ false , "tree" ] , [ false , "form" ] ] ,
} ) ;
} ,
render _value : function ( ) {
var text = _ . str . sprintf ( "%d %s" , this . val ( ) . length , this . string ) ;
this . $ ( ) . html ( QWeb . render ( "X2ManyCounter" , { text : text } ) ) ;
this . $ ( "a" ) . click ( _ . bind ( this . go _to , this ) ) ;
} ,
go _to : function ( ) {
return this . view . recursive _save ( ) . then ( _ . bind ( function ( ) {
var val = this . val ( ) ;
var context = { } ;
/ *
Object { groups _id : Array [ 0 ] , domain : false , help : "<p class='oe_view_nocontent_create'>Click here to …documents, etc.↵ </p>↵ " , res _model : "project.task" , search _view _id : Array [ 2 ] … }
auto _refresh : 0
auto _search : true
context : Class
domain : false
filter : false
flags : Object
groups _id : Array [ 0 ]
help : "<p class='oe_view_nocontent_create'>Click here to add new tasks</p><p>↵ OpenERP's project management allows you to manage the pipeline↵ of tasks in order to get things done efficiently. You can↵ track progress, discuss on tasks, attach documents, etc.↵ </p>↵ "
id : 151
limit : 80
multi : false
name : "Tasks"
res _id : 0
res _model : "project.task"
search _view : "{'name': u'project.task.search.form', 'fields': {'categ_ids': {'domain': [], 'string': 'Tags', 'views': {}, 'm2m_join_columns': ['project_task_id', 'project_category_id'], 'm2m_join_table': 'project_category_project_task_rel', 'relation': 'project.category', 'context': {}, 'selectable': True, 'type': 'many2many'}, 'partner_id': {'domain': [], 'string': 'Customer', 'views': {}, 'relation': 'res.partner', 'context': {}, 'selectable': True, 'type': 'many2one'}, 'user_id': {'domain': [], 'string': 'Assigned to', 'views': {}, 'relation': 'res.users', 'context': {}, 'selectable': True, 'type': 'many2one'}, 'project_id': {'domain': [], 'string': 'Project', 'views': {}, 'relation': 'project.project', 'context': {}, 'selectable': True, 'type': 'many2one', 'select': '1'}, 'stage_id': {'domain': " [ ( 'project_ids' , '=' , project _id ) ] ", 'string': 'Stage', 'views': {}, 'relation': 'project.task.type', 'context': {}, 'selectable': True, 'type': 'many2one'}, 'name': {'string': 'Task Summary', 'views': {}, 'required': True, 'selectable': True, 'type': 'char', 'select': True, 'size': 128}}, 'arch': '<search string=" Tasks ">\n <field name=" name " string=" Tasks " modifiers=" { & quot ; required & quot ; : true } "/>\n <field name=" categ _ids " modifiers=" { } "/>\n <filter string=" Unassigned " name=" unassigned " domain=" [ ( \ 'user_id\', \'=\', False)]"/>\n <filter string="New" name="draft" domain="[(\'stage_id.sequence\', \'=\', 1)]"/>\n <separator/>\n <filter string="My Tasks" domain="[(\'user_id\',\'=\',uid)]"/>\n <separator/>\n <filter string="Unread Messages" name="message_unread" domain="[(\'message_unread\',\'=\',True)]"/>\n <separator/>\n <filter string="Deadlines" context="{\'deadline_visible\': False}" domain="[(\'date_deadline\',\'<>\',False)]" help="Show only tasks having a deadline"/>\n <field name="partner_id" modifiers="{}"/>\n <field name="project_id" modifiers="{}"/>\n <field name="user_id" modifiers="{}"/>\n <field name="stage_id" domain="[]" modifiers="{}"/>\n <group expand="0" string="Group By...">\n <filter string="Users" name="group_user_id" icon="terp-personal" domain="[]" context="{\'group_by\':\'user_id\'}"/>\n <filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{\'group_by\':\'project_id\'}"/>\n <filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{\'group_by\':\'stage_id\'}"/>\n <filter string="Last Stage Update" icon="terp-go-month" domain="[]" context="{\'group_by\':\'date_last_stage_update\'}"/>\n <filter string="Deadline" icon="terp-gnome-cpu-frequency-applet+" domain="[]" context="{\'group_by\':\'date_deadline\'}"/>\n <filter string="Start Month" icon="terp-go-month" domain="[]" context="{\'group_by\':\'date_start\'}"/>\n <filter string="End Month" icon="terp-go-month" domain="[]" context="{\'group_by\':\'date_end\'}" invisible="1" modifiers="{"invisible": true}"/>\n </group>\n </search>' , 'model' : 'project.task' , 'type' : u 'search' , 'view_id' : 288 , 'field_parent' : False } "
search _view _id : Array [ 2 ]
src _model : false
target : "current"
type : "ir.actions.act_window"
usage : false
view _id : false
view _ids : Array [ 0 ]
view _mode : "kanban,list,form,calendar,gantt,graph"
views : Array [ 6 ]
_ _proto _ _ : Object
* /
if ( this . field . type === "one2many" ) {
context [ "default_" + this . field . relation _field ] = this . view . datarecord . id ;
}
context [ "search_default_" + this . field . relation _field ] = [ this . view . datarecord . id ] ;
return this . do _action ( {
type : 'ir.actions.act_window' ,
auto _search : true ,
name : this . string ,
res _model : this . field . relation ,
res _id : val . length >= 1 ? val [ 0 ] : false ,
res _ids : val ,
views : this . options . views ,
target : 'current' ,
context : { } ,
} ) ;
} , this ) ) ;
} ,
val : function ( ) {
var value = this . get ( "value" ) || [ ] ;
if ( value . length >= 1 && value [ 0 ] instanceof Array ) {
value = value [ 0 ] [ 2 ] ;
}
return value ;
}
} ) ;
2011-03-31 10:57:51 +00:00
/ * *
2012-05-02 09:27:43 +00:00
* Registry of form fields , called by : js : ` instance.web.FormView ` .
*
2012-06-21 23:56:41 +00:00
* All referenced classes must implement FieldInterface . Those represent the classes whose instances
2012-05-02 09:27:43 +00:00
* will substitute to the < field > tags as defined in OpenERP ' s views .
2011-03-31 10:57:51 +00:00
* /
2012-04-17 12:09:49 +00:00
instance . web . form . widgets = new instance . web . Registry ( {
'char' : 'instance.web.form.FieldChar' ,
'id' : 'instance.web.form.FieldID' ,
'email' : 'instance.web.form.FieldEmail' ,
'url' : 'instance.web.form.FieldUrl' ,
'text' : 'instance.web.form.FieldText' ,
2012-08-13 11:46:38 +00:00
'html' : 'instance.web.form.FieldTextHtml' ,
2012-04-17 12:09:49 +00:00
'date' : 'instance.web.form.FieldDate' ,
'datetime' : 'instance.web.form.FieldDatetime' ,
'selection' : 'instance.web.form.FieldSelection' ,
2013-03-02 21:38:49 +00:00
'radio' : 'instance.web.form.FieldRadio' ,
2012-04-17 12:09:49 +00:00
'many2one' : 'instance.web.form.FieldMany2One' ,
2012-11-05 13:02:32 +00:00
'many2onebutton' : 'instance.web.form.Many2OneButton' ,
2012-05-04 11:06:15 +00:00
'many2many' : 'instance.web.form.FieldMany2Many' ,
2012-05-25 15:05:44 +00:00
'many2many_tags' : 'instance.web.form.FieldMany2ManyTags' ,
'many2many_kanban' : 'instance.web.form.FieldMany2ManyKanban' ,
2012-04-17 12:09:49 +00:00
'one2many' : 'instance.web.form.FieldOne2Many' ,
'one2many_list' : 'instance.web.form.FieldOne2Many' ,
'reference' : 'instance.web.form.FieldReference' ,
'boolean' : 'instance.web.form.FieldBoolean' ,
'float' : 'instance.web.form.FieldFloat' ,
'integer' : 'instance.web.form.FieldFloat' ,
'float_time' : 'instance.web.form.FieldFloat' ,
'progressbar' : 'instance.web.form.FieldProgressBar' ,
'image' : 'instance.web.form.FieldBinaryImage' ,
'binary' : 'instance.web.form.FieldBinaryFile' ,
2012-11-16 11:25:17 +00:00
'many2many_binary' : 'instance.web.form.FieldMany2ManyBinaryMultiFiles' ,
2012-10-08 15:28:31 +00:00
'statusbar' : 'instance.web.form.FieldStatus' ,
'monetary' : 'instance.web.form.FieldMonetary' ,
2013-09-25 14:45:56 +00:00
'many2many_checkboxes' : 'instance.web.form.FieldMany2ManyCheckBoxes' ,
2013-10-04 15:37:34 +00:00
'x2many_counter' : 'instance.web.form.X2ManyCounter' ,
2011-03-31 10:57:51 +00:00
} ) ;
2011-10-31 10:27:52 +00:00
2012-05-02 09:27:43 +00:00
/ * *
* Registry of widgets usable in the form view that can substitute to any possible
* tags defined in OpenERP ' s form views .
*
* Every referenced class should extend FormWidget .
* /
2012-04-17 12:09:49 +00:00
instance . web . form . tags = new instance . web . Registry ( {
'button' : 'instance.web.form.WidgetButton' ,
2012-04-10 13:04:44 +00:00
} ) ;
2011-03-30 14:00:48 +00:00
2012-09-28 10:08:44 +00:00
instance . web . form . custom _widgets = new instance . web . Registry ( {
} ) ;
2013-08-06 12:50:22 +00:00
} ) ( ) ;
2011-03-30 14:00:48 +00:00
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: