Partpicker: Filtermöglichkeit nach konvertierbaren Einheiten ('convertible_unit')
[kivitendo-erp.git] / js / autocomplete_part.js
1 namespace('kivi', function(k){
2   k.PartPickerCache = { }
3   k.PartPicker = function($real, options) {
4     var o = $.extend({
5       limit: 20,
6       delay: 50,
7     }, options);
8     var STATES = {
9       UNIQUE: 1,
10       UNDEFINED: 0,
11     }
12     var real_id = $real.attr('id');
13     var $dummy  = $('#' + real_id + '_name');
14     var $type   = $('#' + real_id + '_type');
15     var $unit   = $('#' + real_id + '_unit');
16     var $convertible_unit = $('#' + real_id + '_convertible_unit');
17     var $column = $('#' + real_id + '_column');
18     var state   = STATES.PICKED;
19     var last_real = $real.val();
20     var last_dummy = $dummy.val();
21     var open_dialog = function(){
22       open_jqm_window({
23         url: 'controller.pl?action=Part/part_picker_search',
24         data: $.extend({
25           real_id: real_id,
26         }, ajax_data($dummy.val())),
27         id: 'part_selection',
28       });
29       return true;
30     };
31
32     function ajax_data(term) {
33       var data = {
34         'filter.all:substr::ilike': term,
35         'filter.obsolete': 0,
36         'filter.unit_obj.convertible_to': $convertible_unit && $convertible_unit.val() ? $convertible_unit.val() : '',
37         column:   $column && $column.val() ? $column.val() : '',
38         current:  $real.val(),
39       };
40
41       if ($type && $type.val())
42         data['filter.type'] = $type.val().split(',');
43
44       if ($unit && $unit.val())
45         data['filter.unit'] = $unit.val().split(',');
46
47       return data;
48     }
49
50     function set_item (item) {
51       if (item.id) {
52         $real.val(item.id);
53         // autocomplete ui has name, ajax items have description
54         $dummy.val(item.name ? item.name : item.description);
55       } else {
56         $real.val('');
57         $dummy.val('');
58       }
59       state = STATES.PICKED;
60       last_real = $real.val();
61       last_dummy = $dummy.val();
62       $real.trigger('change');
63     }
64
65     function make_defined_state () {
66       if (state == STATES.PICKED)
67         return true
68       else if (state == STATES.UNDEFINED && $dummy.val() == '')
69         set_item({})
70       else
71         set_item({ id: last_real, name: last_dummy })
72     }
73
74     function update_results () {
75       $.ajax({
76         url: 'controller.pl?action=Part/part_picker_result',
77         data: $.extend({
78             'real_id': $real.val(),
79         }, ajax_data(function(){ var val = $('#part_picker_filter').val(); return val === undefined ? '' : val })),
80         success: function(data){ $('#part_picker_result').html(data) }
81       });
82     };
83
84     function close_popup() {
85       $('#part_selection').jqmClose()
86     };
87
88     $dummy.autocomplete({
89       source: function(req, rsp) {
90         $.ajax($.extend(o, {
91           url:      'controller.pl?action=Part/ajax_autocomplete',
92           dataType: "json",
93           data:     ajax_data(req.term),
94           success:  function (data){ rsp(data) }
95         }));
96       },
97       select: function(event, ui) {
98         set_item(ui.item);
99       },
100     });
101     /*  In case users are impatient and want to skip ahead:
102      *  Capture <enter> key events and check if it's a unique hit.
103      *  If it is, go ahead and assume it was selected. If it wasn't don't do
104      *  anything so that autocompletion kicks in.  For <tab> don't prevent
105      *  propagation. It would be nice to catch it, but javascript is too stupid
106      *  to fire a tab event later on, so we'd have to reimplement the "find
107      *  next active element in tabindex order and focus it".
108      */
109     $dummy.keypress(function(event){
110       if (event.keyCode == 13 || event.keyCode == 9) { // enter or tab or tab
111         // if string is empty assume they want to delete
112         if ($dummy.val() == '') {
113           set_item({});
114           return true;
115         } else if (state == STATES.PICKED) {
116           return true;
117         }
118         $.ajax({
119           url: 'controller.pl?action=Part/ajax_autocomplete',
120           dataType: "json",
121           data: $.extend( ajax_data($dummy.val()), { prefer_exact: 1 } ),
122           success: function (data){
123             if (data.length == 1) {
124               set_item(data[0]);
125               if (event.keyCode == 13)
126                 $('#update_button').click();
127             } else if (data.length > 1) {
128              if (event.keyCode == 13)
129                 open_dialog();
130               else
131                 make_defined_state();
132             } else {
133               if (event.keyCode == 9)
134                 make_defined_state();
135             }
136           }
137         });
138         if (event.keyCode == 13)
139           return false;
140       } else {
141         state = STATES.UNDEFINED;
142       }
143     });
144
145 //    $dummy.blur(make_defined_state);  // blur triggers also on open_jqm_dialog
146
147     // now add a picker div after the original input
148     var pcont  = $('<span>').addClass('position-absolute');
149     var picker = $('<div>');
150     $dummy.after(pcont);
151     pcont.append(picker);
152     picker.addClass('icon16 CRM--Schnellsuche').click(open_dialog);
153
154     return {
155       real:           function() { return $real },
156       dummy:          function() { return $dummy },
157       type:           function() { return $type },
158       unit:           function() { return $unit },
159       convertible_unit: function() { return $convertible_unit },
160       column:         function() { return $column },
161       update_results: update_results,
162       set_item:       set_item,
163       reset:          make_defined_state,
164       init_results:    function () {
165         $('div.part_picker_part').each(function(){
166           $(this).click(function(){
167             set_item({
168               name: $(this).children('input.part_picker_description').val(),
169               id:   $(this).children('input.part_picker_id').val(),
170             });
171             close_popup();
172             return true;
173           });
174         });
175         $('#part_selection').keypress(function(e){
176            if (e.keyCode == 27) { // escape
177              close_popup();
178              $dummy.focus();
179            }
180         });
181       }
182     }
183   }
184 });
185
186 $(function(){
187   $('input.part_autocomplete').each(function(i,real){
188     kivi.PartPickerCache[real.id] = new kivi.PartPicker($(real));
189   })
190 });