PageSourceSearch

https://auction.drawingcenter.org/public/js/client/ws/auctionClient.js?t=1784745125

js drawingcenter.org collected 2026-10-02 03:32:03 UTC 75,750 bytes, 1,762 lines download raw bytes

1var CSS_GREEN = 'green_t';
2var CSS_RED = 'red_t';
3var CSS_BLACK = 'color_black01';
4
5var stateCssColor = [];
6stateCssColor['success'] = CSS_GREEN;
7stateCssColor['sold'] = CSS_GREEN;
8stateCssColor['error'] = CSS_RED;
9stateCssColor['unsold'] = CSS_BLACK;
10
11var DEFAULT_AUDIO_VOLUME = 1.0;
12var CONNECTION_ISSUE_LOG_COUNT = 0;
13var SUCCESS_CONNECT_COUNT = 0;
14
15var overlayNotificationTimeout = null;
16
17/**
18 * Polyfill for keys()
19 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
20 */
21if (!Object.keys) {
22    Object.keys = (function () {
23        'use strict';
24        var hasOwnProperty = Object.prototype.hasOwnProperty,
25                hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
26                dontEnums = [
27                    'toString',
28                    'toLocaleString',
29                    'valueOf',
30                    'hasOwnProperty',
31                    'isPrototypeOf',
32                    'propertyIsEnumerable',
33                    'constructor'
34                ],
35                dontEnumsLength = dontEnums.length;
36
37        return function (obj) {
38            if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
39                throw new TypeError('Object.keys called on non-object');
40            }
41
42            var result = [], prop, i;
43
44            for (prop in obj) {
45                if (hasOwnProperty.call(obj, prop)) {
46                    result.push(prop);
47                }
48            }
49
50            if (hasDontEnumBug) {
51                for (i = 0; i < dontEnumsLength; i++) {
52                    if (hasOwnProperty.call(obj, dontEnums[i])) {
53                        result.push(dontEnums[i]);
54                    }
55                }
56            }
57            return result;
58        };
59    }());
60}
61
62/**
63 * WebSocket Auction Client
64 * @author Amit
65 **/
66
67function AuctionClient() {
68    this.connection = null;
69    this.connectionErrorCode = 0;
70    this.clientData = null;
71    this.currency = [];
72    
73    var webSocket = setting.webSocket;
74    this.defaultSiteName = setting.defaultSiteName;
75    this.siteName = setting.siteName;
76    this.webSocketEndPoint = webSocket.host + (webSocket.port ? ":" + webSocket.port : '') + "/";
77    
78    this.webSocket = window.WebSocket || window.MozWebSocket;
79    this.consoleContent = $('#content');
80    this.criteoTrackTransactionIndex = -1;
81
82    this.configReserveMet = setting.reserveMet;
83    this.showReserveMetBanner = false;
84    this.foreceDisplayHighestBidderMessage = false;
85    if(this.configReserveMet){
86        if(this.configReserveMet.met) this.showReserveMetBanner = this.configReserveMet.met.showBanner;
87        if(this.configReserveMet.notMet)this.foreceDisplayHighestBidderMessage = this.configReserveMet.notMet.foreceDisplayHighestBidderMessage;
88    }
89    if (!this.webSocket) {
90        this.appendConsoleContent(i18nTranslate('Sorry, but your browser doesn\'t support WebSockets.'));
91        return false;
92    }
93
94    this.LotSnapshotReason = {
95        UNKNOWN:                        0,
96        LOT_STATE_CHANGED:              1,
97        LOT_BID_UPDATED:                2,
98        LOT_BID_RETRACTED:              3,
99        LOT_INCREMENT_CHANGED:          4,
100        LOT_MANUAL_NEXT_BID_APPLIED:    5,
101        LOT_END_TIME_EXTENDED:          6,
102        LOT_RE_OPENED:                  7
103    };
104
105    this.messageType = {
106        UNKNOWN: 0,
107        FAIRWARNING: 1,
108        FIVESECONDWARNING: 2,
109        GENERALMESSAGE: 3
110    };
111    this.fiveSecondsTimerInstance = null;
112
113    this.soundFiles = {
114        startLot: getUrl('public/sound/chimes.wav'),
115        passLot: getUrl('public/sound/passed.wav'),
116        biddingLot: getUrl('public/sound/place_bid.wav'),
117        bidAccepted: getUrl('public/sound/bid_accepted.wav'),
118        bidReceived: getUrl('public/sound/bid_received.wav'),
119        outBid: getUrl('public/sound/out_bid.mp3'),
120        winLot: getUrl('public/sound/sold_won.wav'),
121        notWonLot: getUrl('public/sound/sold_not_won.wav'),
122        fairWarning: getUrl('public/sound/fair_warning.wav')
123    };
124
125    this.sound = {
126        startLot: null,
127        passLot: null,
128        biddingLot: null,
129        bidAccepted: null,
130        bidReceived: null,
131        outBid: null,
132        winLot: null,
133        notWonLot: null,
134        fairWarning: null
135    };
136    
137    this.logType = {
138        error: 1,
139        warning: 2,
140        log: 3
141    };
142
143    var _bidsquareBidderTxt = i18nTranslate(this.defaultSiteName+' Bidder');
144    var _competingBidderTxt = i18nTranslate('Competing Bidder');
145    var _bidderTxt = i18nTranslate('Bidder');
146    /*We are setting bidder text static now, In future we are making dynamic this changes*/
147    /*WL setting*/
148    this.bidderSettingWl = {
149        'bidsquare':{
150            "text" : _competingBidderTxt,
151            'showBidderNo': false
152        },
153        'wl':{
154            "text" : _bidderTxt,
155            'showBidderNo': true
156        },
157        'floor':{
158            "text" : _competingBidderTxt,
159            'showBidderNo': false   
160        }
161    };
162    /*Bidsquare setting*/
163    this.bidderSettingBidsquare = {
164        'bidsquare':{
165            "text" : _bidsquareBidderTxt,
166            'showBidderNo': true
167        },
168        'wl':{
169            "text" : _competingBidderTxt,
170            'showBidderNo': false
171        },
172        'floor':{
173            "text" : _competingBidderTxt,
174            'showBidderNo': false   
175        }
176    };
177
178    /*Clerk setting*/
179    this.bidderSettingClerk = {
180        'bidsquare':{
181            "text" : _bidsquareBidderTxt,
182            'showBidderNo': true
183        },
184        'wl':{
185            "text" : _bidderTxt,
186            'showBidderNo': true
187        },
188        'floor':{
189            "text" : _competingBidderTxt,
190            'showBidderNo': true   
191        }
192    };
193
194    // assert "permission" for sound effects, 
195    // note we are not using the Promise then/catch returned since that will only reject on user interaction
196    //  if we change it to reject on queue of interaction we then can not fulfill it with a resolve afterwards, Promise Chaining won't work well for that either
197    //  the 2 cases that will execute are only onPlaySoundSuccess if we don't need permision granted or first onPlaySoundFailure and then onPlaySoundSuccess after user interacts
198    mediaPlaybackRequiresUserGesture(this.onPlaySoundSuccess.bind(this), this.onPlaySoundFailure.bind(this));
199    
200    this.setVolume(DEFAULT_AUDIO_VOLUME);
201    this.setCriteoTrackTransactionIndex();
202    
203    this.localStorageId = null;
204    this.localStorageDatatimeId = null;
205    
206    this.isWidget = false;
207}
208AuctionClient.prototype.eventItemTimerInstance = {};
209AuctionClient.prototype.appendConsoleContent = function (contentString) {
210    if (setting.webSocket.debug) {
211        console.log(contentString);
212    }
213};
214
215/*Get Bidder text as per the setting*/
216/*We believe we can pass */
217AuctionClient.prototype.getBidderTxt = function (siteId,bidderId,isFloorBid) {
218    /*Get Biddersetting obj as per current site id*/
219    var bidderSettingObj = this.bidderSettingBidsquare;
220    var isEventClerk = this.isEventClerk();
221    if (isEventClerk) {
222        bidderSettingObj = this.bidderSettingClerk;
223    }
224    else if (this.clientData.siteID) {
225        bidderSettingObj = this.bidderSettingWl;
226    }
227
228    /*Get Biddersetting as per receive siteid from AE*/
229    var bidderSetting = bidderSettingObj.bidsquare;
230    if(typeof isFloorBid !=='undefined' && isFloorBid) {
231        var bidderSetting = bidderSettingObj.floor;
232    }
233    else if (typeof siteId !== 'undefined' && siteId) {
234        bidderSetting = bidderSettingObj.wl;
235    }
236    
237    if (!isEventClerk && typeof this.clientData.hideBidderNumber !== 'undefined' && this.clientData.hideBidderNumber) {
238        bidderSetting['showBidderNo'] = false;
239    }
240    
241    /*Set Bidder Text as per setting*/
242    var txt = bidderSetting['text'];
243    if(bidderSetting['showBidderNo'] && typeof bidderId !=='undefined' && bidderId) {
244        txt += " " + bidderId;
245    }
246
247    return txt;
248};
249
250
251AuctionClient.prototype.logError = function (data) {
252    //this.appendConsoleContent('logError > data: ' + data);
253    this.appendConsoleContent('AE connection failed issue logged');
254    var logOption = data;
255    logOption.uri = 'auction/log';
256    logOption = $.extend({}, this.clientData, logOption);
257    this.appendConsoleContent('logError > logOption: ' + logOption);
258    phpLog(logOption, this.logType.error);
259};
260
261AuctionClient.prototype.addAuction = function (auctionID) {
262    this.auctionIDs = this.addIds(auctionID);
263};
264
265AuctionClient.prototype.addLot = function (lotIDs) {
266    this.lotIDs = this.addIds(lotIDs);
267};
268
269AuctionClient.prototype.addIds = function (ids) {
270    var storage = [];
271    switch (typeof (ids)) {
272        case 'object':
273            /*for (var e in ids) {
274                storage.push(ids[e]);
275            }*/
276            storage = ids;
277            break;
278        case 'number':
279            storage.push(ids);
280            break;
281    }
282    
283    return storage;
284};
285
286AuctionClient.prototype.initializeConnection = function () {
287    var hasSuccess = false;
288    this.connection = this.connection || new WebSocket(this.webSocketEndPoint);
289    // this is technically wrong 
290    // if we had a previous connection then we want to really track how many connections are open
291    // and show if any connection is not open and clear when all connections are open successfully
292    // for now this is good enough and fixes the issue when we have multiple instances of auctionClient running
293    // i.e. multiple instances can be due to 1 live and 1 timed running on the same page.
294    if (overlayNotificationTimeout) clearTimeout(overlayNotificationTimeout);
295    overlayNotificationTimeout = setTimeout(function() {
296        this.reconnectOverlayNotification('on');
297    }.bind(this), 3000);
298    this.connection.onopen = function () {
299        this.appendConsoleContent('Connected to AE');
300        if (this.isWidget)
301        {
302            window.parent.postMessage({BSQMessageType: "bsqAEConnected", bsqAEConnected: true}, '*');
303        }
304        this.reconnectOverlayNotification('off');
305        this.publishStoredMessage();
306        this.publishInitialMessage();
307        this.clientLogin();
308    }.bind(this);
309    this.connection.onerror = function (error) {
310        var errorJson = JSON.stringify(error);
311        this.appendConsoleContent('Error: ' + errorJson);
312    }.bind(this);
313    this.connection.onmessage = function (message) {
314        if (!hasSuccess) SUCCESS_CONNECT_COUNT++;
315        hasSuccess = true;
316        try {
317            var json = JSON.parse(message.data);
318            if (json.data !== null) this.processClient(json);
319        } catch (e) {
320            this.appendConsoleContent(e);
321            this.appendConsoleContent('This doesn\'t look like a valid JSON: ' + message.data);
322            return;
323        }
324    }.bind(this);
325    this.connection.onclose = function (e) {
326        if (!e.wasClean) {
327            this.appendConsoleContent('Not connected to AE');
328            this.connectionErrorCode = e.code;
329            /**
330             * Only throw the "Not Connected. Try re-connecting" popup at live panel
331             */
332            this.reconnectOverlayNotification('on');
333            
334            /**
335             * Only reconnect when the below error code found
336             * The below listed error codes seems to be safe to reconnect
337             * 
338             * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
339             */
340            switch (e.code) {
341                case 1005: //No Status Recvd
342                case 1006: //Abnormal Closure
343                case 1009: //Message too big
344                case 1011: //Internal Error
345                case 1012: //Service Restart
346                case 1013: //Try Again Later
347                    this.connection = null;
348                    this.appendConsoleContent('Trying re-connect');
349                    setTimeout(function(){
350                        // We have to set mergedCallbackForPopulateItemInfo false to ajax call fo fetch item details on reconnecting connection
351                        if (typeof this.mergedCallbackForPopulateItemInfo !== 'undefined') {
352                            this.mergedCallbackForPopulateItemInfo = false;
353                        }
354                        this.initializeConnection();
355                    }.bind(this), 500); //Seems like websocket need to some time to completly close the connection. So, try to reconnect after few ms.
356                    break;
357                default:
358                    this.appendConsoleContent('Please save your bid and refresh the page');
359            }
360        }
361    }.bind(this);
362};
363
364AuctionClient.prototype.processClientMessage = function (data, senderTxt) {
365    var message = {
366        signature: "LAE_PROTOCOL",
367        type: "message",
368        version: 1,
369        sender: senderTxt,
370        sendTime: (new Date()).getTime(),
371        data: data
372    };
373    return message;
374};
375
376AuctionClient.prototype.sendMessage = function (data, callback) {
377    //this.appendConsoleContent('sendMessage > data: ' + JSON.stringify(data));
378    var messageOption = data;
379    var clientData = $.extend({}, clientData, this.clientData);
380    var registrationNumbers = {};
381    if (typeof clientData.registrationNumbers !== 'undefined') {
382        registrationNumbers = clientData.registrationNumbers;
383        delete clientData.registrationNumbers;
384    }
385    if (typeof clientData !== 'undefined') {
386        messageOption = $.extend({}, messageOption, clientData);
387    }
388    if (typeof messageOption.userID !== 'undefined' && typeof messageOption.auctionID !== 'undefined') {
389        if (messageOption.userID > 0) {
390            var bidderNumber = messageOption.userID;
391            if (typeof registrationNumbers[messageOption.userID] !== 'undefined') {
392                if (typeof registrationNumbers[messageOption.userID][messageOption.auctionID] !== 'undefined') {
393                    bidderNumber = registrationNumbers[messageOption.userID][messageOption.auctionID];
394                }
395            }
396            if (typeof messageOption.registeredBidderID !== 'undefined') {
397                bidderNumber = messageOption.registeredBidderID;
398            }
399            messageOption = $.extend({}, messageOption, {registeredBidderID: bidderNumber});
400        }
401    }
402    //this.appendConsoleContent('sendMessage > messageOption: ' + JSON.stringify(messageOption));
403    var message = this.processClientMessage(messageOption);
404    var json = JSON.stringify(message);
405    this.appendConsoleContent('MessageSend: ' + json);
406    if (this.connection && this.connection.readyState === 1) {
407        //this.appendConsoleContent('Sending Message to LAE');
408        this.connection.send(json);
409        if (typeof callback === 'function') {
410            callback();
411        }
412    } else {
413        var intervalCount = 0;
414        var timeoutInterval = setInterval(function() {
415            if (!this.connection || this.connection.readyState !== 1) {
416                intervalCount += 1;
417            } else {
418                clearInterval(timeoutInterval);
419                this.sendMessage(data, callback);
420            }
421            //Will wait for 15 sec before client put to the timeout
422            if (intervalCount > 15) {
423                if (this.isNonLiveClient()) alert("Trying to reconnect. Please try again.");
424                clearInterval(timeoutInterval);
425                if (typeof callback === 'function') {
426                    callback();
427                }
428            }
429        }.bind(this), 1000);
430    }
431};
432
433AuctionClient.prototype.addClient = function (clientData) {
434    this.clientData = clientData;
435    
436    this.clientData.setIsPaymentVerified = function (verified)
437    {
438        if (typeof this.paymentVerified === 'undefined')
439        {
440            this.paymentVerified = 0;
441        }
442        this.paymentVerified = (typeof verified !== 'undefined') ? verified : 0;
443    };
444    
445    this.clientData.isPaymentVerified = function ()
446    {
447        if (typeof this.paymentVerified !== 'undefined')
448        {
449            if (this.paymentVerified === 1)
450            {
451                return true;
452            }
453        }
454        return false;
455    };
456};
457
458AuctionClient.prototype.addCurrency = function (eventCurrency) {
459    this.currency = eventCurrency;
460};
461
462AuctionClient.prototype.validateNumber = function (number) {
463    //var regxNumber = /^\d+(\.\d+)?$/;
464    var regxNumber = /^\d+$/;
465    return regxNumber.test(number);
466};
467
468AuctionClient.prototype.clientLogin = function () {
469    //this.appendConsoleContent('Inside this.clientLogin()');
470    var messageOption = {
471        action: "login"
472    };
473    //this.appendConsoleContent('clientLogin > messageOption: ' + JSON.stringify(messageOption));
474    //this.appendConsoleContent('clientLogin > sendMessage');
475    this.sendMessage(messageOption, function () {
476        //this.appendConsoleContent('clientLogin > sendMessage > Message Send.....');
477    }.bind(this));
478};
479
480AuctionClient.prototype.clientSubscription = function () {
481    //this.appendConsoleContent('Inside this.clientSubscription()');
482    //this.appendConsoleContent('clientSubscription > sendMessage');
483    if (!this.lotIDs || this.lotIDs.length === 0) {
484        this.sendMessage({
485            action: "subscribe",
486            auctionIDs: this.auctionIDs,
487            lotIDs: this.lotIDs,
488            subscriptionID: generateUid()
489        }, function () {
490            //this.appendConsoleContent('clientSubscription > sendMessage > Message Send.....');
491        }.bind(this));
492    } else {
493        var auctionIDs = Object.keys(this.lotIDs);
494        if (auctionIDs.length > 0) {
495            for (var a in auctionIDs) {
496                var auctionId = auctionIDs[a];
497                var lotIDs = Object.keys(this.lotIDs[auctionId]);
498                if (lotIDs.length > 0) {
499                    var lots = [];
500                    for (var l in lotIDs) {
501                        lots.push(parseInt(lotIDs[l]));
502                    }
503                    this.sendMessage({
504                        action: "subscribe",
505                        auctionIDs: [parseInt(auctionId)],
506                        lotIDs: lots,
507                        subscriptionID: generateUid()
508                    }, function () {
509                        //this.appendConsoleContent('clientSubscription > sendMessage > Message Send.....');
510                    }.bind(this));
511                }
512            }
513        }
514    }
515};
516
517AuctionClient.prototype.updateLotStatus = function (lotId, auctionId, soldPice, highestBidder, itemStatus, nextItemID) {
518    //this.appendConsoleContent('Inside this.updateLotSatus()');
519    //this.appendConsoleContent('updateLotSatus > auctionId: ' + auctionId);
520    //this.appendConsoleContent('updateLotSatus > lotId: ' + lotId);
521    var $this = this;
522    
523    var isRestrictedActivityAuction = this.isRestrictedActivityAuction(auctionId);
524
525    var lotIndex = 0;
526    var statType = '';
527
528    if ($this.isNonLiveClient()) {
529        var buttonStatWrapperSelector = $('#ba_' + lotId + '_' + auctionId);
530        lotIndex = buttonStatWrapperSelector.data('lindex');
531        statType = buttonStatWrapperSelector.data('stype');
532    }
533
534    if ($this.isLiveClient()) {
535        statType = 'live_panel_lot_slide';
536    }
537
538    var urlAjax = getUrl('item/buttonStat/' + lotId + '/' + auctionId + '/' + statType + '/' + lotIndex);
539    urlAjax += "?is_ajax=1&uls=1" + ($this.isWidget ? "&widget=1" : "");
540    
541    /*
542     * Need to send these value with defaulted to "0" (zero), even though they are not available.
543     */
544    if (typeof soldPice === 'undefined' || soldPice === null || isRestrictedActivityAuction) soldPice = 0;
545    if (typeof highestBidder === 'undefined' || highestBidder === null) highestBidder = 0;
546    if (typeof itemStatus === 'undefined' || itemStatus === null) itemStatus = 0;
547    
548    urlAjax += "&soldAmount=" + soldPice;
549    urlAjax += "&highestBidder=" + highestBidder;
550    urlAjax += "&itemStatus=" + itemStatus;
551    
552    if (typeof $this.mergedCallbackForPopulateItemInfo !== 'undefined' && $this.mergedCallbackForPopulateItemInfo) {
553        if (typeof nextItemID !== 'undefined') urlAjax += "&mergeItemInfo=1&nextItemId=" + nextItemID;
554    }
555    //this.appendConsoleContent('updateLotSatus > isNonLiveClient() > urlAjax: ' + urlAjax);
556    // On the live panel this whole request belongs to a single lot advance (from the sold lot
557    // to nextItemID) and paints the single shared UI. Rapid skips can leave requests in flight
558    // that resolve out of order, so: (1) abort the prior in-flight live request, and (2) ignore
559    // any response whose advance is no longer current, i.e. its next lot is no longer the panel
560    // target (_panelLotId). This gates the entire callback (both the buttonState render and the
561    // merged item paint) so we never apply a stale response. Non-live pages have a button per
562    // lot writing to per-lot DOM, so they are unaffected and keep the original behavior.
563    var isLivePanel = $this.isLiveClient();
564    // The lot this advance moves to; null when there is no next lot (last lot) so we don't
565    // gate the final sold lot's status update.
566    var reqNextLotId = (isLivePanel && typeof nextItemID !== 'undefined' && parseInt(nextItemID) > 0)
567        ? parseInt(nextItemID) : null;
568
569    // Abort the prior live buttonStat request (independent of the itemRelatedInfo request's
570    // own abort handle). The handle is not cleared on completion, so it may already be finished
571    // here - aborting a completed jqXHR is a harmless no-op (and the try/catch covers anything
572    // unexpected).
573    if (isLivePanel && $this._buttonStatXhr && typeof $this._buttonStatXhr.abort === 'function') {
574        try { $this._buttonStatXhr.abort(); } catch (e) { /* ignore */ }
575    }
576
577    var jsonData = null;
578    var xhr = $.ajax({
579        type: 'GET',
580        url: urlAjax,
581        dataType: 'json',
582        success: function (data) {
583            jsonData = data;
584        },
585        complete: function () {
586            if (!jsonData) return; // aborted (superseded) or failed request
587            // Ignore an out-of-order response for an advance that is no longer current.
588            if (reqNextLotId !== null && reqNextLotId !== $this._panelLotId) return;
589
590            if (typeof jsonData.buttonState !== 'undefined') {
591                var buttonState = jsonData.buttonState;
592                for (var i in buttonState) {
593                    var selector = buttonState[i].selector;
594                    var renderHtml = buttonState[i].renderHtml;
595                    var jqAction = buttonState[i].jqAction;
596                    switch (jqAction) {
597                        case 'replace':
598                            $(selector).html(renderHtml);
599                            break;
600                        case 'append':
601                            $(selector).append(renderHtml);
602                            break;
603                        case 'replaceWithSelector': // This case only using live panel buttom scroll items
604                            if (typeof buttonState[i].jqReplaceSelector !== 'undefined') {
605                                for (var s in buttonState[i].jqReplaceSelector) {
606                                    var jqReplaceSelector = buttonState[i].jqReplaceSelector[s];
607                                    $(selector).find(jqReplaceSelector).remove();
608                                }
609                            }
610                            $(selector).append(renderHtml);
611                            $(selector).removeClass("on").addClass("closed");
612                            break;
613                    }
614                }
615            }
616
617            if (typeof jsonData.item !== 'undefined') {
618                $this.registeredItemsInfo = jsonData.item;
619                if (typeof $this.populateLotRelatedInfoAjaxCompleteCallback !== 'undefined') {
620                    if (isLivePanel) $this.populateLotRelatedInfoAjaxCompleteCallback(auctionId);
621                }
622            }
623
624            // The buttonStat ajax has finished; let the live bid button advance gate know so
625            // it can re-enable once the new lot info/image are also ready.
626            if (isLivePanel && typeof $this._markBidButtonStatDone === 'function') {
627                $this._markBidButtonStatDone();
628            }
629        }
630    });
631    if (isLivePanel) $this._buttonStatXhr = xhr;
632};
633
634AuctionClient.prototype.enableButton = function (buttonElement) {
635    buttonElement.css('opacity', 1);
636    buttonElement.prop('disabled', false);
637};
638
639AuctionClient.prototype.disableButton = function (buttonElement, dimmed) {
640    buttonElement.prop('disabled', true);
641    var opacity = "";
642    if (dimmed !== 'undefined' && dimmed) {
643        opacity = "0.5";
644    }
645    buttonElement.css('opacity', opacity);
646};
647
648AuctionClient.prototype._displayMessage = function (typeTxt, lotId, auctionId, messageTxt) {
649    var elementSelector = '#msg_' + lotId + '_' + auctionId;
650    if (lotId === null && auctionId === null) {
651        elementSelector = '.ack_bid_msg';
652    }
653    var elementCssColor = stateCssColor;
654    var messageElement = $(elementSelector);
655    for (var c in elementCssColor) {
656        messageElement.removeClass(elementCssColor[c]);
657    }
658    if (typeof elementCssColor[typeTxt] !== 'undefined') {
659        messageElement.addClass(elementCssColor[typeTxt]);
660    }
661    messageElement.html(i18nTranslate(messageTxt));
662};
663
664AuctionClient.prototype.successMessage = function (lotId, auctionId, messageTxt) {
665    this._displayMessage('success', lotId, auctionId, messageTxt);
666};
667
668AuctionClient.prototype.errorMessage = function (lotId, auctionId, messageTxt) {
669    this._displayMessage('error', lotId, auctionId, messageTxt);
670};
671
672AuctionClient.prototype.removeMessage = function (lotId, auctionId) {
673    var elementSelector = '#msg_' + lotId + '_' + auctionId;
674    if (lotId === null && auctionId === null) {
675        elementSelector = '.ack_bid_msg';
676    }
677    var messageElement = $(elementSelector);
678    messageElement.html('');
679    
680    var reserveNMElementSelecter = $('#rnm_' + lotId + '_' + auctionId);
681    reserveNMElementSelecter.html('');
682};
683
684AuctionClient.prototype.isLiveClient = function () {
685    var client = false;
686    if (typeof this.clientData.livePanel !== 'undefined' && this.clientData.livePanel) {
687        client = true;
688    }
689    return client;
690};
691
692AuctionClient.prototype.isEventClerk = function () {
693    var client = false;
694    if (typeof this.isClerk !== 'undefined' && this.isClerk) {
695        client = true;
696    }
697    return client;
698};
699
700AuctionClient.prototype.isNonLiveClient = function () {
701    var client = false;
702    if (typeof this.clientData.livePanel === 'undefined' || !this.clientData.livePanel) {
703        client = true;
704    }
705    return client;
706};
707
708AuctionClient.prototype.prefixMessageTxt = function (messageTxt, cacheMessage, preText) {
709    if (typeof cacheMessage === 'undefined') {
710        cacheMessage = false;
711    }
712    if (typeof preText === 'undefined') {
713        preText = '> ';
714    }
715    var messageString = preText + messageTxt;
716    if (cacheMessage) {
717        this.storeConsoleMessage(messageString);
718        this.cacheLastClientMessageDateTime(this.messageDateTimeFormat());
719    }
720    return messageString;
721};
722
723AuctionClient.prototype.attachMessageToDom = function (content) {
724    this.consoleContent.prepend(content);
725    this.consoleContent.scrollTop(0);
726};
727
728AuctionClient.prototype.getMessageWrapper = function (htmlTag) {
729    if (typeof htmlTag === 'undefined') {
730        htmlTag = 'span';
731    }
732    return $('<' + htmlTag + '/>');
733};
734
735AuctionClient.prototype.isRestrictedActivityAuction = function (auctionID) {
736    var isRestrictedActivity = null;
737    if (typeof this.clientData.isRestrictedActivity !== 'undefined' && this.clientData.isRestrictedActivity) {
738        if (typeof auctionID !== 'undefined') {
739            if (typeof this.clientData.isRestrictedActivity[auctionID] !== 'undefined') {
740                isRestrictedActivity = this.clientData.isRestrictedActivity[auctionID];
741            }
742        }
743    }
744    return isRestrictedActivity;
745};
746
747AuctionClient.prototype.isRestrictedActivityMessage = function (message, isRestrictedActivityAuction) {
748    var isRestricted = null;
749    if (isRestrictedActivityAuction) {
750        isRestricted = true;
751        switch (message.data.action) {
752            case 'loginReply':
753            case 'lotItemStarted':
754            case 'auctionSnapshot':
755            case 'lotItemSkipped':
756            case 'clientBidRejected':
757            case 'clientBidAck':
758                isRestricted = false;   // allow all as these don't have any "sensative" info
759                break;
760            case 'lotItemSold':
761                // not restricted but need to filter some values from the messages manually
762                isRestricted = false;
763                break;
764            case 'auctionLotSnapshot':
765                if (typeof message.data.reason !== 'undefined') {
766                    switch (message.data.reason) {
767                        case this.LotSnapshotReason.LOT_RE_OPENED:
768                            isRestricted = false;
769                            break;
770                    }
771                }
772                break;
773        }
774    }
775    return isRestricted;
776};
777
778AuctionClient.prototype.publishMessage = function (message, cacheMessage) {
779    if (typeof cacheMessage === 'undefined') {
780        cacheMessage = true;
781    }
782    // Clear the five second interval after below action only
783    var stopFiveSecondsTimerInstanceActionArr = [
784                                                    'lotItemSold', 
785                                                    'lotItemSkipped', 
786                                                    'onlineBidAccepted', 
787                                                    'floorBidAccepted', 
788                                                    'lotMessageFromAdmin', 
789                                                    'lotIncrementChanged', 
790                                                ];
791    if($.inArray(message.data.action, stopFiveSecondsTimerInstanceActionArr) !== -1) {
792        clearInterval(this.fiveSecondsTimerInstance);
793    }
794
795    var startingSoonAuctionClass = "starting-soon";
796    
797    var isRestrictedActivityAuction = (typeof message.data.auctionID !== 'undefined' ? this.isRestrictedActivityAuction(message.data.auctionID) : false);
798    
799    if (isRestrictedActivityAuction) {
800        if (this.isRestrictedActivityMessage(message, isRestrictedActivityAuction)) {
801            return; // if the message is completely restricted then just bail and do nothing, else we'll fall through and "filter" the messages based on isRestrictedActivityAuction var
802        }
803    }
804    
805    switch (message.data.action) {
806        case "lotItemStarted":
807            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt("<hr>", cacheMessage, "")));
808            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt("<span class=\"impt\">" + i18nTranslate("Lot $1 started", message.data.lotNumber) + "</span> (" + message.data.lotName + ")", cacheMessage)));
809            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt("<hr>", cacheMessage, "")));
810            if (this.isLiveClient()) {
811                this.playSound('startLot');
812            }
813            break;
814        case "auctionSnapshot":
815            if (this.isLiveClient()) {
816                if (typeof message.data.auctionState !== 'undefined') {
817                    switch (message.data.auctionState) {
818                        case 1:
819                        case 2:
820                            if(typeof this.clientData.isBiddingStarted !== 'undefined' && !this.clientData.isBiddingStarted) {
821                                var storedMessage = this.getStoredMessage();
822                                // check if any message availble in local storage
823                                // If availble then we don't want to show auction starting soon message
824                                if(storedMessage.length === 0) {
825                                    this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED + ' ' + startingSoonAuctionClass).html(this.prefixMessageTxt(i18nTranslate("Auction starting soon"), cacheMessage)));
826                                }
827                            }
828                            break;
829
830                        case 3:
831                            this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(i18nTranslate("AUCTION IS PAUSED. WE WILL RESUME SHORTLY"), cacheMessage)));
832                            break;
833                            
834                        case 4:
835                            this.attachMessageToDom(this.getMessageWrapper().addClass("impt").html(this.prefixMessageTxt(i18nTranslate("Auction Ended. Thank you for bidding!"), cacheMessage)));
836                            break;
837                    }
838                }
839            }
840            break;
841        case "auctionLotSnapshot":
842            if (typeof message.data.reason !== 'undefined') {
843                switch (message.data.reason) {
844                    case this.LotSnapshotReason.LOT_BID_RETRACTED:
845                        if (parseInt(message.data.lotState) === 1) { //Only show bid retracted message to the message console for the active lot
846                            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt("===== " + i18nTranslate('Bid retracted') + "=====", cacheMessage)));
847                            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate("Current Price - $1 Asking Price - $2", formatMoney(message.data.currentBid, this.currency[message.data.auctionID].symbol), formatMoney(message.data.nextBid, this.currency[message.data.auctionID].symbol)), cacheMessage)));
848                        }
849                        break;
850                    case this.LotSnapshotReason.LOT_INCREMENT_CHANGED:
851                        this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate("Increment changed $1 and New asking Price - $2", formatMoney(message.data.increment, this.currency[message.data.auctionID].symbol), formatMoney(message.data.nextBid, this.currency[message.data.auctionID].symbol)), cacheMessage)));
852                        break;
853                    case this.LotSnapshotReason.LOT_MANUAL_NEXT_BID_APPLIED:
854                        this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate("New asking Price - $1", formatMoney(message.data.nextBid, this.currency[message.data.auctionID].symbol)), cacheMessage)));
855                        break;
856                    case this.LotSnapshotReason.LOT_RE_OPENED:
857                        this.attachMessageToDom(this.getMessageWrapper().addClass("impt deep").html(this.prefixMessageTxt(i18nTranslate("Lot $1 Re-Opened", message.data.lotNumber), cacheMessage)));
858                        break;
859                }
860            }
861            if (this.isLiveClient()) {
862                if (typeof message.data.lotState !== 'undefined' && message.data.lotState === 1) {
863                    if (message.data.numberOfBids === 0) {
864                        if (!isRestrictedActivityAuction) {
865                            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate("Asking Price - $1", formatMoney(message.data.nextBid, this.currency[message.data.auctionID].symbol)))));
866                        }
867                    }
868                }
869            }
870            break;
871        case "lotItemSold":
872        case "lotItemResold":
873            
874            var isResold = message.data.action === "lotItemResold";
875            if (isResold) {
876                if (!this.isEventClerk() && !this.isAuctioneerScreen()) {
877                    break; // we only want auctioneer screen and clerk to see this message, we will ignore lotItemResold for all user-facing messages
878                }
879            }
880            
881            var soldTo = message.data.soldToUserName;
882            var registeredBidderID = soldTo;
883            if (typeof message.data.registeredBidderID !== 'undefined') {
884                registeredBidderID = message.data.registeredBidderID;
885            }
886            var floorBidderNumber = null;
887            if (typeof message.data.floorBidderNumber !== 'undefined' || message.data.floorBidderNumber !== null) {
888                floorBidderNumber = message.data.floorBidderNumber;
889            }
890            var messageContent = {i18nMsg: "Lot $1", args: [message.data.lotNumber]};
891            if (isRestrictedActivityAuction) {
892                messageContent.i18nMsg += " Closed";
893            } else {
894                var BidderNumber = (parseInt(soldTo) > 0 ? registeredBidderID : (floorBidderNumber ? floorBidderNumber : ""));
895                var isFloorBid = parseInt(soldTo) > 0 ? false : true;
896                messageContent.args.push(this.getBidderTxt(message.data.siteID, BidderNumber, isFloorBid));
897                messageContent.args.push(formatMoney(message.data.sellPrice, this.currency[message.data.auctionID].symbol));
898                messageContent.i18nMsg += " sold to $2 at $3";
899            }
900            this.attachMessageToDom(this.getMessageWrapper().addClass("impt").html(this.prefixMessageTxt(i18nTranslate(message
900Content), cacheMessage)));
901            if (this.isLiveClient()) {
902                if (parseInt(message.data.soldToUserName) === parseInt(this.clientData.userID)) {
903                    this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_GREEN).html(this.prefixMessageTxt(i18nTranslate("Congratulations! You are the winner!"))));
904                    this.playSound('winLot');
905                } else {
906                    this.playSound('notWonLot');
907                }
908            }
909            break;
910        case "lotItemSkipped":
911            if (parseInt(message.data.lotState) > 0) {
912                var messageContent = {i18nMsg: "Lot $1", args: [message.data.lotNumber]};
913                if (isRestrictedActivityAuction) {
914                    messageContent.i18nMsg += " Closed";
915                } else {
916                    messageContent.i18nMsg += " Passed";
917                }
918                if (typeof message.data.makeUnsold === 'undefined' || message.data.makeUnsold) this.attachMessageToDom(this.getMessageWrapper().addClass("impt").html(this.prefixMessageTxt(i18nTranslate(messageContent), cacheMessage)));
919            }
920            if (this.isLiveClient()) {
921                this.playSound('passLot');
922            }
923            break;
924        case "clientBidRejected":
925            if (this.isLiveClient()) {
926                this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(i18nTranslate("$1 YOUR BID HAS BEEN REJECTED", formatMoney(message.data.nextBid, this.currency[message.data.auctionID].symbol)) + " [" + i18nTranslate(message.data.errorMsgi18n || message.data.errorMsg) + "]")));
927            }
928            break;
929        case "onlineBidAccepted":
930        case "floorBidAccepted":
931            var BidderTxt = '';
932            var BidderNumber = '';
933            switch (message.data.action) {
934                case "floorBidAccepted":
935                    BidderTxt = this.getBidderTxt(message.data.siteID, '', true);
936                    // BidderTypeName = 'Competing';
937                    break;
938                case "onlineBidAccepted":
939                    BidderNumber = (typeof message.data.registeredBidderID !== 'undefined' ? message.data.registeredBidderID : message.data.userID);
940                    
941                    BidderTxt = this.getBidderTxt(message.data.siteID, BidderNumber);
942                    
943                    if (this.isLiveClient()) {
944                        this.playSound('bidAccepted');
945                    }
946                    break;
947            }
948            // this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(formatMoney(message.data.bid, this.currency[message.data.auctionID].symbol) + " - by " + BidderTypeName + " Bidder" + BidderNumber, cacheMessage)));
949            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate("$1 - by $2" + (typeof message.data.isCompetingOutbid !== 'undefined' && message.data.isCompetingOutbid ? ' (has Competing Bid)' : ''), formatMoney(message.data.bid, this.currency[message.data.auctionID].symbol), BidderTxt), cacheMessage)));
950            if (this.isLiveClient()) {
951                var userTotalBid = $('#utb');
952                if (parseInt(userTotalBid.val()) > 0) {
953                    if (parseInt(message.data.highestBidder) !== parseInt(this.clientData.userID)) {
954                        if (parseInt(message.data.previousMaxBidder) === parseInt(this.clientData.userID)) {
955                            var absenteeBidAmount = parseInt($('#user_ab_amount').val().trim());
956                            if (absenteeBidAmount < parseInt(message.data.nextBid)) {
957                                this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(i18nTranslate("YOU HAVE BEEN OUTBID. Please bid again."))));
958                                this.playSound('outBid');
959                            } 
960                        }
961                    }
962                    if (parseInt(message.data.userID) === parseInt(this.clientData.userID)) {
963                        this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_GREEN).html(this.prefixMessageTxt(i18nTranslate("Your $1 bid accepted", formatMoney(message.data.bid, this.currency[message.data.auctionID].symbol)))));
964                    }
965                }
966            }
967            break;
968        case "clientBidAck":
969            if (this.isLiveClient()) {
970                var user_last_bid_amount = $("#le_event_item_next_bid");
971                this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_GREEN).html(this.prefixMessageTxt(i18nTranslate("$1 bid submitted", formatMoney(user_last_bid_amount.val(), this.currency[message.data.auctionID].symbol)))));
972                this.playSound('biddingLot');
973            }
974            break;
975        case "lotMessageFromAdmin":
976            switch (message.data.messageType) {
977                case this.messageType.GENERALMESSAGE:
978                    // currently general message doesn't support i18n translations
979                    // clerk needs to send multiple messages in multiple languages
980                    // as "hack" for now we will attempt to translate the message from the clerk 
981                    // and if its in our dictionary then it will translate
982                    this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate(message.data.messageText), cacheMessage)));
983                    break;
984                case this.messageType.FAIRWARNING:
985                    //this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(message.data.messageText, cacheMessage)));
986                    if (this.isLiveClient()) {
987                        this.playSound('fairWarning');
988                    }
989                    var i = 2;
990                    var countDownMessageTxt = i18nTranslate(message.data.messageText);
991                    countDownMessageTxt += " - " + i18nTranslate("Lot is about to close!");
992                    this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(countDownMessageTxt, cacheMessage)));
993                    break;
994                case this.messageType.FIVESECONDWARNING:
995                    var i = 4;
996                    var $thisClient = this;
997                    var fswMessage = message.data.messageText;
998                    var fswMessagei18n = message.data.i18nMessageText;
999                    var publishFSW = function (count) {
1000                        var content = $thisClient.getMessageWrapper();
1001                        var countMsg = null;
1002                        // i18n method, we don't embed the html and only send the msg with $1 replacement var
1003                        // only support object style i18n messages, else fallback
1004                        if (typeof fswMessagei18n !== 'undefined' && fswMessagei18n && typeof fswMessagei18n.i18nMsg !== 'undefined') {
1005                            fswMessagei18n.args = ['<span class="impt">' + count + '</span>'];
1006                            countMsg = i18nTranslate(fswMessagei18n);
1007                        } else { // lagacy method just in case
1008                            countMsg = fswMessage.replace(/[0-9]+/, count);
1009                        }
1010                        content.html($thisClient.prefixMessageTxt(countMsg, cacheMessage));
1011                        $thisClient.attachMessageToDom(content);
1012                    }
1013                    publishFSW(i + 1);
1014                    this.fiveSecondsTimerInstance = setInterval(function () {
1015                        publishFSW(i)
1016                        i--;
1017                        if (i === 0) {
1018                            clearInterval(this.fiveSecondsTimerInstance);
1019                        }
1020                    }.bind(this), 1000);
1021                    break;
1022            }
1023            break;
1024        case "lotAdminActionRejected":
1025            this.attachMessageToDom(this.getMessageWrapper().addClass(CSS_RED).html(this.prefixMessageTxt(message.data.errorMsg)));
1026            break;
1027        case "lotIncrementChanged":
1028            var messageTxt = {i18nMsg: "Increment changed $1", args: [formatMoney(message.data.increment, this.currency[message.data.auctionID].symbol)]};
1029            var askingBid = 0;
1030            if (typeof message.data.currentBid !== 'undefined') {
1031                askingBid = message.data.currentBid;
1032            }
1033            if (typeof message.data.nextBid !== 'undefined') {
1034                askingBid = message.data.nextBid;
1035            }
1036            
1037            if (askingBid > 0) {
1038                messageTxt.i18nMsg += " and New asking Price - $2";
1039                messageTxt.args.push(formatMoney(askingBid, this.currency[message.data.auctionID].symbol));
1040            }
1041            this.attachMessageToDom(this.getMessageWrapper().html(this.prefixMessageTxt(i18nTranslate(messageTxt), cacheMessage)));
1042            break;
1043    }
1044};
1045
1046AuctionClient.prototype.setVolume = function (volume) {
1047    this.currentVolume = volume;
1048    for (var soundIndex in this.sound) {
1049        if (this.sound[soundIndex] instanceof Audio) {
1050            this.sound[soundIndex].volume = volume;
1051        }
1052    }
1053};
1054
1055AuctionClient.prototype.muteAudio = function (mute) {
1056    if (mute === true) {
1057        this.setVolume(0);
1058    }
1059    if (mute === false) {
1060        this.setVolume(DEFAULT_AUDIO_VOLUME);
1061    }
1062};
1063
1064AuctionClient.prototype.onPlaySoundSuccess = function () {
1065    // do nothing, will be handled by child class override
1066    // should update UI to show sound is enabled/unmuted
1067};
1068
1069AuctionClient.prototype.onPlaySoundFailure = function () {
1070    // do nothing, will be handled by child class override
1071    // should update UI to show sound is disabled/muted
1072};
1073
1074AuctionClient.prototype.playSound = function (soundIndex) {
1075    if (typeof soundIndex !== 'undefined' && typeof this.sound[soundIndex] !== 'undefined') {
1076        if (!(this.sound[soundIndex] instanceof Audio)) {
1077            this.sound[soundIndex] = new Audio(this.soundFiles[soundIndex]);
1078            if (typeof this.currentVolume !== 'undefined') this.setVolume(this.currentVolume);  // need to make sure volume is set to current state (fixes case were you mute or change volue before we load that sound file)
1079        }
1080        var p = this.sound[soundIndex].play();
1081        // Promise not supported in IE
1082        try {
1083            if (p instanceof Promise) {
1084                p.catch(function (err) {
1085                    // ignore error, need to wait for mediaPlaybackRequiresUserGesture promise is fulfilled for playback
1086                });
1087            }
1088        }
1089        catch(err) {
1090            // ignore the error if promise not supported in any browser
1091        }
1092        return p;
1093    }
1094};
1095
1096AuctionClient.prototype.hasReserveMet = function (message, userLastBidAmount) {
1097    //this.appendConsoleContent('hasReserveMet > userLastBidAmount > before: ' + userLastBidAmount);
1098    if (typeof userLastBidAmount === 'undefined' || userLastBidAmount === null) {
1099        userLastBidAmount = 0;
1100    }
1101    //this.appendConsoleContent('hasReserveMet > userLastBidAmount > after: ' + userLastBidAmount);
1102    var currentLotEL = '.el_' + message.data.auctionID;
1103    var disable_reserve_price = $(currentLotEL+' #disable_reserve_price').val();
1104    var isReserverMet = true;
1105    if(!disable_reserve_price){
1106        if (typeof message.data.isReservePriceMet !== 'undefined') {
1107            //this.appendConsoleContent('hasReserveMet > has: message.data.isReservePriceMet');
1108            //this.appendConsoleContent(message.data.isReservePriceMet);
1109            isReserverMet = message.data.isReservePriceMet;
1110        }
1111        
1112        if (!isReserverMet && userLastBidAmount > 0) {
1113            //this.appendConsoleContent('hasReserveMet > !isReserverMet && userLastBidAmount > 0');
1114            isReserverMet = false;
1115        }
1116        if (message.data.numberOfBids === 0 ) isReserveMet = false;
1117    }
1118    
1119    return isReserverMet;
1120};
1121
1122AuctionClient.prototype.onClientBid = function (params, callback) {
1123    //this.appendConsoleContent('Inside onClientBid()');
1124    //this.appendConsoleContent('onClientBid > params: ' + JSON.stringify(params));
1125    var auctionId = (typeof params.auctionId !== 'undefined' ? params.auctionId : 0);
1126    var lotId = (typeof params.lotId !== 'undefined' ? params.lotId : 0);
1127    var amount = (typeof params.amount !== 'undefined' ? params.amount : 0);
1128    var clientBidID = (typeof params.clientBidID !== 'undefined' ? params.clientBidID : "");
1129    var messageOption = {
1130        action: "clientBid",
1131        auctionID: parseInt(auctionId),
1132        lotID: parseInt(lotId),
1133        price: parseFloat(amount),
1134        clientBidID: clientBidID
1135    };
1136    //this.appendConsoleContent('onClientBid > messageOption: ' + JSON.stringify(messageOption));
1137    this.sendMessage(messageOption, function () {
1138        if (typeof callback === 'function') {
1139            //this.appendConsoleContent('callback found');
1140            callback();
1141            //this.appendConsoleContent('callback called');
1142        }
1143    }.bind(this));
1144};
1145
1146AuctionClient.prototype.onModifyBid = function (params, callback) {
1147    //this.appendConsoleContent('Inside onModifyBid()');
1148    //this.appendConsoleContent('onModifyBid > params: ' + JSON.stringify(params));
1149    var auctionId = (typeof params.auctionId !== 'undefined' ? params.auctionId : 0);
1150    var lotId = (typeof params.lotId !== 'undefined' ? params.lotId : 0);
1151    var userId = (typeof params.userID !== 'undefined' ? params.userID : 0);
1152    var amount = (typeof params.amount !== 'undefined' ? params.amount : 0);
1153    var bidReferenceId = (typeof params.bidReferenceId !== 'undefined' ? params.bidReferenceId : "");
1154    var messageOption = {
1155        action: "modifyBid",
1156        auctionID: parseInt(auctionId),
1157        lotID: parseInt(lotId),
1158        userID: parseInt(userId),
1159        newMaxBid: parseFloat(amount),
1160        bidReferenceID: bidReferenceId
1161    };
1162    if (typeof params.registeredBidderID !== 'undefined') {
1163        messageOption = $.extend({}, messageOption, {registeredBidderID: params.registeredBidderID});
1164    }
1165    //this.appendConsoleContent('onModifyBid > messageOption: ' + JSON.stringify(messageOption));
1166    this.sendMessage(messageOption, function () {
1167        if (typeof callback === 'function') {
1168            callback();
1169        }
1170    }.bind(this));
1171};
1172
1173AuctionClient.prototype.storeConsoleMessage = function (messageTxt) {
1174    //this.appendConsoleContent('Inside storeConsoleMessage()');
1175    var auctionId = this.auctionIDs[0];
1176    var localStorageId = this.localStorageId ? this.localStorageId : 'console.msg.' + auctionId;
1177    try {
1178        if (typeof (Storage) !== "undefined") {
1179            if (!localStorage.getItem(localStorageId)) {
1180                localStorage.setItem(localStorageId, JSON.stringify([]));
1181            }
1182
1183            var consoleMessage = JSON.parse(localStorage.getItem(localStorageId));
1184            if (consoleMessage) {
1185                if (consoleMessage.length > 50) {
1186                    consoleMessage.shift();
1187                }
1188                consoleMessage.push(messageTxt);
1189                localStorage.setItem(localStorageId, JSON.stringify(consoleMessage));
1190            }
1191        }
1192    } catch (e) {
1193        this.appendConsoleContent(e);
1194    }
1195};
1196
1197AuctionClient.prototype.getStoredMessage = function () {
1198    var storedMessage = [];
1199    var auctionId = this.auctionIDs[0];
1200    var localStorageId = this.localStorageId ? this.localStorageId : 'console.msg.' + auctionId;
1201    try {
1202        if (typeof (Storage) !== "undefined") {
1203            if (localStorage.getItem(localStorageId)) {
1204                storedMessage = JSON.parse(localStorage.getItem(localStorageId));
1205            }
1206        }
1207    } catch (e) {
1208        this.appendConsoleContent(e);
1209    }
1210    return storedMessage;
1211};
1212
1213AuctionClient.prototype.publishStoredMessage = function () {
1214    var storedMessage = this.getStoredMessage();
1215    if (storedMessage) {
1216        for (var stMsg in storedMessage) {
1217            this.attachMessageToDom(this.getMessageWrapper().html(storedMessage[stMsg]));
1218        }
1219    }
1220};
1221
1222AuctionClient.prototype.hasStoredMessage = function () {
1223    var storedMessage = this.getStoredMessage();
1224    if (storedMessage && storedMessage.length > 0) {
1225        return true;
1226    }
1227    return false;
1228};
1229
1230AuctionClient.prototype.cacheLastClientMessageDateTime = function (consoleMessageDateTime) {
1231    var auctionId = this.auctionIDs[0];
1232    var localStorageId = this.localStorageDatatimeId ? this.localStorageDatatimeId : 'console.msg.dateTime.' + auctionId;
1233    try {
1234        if (typeof (Storage) !== "undefined") {
1235            if (!localStorage.getItem(localStorageId)) {
1236                localStorage.setItem(localStorageId, "");
1237            }
1238            localStorage.setItem(localStorageId, consoleMessageDateTime);
1239        }
1240    } catch (e) {
1241        this.appendConsoleContent(e);
1242    }
1243};
1244
1245AuctionClient.prototype.getLastClientMessageDateTime = function () {
1246    var auctionId = this.auctionIDs[0];
1247    var consoleMessageDateTime = "";
1248    var localStorageId = this.localStorageDatatimeId ? this.localStorageDatatimeId : 'console.msg.dateTime.' + auctionId;
1249    try {
1250        if (typeof (Storage) !== "undefined") {
1251            if (localStorage.getItem(localStorageId)) {
1252                consoleMessageDateTime = localStorage.getItem(localStorageId);
1253            }
1254        }
1255    } catch (e) {
1256        this.appendConsoleContent(e);
1257    }
1258    return consoleMessageDateTime;
1259};
1260
1261AuctionClient.prototype.messageDateTimeFormat = function () {
1262    var whenConnect = new Date();
1263    var whenConnectTxt = "";
1264    var whenConnectHours = padInt(whenConnect.getHours());
1265    var whenConnectMinutes = padInt(whenConnect.getMinutes());
1266    var whenConnectDate = padInt(whenConnect.getDate());
1267    var whenConnectMonth = padInt(whenConnect.getMonth());
1268    var whenConnectYear = padInt(whenConnect.getFullYear());
1269    if (whenConnectYear.length > 2) {
1270        whenConnectYear = whenConnectYear.slice(-2);
1271    }
1272    var whenConnectAmPm = "am";
1273    if (whenConnectHours > 12) {
1274        whenConnectHours = padInt((parseInt(whenConnectHours) - 12));
1275        whenConnectAmPm = "pm";
1276    }
1277    whenConnectTxt += whenConnectHours + ":" + whenConnectMinutes + whenConnectAmPm;
1278    whenConnectTxt += " " + padInt(parseInt(whenConnectMonth) + 1) + "/" + whenConnectDate + "/" + whenConnectYear;
1279    //console.log(whenConnectTxt);
1280    return whenConnectTxt;
1281};
1282
1283AuctionClient.prototype.publishInitialMessage = function () {
1284    if (this.hasStoredMessage()) {
1285        var lastClientMessageTxt = "last client msg at $1";
1286        this.attachMessageToDom(this.getMessageWrapper().html("== " + i18nTranslate(lastClientMessageTxt, this.getLastClientMessageDateTime()) + " =="));
1287    }
1288    var whenConnectTxt = "";
1289    if (this.hasStoredMessage()) {
1290        whenConnectTxt += "re-";
1291    }
1292    whenConnectTxt += "connected to "+this.siteName+" live center at $1";
1293    this.attachMessageToDom(this.getMessageWrapper().html("== " + i18nTranslate(whenConnectTxt, this.messageDateTimeFormat()) + " =="));
1294};
1295
1296AuctionClient.prototype.getRemainingBidBlance = function (auctionId) {
1297    var jsonData;
1298    var ajaxItemsUrl = getUrl('item/bidlimit/' + auctionId + '?is_ajax=1');
1299    $.ajax({
1300        type: 'GET',
1301        url: ajaxItemsUrl,
1302        async: false,
1303        success: function (data, textStatus, jqXHR) {
1304            jsonData = data;
1305        }
1306    });
1307    return jsonData;
1308};
1309
1310AuctionClient.prototype.checkBidLimitExceeded = function (amount, auctionId, lotId, action, clientBidFromWidget) {
1311    var error = false;
1312    
1313    var hasWidgetBid = false;
1314    if (this.isWidget)
1315    {
1316        if (typeof clientBidFromWidget !== 'undefined' && clientBidFromWidget !== null)
1317        {
1318            hasWidgetBid = true;
1319        }
1320    }
1321
1322    var bidlimitData = this.getRemainingBidBlance(auctionId);
1323    if (parseFloat(bidlimitData.totalBidlimit) > 0) {
1324        var totalConsumed = bidlimitData.totalConsumed;
1325        if (action === 'mb') {
1326            if (!hasWidgetBid)
1327            {
1328                var userLastBidAmountSelector = '#ulba_' +  lotId + '_' + auctionId;
1329                if (this.isLiveClient()) {
1330                    userLastBidAmountSelector = '#user_last_bid_amount';
1331                }
1332                var userLastBidAmount = $(userLastBidAmountSelector);
1333
1334                var lastBid = 0;
1335                if (typeof userLastBidAmount.data('bidamt') !== 'undefined') {
1336                    lastBid = userLastBidAmount.data('bidamt');
1337                } else {
1338                    lastBid = userLastBidAmount.val();
1339                }
1340            } else
1341            {
1342                lastBid = clientBidFromWidget.userLastBidAmount;
1343            }
1344            
1345            totalConsumed = parseFloat(totalConsumed) - parseFloat(lastBid);
1346            if (parseFloat(totalConsumed) < 0) totalConsumed = 0;
1347        }
1348        if (parseFloat(bidlimitData.totalBidlimit) < (parseFloat(totalConsumed) + parseFloat(amount))) {
1349            error = true;
1350        }
1351    }
1352    return error;
1353}
1354
1355AuctionClient.prototype.sanitizeCurrencyAndSeparator = function (amount, removeDecimal/* = true */) {
1356    var trippedAmount = null;
1357    if (amount) {
1358        if (typeof amount === 'string') {
1359            amount = (amount.trim()).replace(/[$,]+/g, "");
1360        }
1361        trippedAmount = amount;
1362    }
1363
1364    // Since IE does not support default parameter value
1365    removeDecimal = (typeof removeDecimal !== 'undefined') ? removeDecimal : true;
1366    if (removeDecimal) {
1367        // Math.trunc() is not available in IE, therefore use Math.floor() instead
1368        // Preferred to use trunc(), because sometimes floor() rounding up the number
1369        if (typeof Math.trunc !== 'undefined') {
1370            trippedAmount = Math.trunc(trippedAmount);
1371        } else {
1372            trippedAmount = Math.floor(trippedAmount);
1373        }
1374    }
1375    
1376    return trippedAmount;
1377};
1378
1379AuctionClient.prototype.setCriteoTrackTransactionIndex = function () {
1380    var criteoTrackTransactionIndex = getCriteoTrackTransactionIndex();
1381    if (criteoTrackTransactionIndex > 0) {
1382        this.criteoTrackTransactionIndex = parseInt(criteoTrackTransactionIndex);
1383    }
1384    //this.appendConsoleContent('setCriteoTrackTransactionIndex > criteoTrackTransactionIndex: ' + this.criteoTrackTransactionIndex);
1385};
1386
1387AuctionClient.prototype.addCriteoTransaction = function (lotId, soldPrice, transactionId) {
1388    if (typeof this.criteoTrackTransactionIndex !== 'undefined' /*&& this.criteoTrackTransactionIndex > 0*/) {
1389        window.criteo_q = addTransactionToCriteoEvent(this.criteoTrackTransactionIndex, lotId, soldPrice, transactionId);
1390        //this.appendConsoleContent('addCriteoTransaction > window.criteo_q: ' + JSON.stringify(window.criteo_q));
1391    }
1392};
1393
1394AuctionClient.prototype.adjustBidAmountUI = function (el,bidText,limit) {
1395    if (typeof limit === 'undefined') {
1396        limit = 13;
1397    }
1398    if(el && bidText) {
1399        var bidLenght = bidText.toString().length;
1400        el.removeClass('dyn-bid-price');
1401        if(bidLenght >= limit) {
1402            el.addClass('dyn-bid-price');
1403        }
1404    }
1405};
1406
1407AuctionClient.prototype.attachReconnectOverlayNotification = function () {
1408    var $overlay = $('body').find('.connect-overlay');
1409    var reConnectMessage = i18nTranslate("Not connected. Trying to reconnect...");
1410    if ($overlay.length <= 0) {
1411        $overlay = $("<div class=\"connect-overlay\">" + reConnectMessage + "</div>");
1412        $('body').append($overlay);
1413
1414        // $overlay.css('width', '200px');
1415        $overlay.css('height', '18px');
1416        $overlay.css('background', '#000000');
1417        $overlay.css('position', 'fixed');
1418        $overlay.css('z-index', '9999');
1419        $overlay.css('right', '10px');
1420        $overlay.css('bottom', '10px');
1421        $overlay.css('text-align', 'center');
1422        $overlay.css('line-height', '1.5');
1423        //$overlay.css('box-shadow', '5px 5px 8px 1px rgba(4, 4, 4, 0.31)');
1424        $overlay.css('font-size', '12px');
1425        $overlay.css('border-radius', '10px');
1426        $overlay.css('font-family', 'klavika-light');
1427        $overlay.css('opacity', '0.5');
1428        $overlay.css('color', '#ffffff');
1429        $overlay.css('padding', '0px 5px');
1430    } else {
1431        $overlay.off('click.needsRefresh').removeClass('needs-refresh').text(reConnectMessage);
1432    }
1433};
1434
1435AuctionClient.prototype.detachReconnectOverlayNotification = function () {
1436    var $overlay = $('body').find('.connect-overlay');
1437    // if (typeof $overlay !== 'undefined') $overlay.remove();
1438    if (typeof $overlay !== 'undefined') {
1439        if (this.clientData.pageRefreshWarning) {
1440            $overlay.addClass('needs-refresh')
1441                .text(i18nTranslate("Connection was lost, some lots may be outdated. Click to reload"))
1442                .off('click.needsRefresh').on('click.needsRefresh', function () {
1443                    if (setting.isMobileWebView) {
1444                        window.location.href = window.location.href.split('#')[0];
1445                        window.location.relaod();
1446                    } else {
1447                        window.location.reload();
1448                    }
1449                });
1450        } else {
1451            $overlay.remove();
1452        }
1453    }
1454};
1455
1456AuctionClient.prototype.reconnectOverlayNotification = function (action) {
1457    clearTimeout(overlayNotificationTimeout);
1458    if (typeof action === 'undefined') action = "on";
1459    switch (action) {
1460        case "on":
1461            var attachReconnectOverlayNotification = false;
1462            if (typeof this.clientData.livePanel !== 'undefined' && this.clientData.livePanel) {
1463                attachReconnectOverlayNotification = true;
1464            } else {
1465                if (this.clientData.pageRefreshWarning !== 'undefined' && this.clientData.pageRefreshWarning) {
1466                    attachReconnectOverlayNotification = true;
1467                }
1468            }
1469            if (attachReconnectOverlayNotification) {
1470                this.attachReconnectOverlayNotification();
1471            }
1472            break;
1473        case "off":
1474            this.detachReconnectOverlayNotification();
1475            break;
1476    }
1477};
1478
1479AuctionClient.prototype.setDualCurrencyBidAmount = function (el, bidAmount, auctionId) {
1480    if(el.length > 0) {
1481        var convertedData = this.getDualCurrencyBidAmount(bidAmount, auctionId);
1482        if(convertedData.exchange != '') el.data('exchange', convertedData.exchange);
1483        if(convertedData.convertedAmount != '') el.html(convertedData.convertedAmount);
1484    }
1485};
1486
1487AuctionClient.prototype.getDualCurrencyBidAmount = function (bidAmount, auctionId) {
1488    var result = {exchange: '', convertedAmount : ''};
1489    if(typeof this.currency[auctionId] != 'undefined')
1490    {
1491        var exchData = {'amount' : bidAmount, 'from_exch_rate' : this.currency[auctionId].exchange_rate, 'from_symbol' : this.currency[auctionId].symbol};
1492//        var userCurrencyData = {'symbol' : exchData.from_symbol, 'exchange_rate' : exchData.from_exch_rate};
1493//        if(typeof this.clientData.userCurrency != 'undefined') userCurrencyData = this.clientData.userCurrency;
1494        var userCurrencyData = this.clientData.userCurrency;
1495        var convertedBidText = convertCurrencyAmount(exchData.amount, exchData.from_exch_rate, exchData.from_symbol, userCurrencyData.exchange_rate, userCurrencyData.symbol);
1496        result.exchange = exchData;
1497        result.convertedAmount = convertedBidText;
1498    }
1499
1500    return result;
1501};
1502
1503/**
1504 * Logging to the app/log/*.log file about the connection lost and only once
1505 * @param {objuect} options 
1506 */
1507AuctionClient.prototype.logConnectionIssue = function (options) {
1508    if (!this.connection || this.connection.readyState !== 1) {
1509        /*
1510        * The variable CONNECTION_ISSUE_LOG_COUNT is a global variable
1511        * So, if in some page ( like search page ) has both item ( live / time )
1512        * then we probably end up loggin for once ( depend on which item bid place occurred first )
1513        * 
1514        * So, if the liveEvent client triggered first then it will log and make one increment
1515        * and then if timeEvent client triggered second, it will found " > 0" and will not log
1516        * 
1517        * But that should be OK, since we atleast log the connection issue at liveEvent/timeEvent client
1518        */
1519        if (typeof options !== 'undefined' && CONNECTION_ISSUE_LOG_COUNT === 0) { // Will only log in first try and not logged afterwards
1520            this.appendConsoleContent('Logging failed to connect to AE');
1521            this.logError({
1522                code: this.connectionErrorCode,
1523                auctionID: options.auctionId,
1524                lotID: options.lotId,
1525                bidAmountPlaced: options.amount,
1526                successConnectionCount: SUCCESS_CONNECT_COUNT
1527            });
1528            CONNECTION_ISSUE_LOG_COUNT ++;
1529        }
1530        return true;
1531    } else {
1532        CONNECTION_ISSUE_LOG_COUNT = 0;
1533    }
1534};
1535
1536/**
1537 * Display the countdown timer at the bid button when connection with AE is lost
1538 * This is only for non-live ( including timed items ) pages.
1539 * @param {object} el
1540 */
1541AuctionClient.prototype.startConnectionLostCountdownTimer = function (el) {
1542    var $this = this;
1543    var i = 14;
1544    var publishFSW = function (count) {
1545        el.html(i18nTranslate("Please Wait $1 sec", count));
1546    };
1547    publishFSW(i + 1);
1548    var thisBtnTextInterval = setInterval(function () {
1549        publishFSW(i);
1550        i--;
1551        if ((i === 0) || ($this.connection.readyState === 1)) {
1552            clearInterval(thisBtnTextInterval);
1553        }
1554    }, 1000);
1555};
1556
1557AuctionClient.prototype.setIsWidget = function(isWidget)
1558{
1559    this.isWidget = isWidget;
1560};
1561
1562AuctionClient.prototype.collectNextBidIfEmptyBid = function(lotId, auctionId, hasWidgetBid, clientBidFromWidget) {
1563    var amount = 0;
1564
1565    // var nextBidPrice = $('#nbp_' + lotId + '_' + auctionId).val().trim();
1566    var nextBidPrice = $('#amt_' + lotId + '_' + auctionId).data('placeholder_amount');
1567    if (!nextBidPrice) nextBidPrice = $('#nbp_' + lotId + '_' + auctionId).val().trim();
1568    if (typeof hasWidgetBid !== 'undefined' && hasWidgetBid) {
1569        if (typeof clientBidFromWidget !== 'undefined') {
1570            nextBidPrice = clientBidFromWidget.nextBidPrice.trim();
1571        }
1572    }
1573
1574    if (nextBidPrice) {
1575        var userLastBidAmount = $('#ulba_' + lotId + '_' + auctionId);
1576        if (typeof hasWidgetBid !== 'undefined' && hasWidgetBid) {
1577            if (typeof clientBidFromWidget !== 'undefined') {
1578                userLastBidAmount = clientBidFromWidget.userLastBidAmount;
1579            }
1580        }
1581
1582        var bidAmountLast = 0;
1583        if (typeof userLastBidAmount.data('bidamt') !== 'undefined') {
1584            bidAmountLast = userLastBidAmount.data('bidamt');
1585        } else {
1586            bidAmountLast = userLastBidAmount.val().trim();
1587        }
1588
1589        amount = bidAmountLast && (parseInt(bidAmountLast) > parseInt(nextBidPrice)) ? bidAmountLast : nextBidPrice;
1590    }
1591
1592    return amount;
1593};
1594
1595AuctionClient.prototype.onBiddingKeyboardAction = function() {
1596    $(document).off('keypress.bidAmount').on('keypress.bidAmount', 'input[name="bid_amount"]', function (evt) {
1597        var code = evt.keyCode ? evt.keyCode : evt.which;
1598        if (code == 13) { // if "Enter" key pressed
1599            evt.preventDefault();
1600            let $theInput = $(this);
1601            var $theItemId = $theInput.data('item-id'); 
1602            var $theEventId = $theInput.data('event-id');
1603
1604            if ($theItemId && $theEventId) {
1605                let $theAssociateBidButton = $("#btn_" + $theItemId + "_" + $theEventId);
1606                if (typeof $theAssociateBidButton !== 'undefined') {
1607                    $theInput.blur();
1608                    $theAssociateBidButton.click();
1609                }
1610            }
1611        }
1612    });
1613
1614    $(document).off('keyup.bidConfirmation').on('keyup.bidConfirmation', function (evt) {
1615        var code = evt.keyCode ? evt.keyCode : evt.which;
1616        if (code == 27) { // if "Escape" key pressed
1617            evt.preventDefault();
1618            showHidePopup('.bid_confirmation_pop_wrap',false);
1619        }
1620    });
1621};
1622
1623AuctionClient.prototype.onBidButtonKeyAction = function(eventName, buttonElement) {
1624    $(document).off(eventName).on(eventName, function (evt) {
1625        var code = evt.keyCode ? evt.keyCode : evt.which;
1626        if (code == 13 && typeof buttonElement !== 'undefined') {
1627            evt.preventDefault();
1628            buttonElement.first().click(); // click self if Enter key pressed
1629        }
1630    });
1631};
1632AuctionClient.prototype.isAuctioneerScreen = function () {
1633    var client = false;
1634    if (typeof this.clientData.auctioneerScreen !== 'undefined' && this.clientData.auctioneerScreen) {
1635        client = true;
1636    }
1637    return client;
1638};
1639AuctionClient.prototype.isFloorScreen = function () {
1640    var client = false;
1641    if (typeof this.clientData.floorScreen !== 'undefined' && this.clientData.floorScreen) {
1642        client = true;
1643    }
1644    return client;
1645};
1646
1647AuctionClient.prototype.onBidEnterBidButtonChange = function(auctionType){
1648    var $this = this;
1649    $(document).on('input', 'input:text[name=bid_amount]', function (evt) {
1650        var auctionId = $(this).data('event-id');
1651        var lotId = $(this).data('item-id');
1652        var thisButtonBidConfirm = $('#btn_'+lotId+'_'+auctionId);
1653        var currentAct = thisButtonBidConfirm.data('act');
1654
1655        if(currentAct === 'sb'){
1656
1657            var placeNextBidButtonText = '', placeMaxBidbuttonText = '';
1658            if(auctionType === 'live') 
1659            {
1660                 placeNextBidButtonText = $this.languageTranslate('placeNextBidButtonTextLive');
1661                 placeMaxBidbuttonText = $this.languageTranslate('placeMaxBidbuttonTextLive')
1662            }
1663            if(auctionType === 'timed') 
1664            {
1665                 placeNextBidButtonText = $this.languageTranslate('placeNextBidButtonTextTimed');
1666                 placeMaxBidbuttonText = $this.languageTranslate('placeMaxBidButtonTextTimed')
1667            }
1668            var btnText = placeNextBidButtonText;
1669            if($(this).val()){
1670                btnText = placeMaxBidbuttonText; 
1671            }
1672           
1673            thisButtonBidConfirm.html(btnText);
1674        }
1675
1676    })
1677};
1678AuctionClient.prototype.displayReserveMetBanner = function (lotId, auctionId, displayBanner = false){
1679    var buttonStatWrapperSelector = $('#re_' + lotId + '_' + auctionId);
1680    if (displayBanner) {
1681        buttonStatWrapperSelector.addClass('reserve-met-banner');
1682        buttonStatWrapperSelector.html(this.languageTranslate('reserveMetBannerNotification'));
1683    } else {
1684        buttonStatWrapperSelector.removeClass('reserve-met-banner');
1685        buttonStatWrapperSelector.html('');
1686    }
1687}
1688
1689AuctionClient.prototype.languageTranslate = function(languageKey, replace) {
1690    if (typeof $.i18n !== 'undefined' && 
1691            typeof $.i18n.rawTranslationMap !== 'undefined' && 
1692            typeof $.i18n.rawTranslationMap[languageKey] !== 'undefined') {
1693        return i18nTranslate($.i18n.rawTranslationMap[languageKey], replace);
1694    }
1695    return '';
1696};
1697AuctionClient.prototype.getBidSuggestionArray = function(bidText,compareWith,eventId){
1698    var suggestedValues = [];
1699    var maxSuggestions = 20;
1700    compareWith = parseInt(compareWith);
1701    compareWith = compareWith ? compareWith : 0;
1702    var biddingIncrements = this.clientData.biddingIncrements[eventId];
1703    var $this = this;
1704    if(biddingIncrements !== undefined){
1705        for(var i = 0; i<= maxSuggestions; i++){
1706            var incrementValue = 10;
1707            var startingAmount = 0;
1708            $.each(biddingIncrements,function(startAmount,increment){
1709                if(compareWith >= startAmount){
1710                    startingAmount = parseInt(startAmount);
1711                    incrementValue = parseInt(increment);
1712                }
1713            });
1714            if(compareWith.toString().toLowerCase().indexOf(bidText.toLowerCase())!==-1){
1715                suggestedValues.push({label:formatMoney(compareWith.toString(), $this.currency[eventId].symbol),value:compareWith});
1716            }
1717            compareWith = ((startingAmount) + (Math.floor((compareWith - startingAmount) / incrementValue)) * incrementValue);
1718            compareWith = compareWith + incrementValue;
1719        }
1720    }
1721    return suggestedValues;
1722}
1723AuctionClient.prototype.onBiddingAutoCompleteAction = function() {
1724    var $this = this;
1725    if(typeof jQuery.ui !== 'undefined' && this.clientData.biddingIncrements !== undefined) {
1726        $('input[name="bid_amount"]').filter(function(){
1727            return ($.inArray($(this).data('event-id'),$this.auctionIDs) !== -1);
1728        }).autocomplete({
1729            minLength:0,
1730            source: function(request,responce){
1731                var next_bid_price = this.element.data('placeholder_amount');
1732                var event_id = this.element.data('event-id');
1733                var item_id = this.element.data('item-id');
1734                var user_last_bid = $("#ulba_"+item_id+"_"+event_id).val();
1735                var user_bid_count = $("#utb_"+item_id+"_"+event_id).val();
1736                if(user_last_bid && user_bid_count > 0){
1737                    next_bid_price = Math.max(next_bid_price,user_last_bid);
1738                }
1739                responce($this.getBidSuggestionArray(request.term,next_bid_price,event_id));
1740            },
1741            select: function(event,ui){
1742                $(this).val(ui.item.value);
1743                var e = jQuery.Event("keypress");
1744                e.which = 13;
1745                $(this).trigger(e);
1746                return true;
1747            },
1748            create: function() {
1749                $(this).data('ui-autocomplete')._renderItem  = function (ul, item) {
1750                    ul.addClass('increment-dropdown');
1751                    return $("<li></li>") 
1752                        .append(item.label)
1753                        .attr("data-value",item.value)
1754                        .data("ui-autocomplete-item", item)
1755                        .appendTo(ul);
1756                };
1757            }
1758        }).focus(function() {
1759            $(this).autocomplete('search', $(this).val())
1760        })
1761    }
1762};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.