Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 8fdaae3a

Von Kivitendo Admin vor mehr als 1 Jahr hinzugefügt

  • ID 8fdaae3a1194233c41862a4564169aed41e94c4a
  • Vorgänger a8cbee0b
  • Nachfolger d3353176

Konten ausziffern - Knockout Helper Funktionen

Unterschiede anzeigen:

js/knockout.kivitendo.js
1
// bindingHandlers
2

  
3
ko.bindingHandlers.toggle = {
4
  init: function(element, valueAccessor) {
5
    var value = valueAccessor();
6
    ko.applyBindingsToNode(element, {
7
      click: function() {
8
        value(!value());
9
      }
10
    });
11
  }
12
};
13

  
14
ko.bindingHandlers.formatted_date = {
15
  update: function(element, valueAccessor, allBindingsAccessor) {
16
    // console.log('valueAccessor = ' + valueAccessor());
17
    var value     = ko.utils.unwrapObservable(valueAccessor()) || undefined;
18
    // console.log("formatted_date value = " + value);
19
    if ( value !== undefined ) {
20
      $(element).text( kivi.format_date(value));
21
    }
22
  }
23
};
24

  
25
ko.bindingHandlers.parsed_formatted_date = {
26
  update: function(element, valueAccessor, allBindingsAccessor) {
27
    var value     = ko.utils.unwrapObservable(valueAccessor()) || undefined;
28
    $(element).text( kivi.parse_date(kivi.format_date(value)));
29
  }
30
};
31

  
32
ko.bindingHandlers.datepicker = {
33
    init: function(element, valueAccessor, allBindingsAccessor) {
34
        var $el = $(element);
35

  
36
        //initialize datepicker with some optional options
37
        var options = allBindingsAccessor().datepickerOptions || {
38
          showOn: "button",
39
          showButtonPanel: true,
40
          changeMonth: true,
41
          changeYear: true,
42
          buttonImage: "image/calendar.png",
43
          buttonImageOnly: true
44
        };
45
        // $.datepicker.setDefaults( $.datepicker.regional[ kivi.myconfg.countrycode ] );
46
        $el.datepicker(options);
47

  
48
        //handle the field changing
49
        // debugger;
50
        ko.utils.registerEventHandler(element, "change", function() {
51
            // update observable whenever input value changes
52

  
53
            // the change event is fired after datepicker internally sets the date and then updates the input
54
            // at this point viewModel.mydata (valueAccessor) still contains the old value
55
            // and we can update/sync it with the value from getpicker.getDate
56

  
57
            // but date may also have been changed manually by user, e.g. using the shortcut 2604
58

  
59
            // console.log('element contains ' + $(element).val());
60
            // console.log('event: change event on element, setting observable via getDate: ' + $el.datepicker("getDate"));
61
            var observable = valueAccessor(); // should contain the current date object in viewModel.myData
62

  
63
            var input_date;
64
            if ( $(element).val() === "" ) {
65
              // don't try parsing if element is empty
66
              input_date = null;
67
            } else {
68
              console.log('about to parse');
69
              input_date = kivi.parse_date($(element).val());
70
              console.log( "isNaN = " + isNaN(input_date.getTime) );
71
            }
72

  
73
            var picker_date = $el.datepicker("getDate");
74
            // console.log("input_date = " + kivi.format_date(input_date) + '    picker_date = ' + kivi.format_date(picker_date));
75
            // console.log("input_date - picker_date = " + (input_date - picker_date));
76

  
77
            // if input was updated via datepicker, getDate will already contain the desired date, use that (observable(picker_date))
78
            //   and input_date and picker_date will match!
79
            // but if input was updated manually, use the parsed_date and also update picker
80

  
81
            if ( input_date !== null && picker_date !== null && input_date - picker_date === 0 ) {
82
              console.log('input_date and picker_date are identical (set by picker), set observable to picker_date');
83
              observable(picker_date);
84
            } else if ( input_date === null ) {
85
              observable(""); // TODO: check that it is a date object, have we validated?
86
              // console.log('input_date and picker_date differ (input field set manually), set observable to input_date');
87
            } else {
88
              observable(input_date); // TODO: check that it is a date object, have we validated?
89
            }
90

  
91
            // observable(new_date);
92
            // return;
93

  
94
            // console.log('event: unwrapped observable: ' + ko.unwrap(observable));
95
            // console.log('event: observable: ' + observable());
96
            // observable still contains the old date Object from vm
97
            // debugger;
98
            // setTimeout(function(){
99
            //     console.log("running after timeout");
100
                // observable($el.datepicker("getDate"));
101
            // }, 10);
102
        });
103

  
104
        //handle disposal (if KO removes by the template binding)
105
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
106
            $el.datepicker("destroy");
107
        });
108

  
109
    },
110
    update: function(element, valueAccessor) {
111
        console.log("the value of the observable was changed, so now we need to update the datepicker");
112
        var value = ko.utils.unwrapObservable(valueAccessor()),
113
            $el = $(element),
114
            current = $el.datepicker("getDate");
115
        var observable = valueAccessor(); // should contain a date object
116
        // debugger;
117
        console.log("observabl: " + ko.unwrap(observable));
118
        console.log("update: value = " + value);
119
        console.log("update: current = " + current);
120
        console.log("update: el.val  = " + $el.val());
121
        console.log("update: el.val  = " + $el.val());
122

  
123
        // if ( isNaN( ko.unwrap(observable())).getTime() ) {
124
        //   console.log("isNaN");
125
        // } else {
126
          // $el.datepicker("setDate", value);
127
        // }
128

  
129
        // if ( current !== null && $el.val() !== '' ) { //$el.val() !== null && curr) {
130
        //   var parsed_date = kivi.parse_date($el.val());
131
        //   var formatted_date = kivi.format_date(parsed_date);
132
        //   console.log("parsed_date = " + parsed_date + ", formatted_date = " + formatted_date);
133
        //   $el.datepicker("setDate", parsed_date);
134
        //   valueAccessor(parsed_date);
135
        // }
136
        if (value - current !== 0) {
137
            console.log('setting date via setDate to ' + value);
138
            $el.datepicker("setDate", value);
139
        }
140
    }
141
};
142

  
143
ko.bindingHandlers.formatted_amount = {
144
  update: function(element, valueAccessor, allBindingsAccessor) {
145
      var value     = ko.utils.unwrapObservable(valueAccessor()) || undefined;
146
      var precision = ko.utils.unwrapObservable(allBindingsAccessor().precision) || 2;
147
      var type = ko.utils.unwrapObservable(allBindingsAccessor().type) || '';
148

  
149
      // automatically add class numeric so we don't have to do it in template
150
      // useful for td
151
      // debugger;
152
      if ( element.tagName === 'TD' ) {  // other tagnames: SPAN
153
        // maybe have it as an option in allBindingsAccessor?, e.g.
154
        // var numeric = ko.utils.unwrapObservable(allBindingsAccessor().numeric) || '';
155
        // if ( numeric ) {
156
        $(element).addClass('numeric');
157
        // }
158
      }
159
      // console.log('updating formatted_amount bH with reference ' + $(element).parent().find('td:eq(1)').html() + ' and value ' + value);
160
      if ( value !== undefined ) {
161
        value = + value;
162
        if ( type === 'cd' ) {
163
          $(element).text( format_sh(value) );
164
        } else {
165
          // console.log('cd');
166
          var formattedAmount = kivi.format_amount(value, precision);
167
          $(element).text(formattedAmount);
168
        }
169
      } else {
170
        $(element).text(''); // don't return undefined here, otherwise deselecting the last element won't work (updating sums)
171
      }
172
  }
173
};
174

  
175
// extenders
176

  
177
// adding several properties to target in one extender
178
ko.extenders.fibu_sums = function (target, unused) {
179
  // console.log('called fibu_sums extender');
180
  // target is an array of bookings
181

  
182
  // debugger;
183
  // create various sums from bookings
184
  // assumes booking model contains:
185
  // *  Numbers debit, credit, amount (not observables)
186
  // *  amount as a Number
187
  //
188
  target.debitSum = ko.computed(function () {
189
    return bookings_sum(target, 'debit');
190
  });
191
  target.creditSum = ko.computed(function () {
192
    return bookings_sum(target, 'credit');
193
  });
194
  target.saldo  = ko.computed(function () {
195
    return bookings_sum(target, true);
196
  });
197
  target.saldo_cd = ko.computed(function () {
198
    return bookings_sum(target, 'cd');
199
  });
200
  target.hasBookings = ko.computed(function () {
201
    return target().length > 0;
202
  });
203
  target.isBalanced = ko.computed(function () {
204
    if ( target().length == 0 )
205
      return false;
206
    return bookings_sum(target, true) == 0 ? true : false;
207
  });
208
  target.hasCreditSaldo = ko.computed(function () {
209
    return target.saldo() > 0 ? true : false;
210
  });
211
  target.hasDebitSaldo = ko.computed(function () {
212
    return target.saldo() < 0 ? true : false;
213
  });
214

  
215
  return target;
216
};
217

  
218
ko.extenders.to_kivitendo = function (target, precision) {
219
  target.to_kivitendo = ko.computed(function () {
220
    return target() === null ? undefined : kivi.format_amount(target(), precision);
221
 });
222
};
223

  
224
// ko.extenders.to_kivitendo_rewrite = function(target, precision) {
225
//     //create a writable computed observable to intercept writes to our observable
226
//     var result = ko.pureComputed({
227
//         read: target,
228
//         write: function(newValue) {
229
//             var current = target(),
230
//                 newValueAsNum = isNaN( kivi.parse_amount(newValue)) ? 0 : kivi.parse_amount(newValue),
231
//                 valueToWrite = kivi.format_amount(newValueAsNum, precision);
232
//             //only write if it changed
233
//             if (valueToWrite !== current) {
234
//                 target(valueToWrite);
235
//             } else {
236
//                 //if the rounded value is the same, but a different value was written, force a notification for the current field
237
//                 if (newValue !== current) {
238
//                     target.notifySubscribers(valueToWrite);
239
//                 }
240
//             }
241
//         }
242
//     }).extend({ notify: 'always' });
243
//
244
//     //initialize with current value to make sure it is rounded appropriately
245
//     result(target());
246
//
247
//     //return the new computed observable
248
//     return result;
249
// };
250

  
251
ko.extenders.to_kivitendo_not_zero_reformat = function(target, precision) {
252
    //create a writable computed observable to intercept writes to our observable
253
    var result = ko.pureComputed({
254
        read: target,  //always return the original observables value
255
        write: function(newValue) {
256
            <!-- console.log('changing from ' + target() + ' to ' + newValue + ' &#45;> (' + kivi.format_amount(newValue,2) + ')'); -->
257
            // console.log('changing from ' + target() + ' to ' + newValue);
258
            var current = target();
259
            var formattedNewValue = isNaN(newValue) ? kivi.parse_amount(newValue) : newValue;
260
            var newValueAsNum = isNaN(formattedNewValue) ? undefined : formattedNewValue;
261
            var valueToWrite = formattedNewValue ? kivi.format_amount(formattedNewValue, precision) : undefined;
262
            //only write if it changed
263
            if (valueToWrite !== current) {
264
                target(valueToWrite);
265
            } else {
266
                //if the rounded value is the same, but a different value was written, force a notification for the current field
267
                if (newValue !== current) {
268
                    target.notifySubscribers(valueToWrite);
269
                }
270
            }
271
        }
272
    }).extend({ notify: 'always' });
273

  
274
    //initialize with current value to make sure it is rounded appropriately
275
    result(target());
276

  
277
    //return the new computed observable
278
    return result;
279
};
280

  
281
// ko.extenders.to_kivitendo_not_zero = function(target, precision) {
282
//     //create a writable computed observable to intercept writes to our observable
283
//     var result = ko.pureComputed({
284
//         read: target,  //always return the original observables value
285
//         write: function(newValue) {
286
//             var current = target(),
287
//                 newValueAsNum = isNaN(newValue) ? undefined : +newValue,
288
//                 valueToWrite = newValueAsNum ? kivi.format_amount(newValueAsNum, precision) : undefined;
289
//             //only write if it changed
290
//             if (valueToWrite !== current) {
291
//                 target(valueToWrite);
292
//             } else {
293
//                 //if the rounded value is the same, but a different value was written, force a notification for the current field
294
//                 if (newValue !== current) {
295
//                     target.notifySubscribers(valueToWrite);
296
//                 }
297
//             }
298
//         }
299
//     }).extend({ notify: 'always' });
300
//
301
//    //initialize with current value to make sure it is rounded appropriately
302
//    result(target());
303
//
304
//    //return the new computed observable
305
//    return result;
306
//};
307

  
308
ko.extenders.to_amount_cd = function (target, precision) {
309
  target.to_amount_cd = ko.computed(function () {
310
    return target() === null ? undefined : format_sh(target())
311
 });
312
};
313

  
314
ko.extenders.formatted = function (underlyingObservable, formatFunction) {
315
  underlyingObservable.formatted = ko.computed(function () {
316
    return formatFunction(underlyingObservable());
317
 });
318
};
319

  
320
// helper functions
321

  
322
function bookings_sum (bookings, type) {
323
  var total = 0;
324
  ko.utils.arrayForEach(bookings(), function(booking) {
325
    if ( type === 'credit' ) {
326
      total += Number(booking.credit);
327
    } else if ( type === 'debit' ) {
328
      total += Number(booking.debit);
329
    } else {
330
      total += booking.amount;
331
    }
332
  });
333
  if ( type === 'cd' ) {
334
    return format_sh(total);
335
  } else {
336
    return total.toFixed(5);
337
  }
338
}
339

  
340
function format_sh (val) {
341
  if ( val === null ) {
342
    return undefined;
343
  } else {
344
    if ( val === 0 ) {
345
      return kivi.format_amount(val,2);
346
    } else if ( val < 0 ) {
347
      return kivi.format_amount(val * (-1),2) + ' S';
348
    } else if ( val > 0 ) {
349
      return kivi.format_amount(val *  (1),2) + ' H';
350
    } else {
351
      return val;
352
    }
353
  }
354
}

Auch abrufbar als: Unified diff