1wgsdk.showFormFieldError = (function($) { 2 var obj = function(form_id) { 3 $('input[type=password], input[type=text]', form_id).each(function(){ 4 var fieldset = $(this).parents('fieldset'); 5 if ($('.b-error-text', fieldset).length > 0){ 6 fieldset.removeClass('accept').addClass('decline'); 7 $('.b-decline', fieldset).css({'display': 'none'}); 8 } 9 }) 10 }; 11 return obj; 12})($) 13 14 15wgsdk.InputLengthValidator = (function($){ 16 var obj = function (inputSelector, params) { 17 params = params || {}; 18 var minValue = params.min; 19 var maxValue = params.max; 20 var required = params.required; 21 var requiredErrorMsg = params.requiredErrorMsg || translate('FORMS_VALIDATION_EMPTY_FIELD_ERROR'); 22 var minLengthErrorMsg = params.minLengthErrorMsg || translate('FORMS_VALIDATION_MIN_LENGTH_ERROR'); 23 var maxLengthErrorMsg = params.maxLengthErrorMsg || translate('FORMS_VALIDATION_MAX_LENGTH_ERROR'); 24 25 minValue = minValue !== undefined ? minValue : -1; 26 maxValue = maxValue !== undefined ? maxValue : $(inputSelector).attr('maxlength'); 27 28 return function(value) { 29 var length = value.length; 30 var empty = length == 0; 31 32 if (required && empty) { 33 return {'status': 'error', 34 'error': requiredErrorMsg}; 35 } 36 37 if (!empty && length < minValue) 38 return {'status': 'error', 39 'error': minLengthErrorMsg}; 40 41 if (maxValue && maxValue > 0) { 42 if (length > maxValue) 43 return {'status': 'error', 44 'error': maxLengthErrorMsg}; 45 } 46 47 return {'status': 'ok'}; 48 }; 49 } 50 return obj; 51})($) 52 53 54wgsdk.InputWatcher = (function($) { 55 56 var obj = function($selector, preprocessor, onChange, postprocessor, events) { 57 var instance = this, 58 defaultEvents = 'input.iw propertychange.iw change.iw forceCheck.iw'; 59 60 if (typeof(events) !== 'string' || events.length === 0) { 61 events = defaultEvents; 62 } 63 64 this.oldValue = ''; 65 this.$selector = $selector; 66 67 // public interfaces 68 this.getValue = function() { 69 return this.$selector.val(); 70 }; 71 this.setValue = function(value, apply) { 72 if (typeof postprocessor === 'function') { 73 value = postprocessor(value, apply, this.oldValue); 74 } 75 this.$selector.val(value); 76 if (apply) { 77 instance.oldValue = value; 78 } 79 }; 80 this.restoreValue = function() { 81 this.setValue(instance.oldValue, false); 82 }; 83 this.destroy = function() { 84 this.$selector.off('.iw'); 85 }; 86 this.processChange = function(e) { 87 var value = instance.getValue(), v; 88 89 if (preprocessor) { 90 v = preprocessor(value); 91 if (v != value) { 92 instance.setValue(v, false); 93 value = instance.getValue(); 94 } 95 } 96 if (value != instance.oldValue || e.type === 'forceCheck') { 97 if (onChange) { 98 onChange(value, instance.oldValue); 99 } 100 instance.oldValue = value; 101 } 102 }; 103 this.stopWatch = function() { 104 this.$selector.off(events); 105 }; 106 this.startWatch = function() { 107 this.$selector.on(events, this.processChange); 108 }; 109 110 this.startWatch(); 111 } 112 113 return obj; 114})($); 115 116 117wgsdk.removeError = (function($){ 118 var obj = function(selector){ 119 var fieldset = $(selector).parents('fieldset'); 120 $('.b-error', fieldset).remove(); 121 $('.b-decline, .b-accept, .b-verification', fieldset).removeAttr('style'); 122 }; 123 return obj 124})($) 125 126wgsdk.AjaxFetcher = (function($){ 127 128 var obj = function (defAjaxSettings, requestStarted, requestFinished, delay){ 129 var instance = this; 130 var curAjax; 131 var curAjaxTimer; 132 133 function onError(XMLHttpRequest, textStatus, errorThrown){ 134 requestFinished(null); 135 instance.cleanRequest(); 136 } 137 function onSuccess(data, textStatus, XMLHttpRequest){ 138 requestFinished(data); 139 instance.cleanRequest(); 140 } 141 142 this.sendRequest = function(data, instant){ 143 instance.cancelRequest(); 144 145 var settings = { 'dataType': 'json', 146 'success': onSuccess, 147 'error': onError}; 148 149 $.extend(true, settings, defAjaxSettings, {'data': data}); 150 151 function sendIt(){ 152 if(requestStarted) 153 requestStarted(settings); 154 155 curAjax = $.ajax(settings); 156 } 157 if( !instant && delay && (delay > 0)) 158 curAjaxTimer = window.setTimeout(sendIt, delay); 159 else 160 sendIt(); 161 }; 162 163 this.cancelRequest = function(){ 164 if(curAjax || curAjaxTimer) 165 onError(); // cleanRequest is called from it 166 }; 167 this.cleanRequest = function(){ 168 if(curAjaxTimer){ 169 window.clearTimeout(curAjaxTimer); 170 curAjaxTimer = null; 171 } 172 173 if(curAjax){ 174 curAjax.abort(); 175 curAjax = null; 176 } 177 }; 178 } 179 return obj; 180 181})($) 182 183wgsdk.NoAjaxFetcher = (function ($){ 184 var obj = function(getDataCallback, requestStarted, requestFinished){ 185 this.sendRequest = function(data, instant){ 186 requestFinished(getDataCallback(data)); 187 }; 188 189 this.cancelRequest = function(){ 190 requestFinished(null); 191 }; 192 } 193 return obj 194})($) 195 196 197 198 199wgsdk.forms = (function($){ 200 var obj = { 201 202 auth: function(params) { 203 var RELOGIN_FORM_URL = window.RELOGIN_FORM_URL ? window.RELOGIN_FORM_URL : "should be defined like global workspace"; 204 var submit_params = { 205 success: function() { 206 // here we have guaranties from the server, that there will be no 600 error 207 // (since relogin has successed), so we can close dialog 208 params.success(); 209 $('#js-relogin-form-wrapper').dialog('close'); 210 }, 211 iframeProxy: true 212 }; 213 var ext_params = { source: RELOGIN_FORM_URL, 214 OnReady: function(dialog) { 215 $('.js-cancel-button', dialog).click(function(){ 216 if(params.OnCancel) { 217 params.OnCancel(); 218 } 219 }); 220 } }; 221 222 wgsdk.forms.submit_from_popup(false, '#js-relogin-form', '#js-relogin-form-wrapper', submit_params, ext_params); 223 }, 224 225 auth_dialog: function() { 226 var LOGIN_FORM_URL = window.LOGIN_FORM_URL ? window.LOGIN_FORM_URL : 'should be defined in global namespace'; 227 var submit_params = { 228 success: function(data) { 229 if (data && data.redirect_to) { 230 location.href = data.redirect_to; 231 } 232 else { 233 setTimeout(function() { 234 location.reload(); 235 }, 100); 236 } 237 }, 238 error: function(data) { 239 if(data.enable_captcha){ 240 window.wotCaptcha.Enable(); 241 $('.fieldset_captcha').show(); 242 } 243 wgsdk.waiting('close'); 244 }, 245 iframeProxy: true 246 }; 247 var ext_params = { 248 source: LOGIN_FORM_URL, 249 stayOpened: true, 250 OnSubmitCallback: function() { 251 wgsdk.waiting('open'); 252 } 253 }; 254 255 wgsdk.forms.submit_from_popup(false, '#js-auth-popup-form', '#js-auth-popup-dialog', submit_params, ext_params); 256 }, 257 258 post: function(params) { 259 260 wgsdk.waiting('open'); 261 262 $.ajax({ 263 type: 'post', 264 data: params.data || {}, 265 url: params.url, 266 dataType: 'json', 267 success: function(data, status, request) { 268 if (!data) { 269 wgsdk.error(translate('FORMS_UNKNOWN_ERROR')); 270 return; 271 } 272 273 if (data.error_code == 600) { 274 wgsdk.forms.auth({ success: function() {wgsdk.forms.post(params); } }); 275 return; 276 } 277 278 if (data.status == 'redirect') { 279 if (data.redirect_url) { 280 location.href = data.redirect_url; 281 } 282 return; 283 } 284 285 if (data.error) { 286 wgsdk.error(data.error); 287 return; 288 } 289 290 if (params.success_replace) { 291 $(params.success_replace.hide, selector).hide(); 292 $(params.success_replace.show, selector).show(); 293 } 294 if (params.success_add_text) { 295 wgsdk.forms.add_text_to_element(params.success_add_text.selector, params.success_add_text.params); 296 } 297 298 if (params.success) params.success(data, status, request); 299 }, 300 error: params.error || function(request, text, errorThrown) { 301 if (wgsdk.dev != null) { 302 wgsdk.dev.ajax_default_error_handler(request, text, errorThrown); 303 } else { 304 wgsdk.error(translate('FORMS_UNKNOWN_ERROR')); 305 return; 306 } 307 }, 308 complete: function() { 309 wgsdk.waiting('close'); 310 if (params.complete) params.complete(); 311 wotUpdateDateTimeFields(); 312 } 313 }); 314 }, 315 316 hide_errors: function (form_selector) { 317 $(form_selector).removeClass('b-error-on-form'); 318 $('.b-message-error-text', form_selector).empty(); 319 320 $('.b-error-on-form-field', form_selector).removeClass('b-error-on-form-field'); 321 $('.b-error-text', form_selector).empty(); 322 }, 323 324 clear_inputs: function(form_selector) { 325 $('input[type="password"]', form_selector).val(''); 326 $('input[type="text"]', form_selector).val(''); 327 }, 328 329 get_next_iframe_number: function(){ 330 if (!wgsdk.forms.__iframe_number) { 331 wgsdk.forms.__iframe_number = 0; 332 } 333 return ++wgsdk.forms.__iframe_number; 334 }, 335 336 submit: function(selector, params) { 337 params = params || {}; 338 params.after_error = 'after_error' in params ? params.after_error : 'focus'; 339 var form = $(selector); 340 341 var MAX_PROCESSING_TIME = 10; 342 if (window.PENDING_OPERATION_JAVASCRIPT_TIMEOUT) { 343 MAX_PROCESSING_TIME = window.PENDING_OPERATION_JAVASCRIPT_TIMEOUT;
344 } 345 346 var processingStartTime = undefined; 347 348 var onFormErrorHandler = params.onFormError || wgsdk.forms.submit_onFormError; 349 var onFormError = function(error_message) { 350 onFormErrorHandler(form, error_message); 351 }; 352 353 var onFieldErrorHandler = params.onFieldError || wgsdk.forms.submit_onFieldError; 354 var onFieldError = function(element_id, error_message) { 355 onFieldErrorHandler(element_id, form, error_message); 356 }; 357 358 function set_focus(wrapper){ 359 window.setTimeout(function(e){ 360 wgsdk.set_focus(wrapper); 361 }, 1000); 362 } 363 364 var processing = false; 365 366 var OnSuccess = function(data, status, request) { 367 processing = false; 368 369 wgsdk.forms.hide_errors(form); 370 if (!data) { 371 wgsdk.error(translate('FORMS_UNKNOWN_ERROR')); 372 return; 373 } 374 375 if (data.status === 'ok') { 376 if (params.success) params.success(data, status, request); 377 378 if (params.success_replace) { 379 $(params.success_replace.hide, selector).hide(); 380 $(params.success_replace.show, selector).show(); 381 } 382 383 if (params.success_add_text) { 384 if (params.success_add_text.params.from_server) { 385 params.success_add_text.params.text = data.log_message; 386 } 387 388 wgsdk.forms.add_text_to_element(params.success_add_text.selector, 389 params.success_add_text.params); 390 } 391 392 if (data.success_url) location.href=data.success_url; 393 if (params.success_url) location.href=params.success_url; 394 395 return; 396 } 397 398 if (data.status === 'warning') { 399 if (params.warning) params.warning(data, status, request); 400 return; 401 } 402 403 if (data.status === 'processing') { 404 405 var date = new Date(); 406 if (processingStartTime === undefined) { 407 processingStartTime = date.getTime(); 408 } 409 410 if (date.getTime() - processingStartTime < MAX_PROCESSING_TIME * 1000) { 411 412 processing = true; 413 414 setTimeout(function() { 415 $.ajax({ 416 type: 'get', 417 url: data.status_url, 418 dataType: 'json', 419 success: OnSuccess, 420 error: OnError, 421 complete: OnComplete, 422 cache: false 423 }); 424 }, 1000); 425 426 return; 427 } 428 429 if ('onTimeout' in params) { 430 params.onTimeout(form); 431 } 432 433 if ('stop_url' in data && data['stop_url']) { 434 // stop processing 435 $.ajax({ type: 'post', 436 url: data.stop_url, 437 dataType: 'json' 438 }); 439 } 440 441 // form error data 442 data.status = 'error'; 443 data.error = translate('FORMS_TIMEOUT'); 444 } 445 446 if (data.status === 'redirect') { 447 if (data.redirect_url) { 448 location.href = data.redirect_url; 449 } 450 return; 451 } 452 453 if (data.status == 'error') 454 { 455 if (data.error_type == 'admin_error'){ 456 alert(data.errors['__all__']); 457 } 458 459 if (window.wotCaptcha) { 460 wotCaptcha.Reload(); 461 } 462 463 if (data.error_code == 600) { 464 wgsdk.forms.auth({ success: function() {form.submit();}, 465 OnCancel: function() { 466 onFormError(translate('FORMS_AUTH_NOT_CONFIRMED')); 467 } 468 }); 469 return; 470 } 471 472 if (data.error_code == 413) {
473 data.error = translate('FORMS_ERROR_413'); 474 if (data.data.size_limit) { 475 var limit = data.data.size_limit; 476 var size = '' + limit + ' b'; 477 if (limit > 1024) { 478 limit = limit / 1024; 479 size = limit.toFixed(2) + ' Kb'; 480 } 481 if (limit > 1024) { 482 limit = limit / 1024; 483 size = limit.toFixed(2) + ' Mb'; 484 } 485 data.error = translate('FORMS_ERROR_413_WITH_LIMIT').replace('%(size)i', size); 486 } 487 } 488 489 if (data.errors && data.errors.__all__ && data.errors.__all__.length > 0) 490 onFormError(data.errors.__all__[0]); 491 if (data.error && data.error.length > 0) 492 onFormError(data.error); 493 494 if (data.errors) 495 for (var field in data.errors) 496 if (field != '__all__' && data.errors[field] && data.errors[field].length > 0) { 497 var prefix = data.form_prefix? data.form_prefix + "-" : ""; 498 onFieldError('id_'+prefix+field, data.errors[field][0]); 499 } 500 } 501 else 502 { 503 onFormError(translate('FORMS_UNKNOWN_ERROR')); 504 } 505 506 if (params.error_replace) { 507 $(params.error_replace.hide, selector).hide(); 508 $(params.error_replace.show, selector).show(); 509 } 510 511 if (params.success_add_text && params.success_add_text.params.from_server) { 512 wgsdk.forms.add_text_to_element(params.success_add_text.selector, 513 {clear: true}); 514 } 515 516 if (params.error) params.error(data); 517 518 if (params.after_error == 'focus') set_focus(form); 519 520 }; 521 522 var OnError = function(request, text, errorThrown) { 523 wgsdk.forms.hide_errors(form); 524 onFormError(translate('FORMS_SERVER_UNAVAILABLE')); 525 526 if (window.wotCaptcha) { 527 wotCaptcha.Reload(); 528 } 529 530 if (params.error) params.error(); 531 532 if (window.ajax_default_error_handler != null){ 533 window.ajax_default_error_handler(request, text, errorThrown); 534 } 535 536 if (params.after_error == 'focus') set_focus(form); 537 }; 538 539 var OnComplete = function() { 540 if (!processing) { 541 wgsdk.waiting('close'); 542 wotUpdateDateTimeFields(); 543 } 544 }; 545 546 wgsdk.waiting('open'); 547 548 var target = form.attr('target'); 549 if (target) { 550 var iframe_number = wgsdk.forms.get_next_iframe_number(); 551 var iframe_id = target+'-'+iframe_number; 552 var iframe = $('<iframe id="'+iframe_id+'" name="'+iframe_id+'" style="display:none;"></iframe>'); 553 iframe.appendTo($('body')); 554 555 form.attr('target', iframe_id); 556 557 if (params.action) { 558 form.attr('action', params.action); 559 } 560 561 function ProcessIframeAnswer(dataString, params) { 562 params = params || {}; 563 564 var data = undefined; 565 var status = 'success'; 566 var request = { 567 status: 200, 568 statusText: 'iframe fake status' 569 }; 570 try { 571 var text = dataString; 572 if (!text) return; 573 data = JSON.parse(text); 574 } 575 catch(err) { 576 status = 'error'; 577 request.status = 404; 578 OnError(request, status, translate('FORMS_WRONG_SERVER_ANSWER')); 579 OnComplete(); 580 } 581 if (data) { 582 OnSuccess(data, status, request); 583 OnComplete(); 584 } 585 586 if (params.OnComplete) params.OnComplete(); 587 588 iframe.remove(); 589 } 590 591 if (params.iframeProxy) { 592 var IFRAME_PROXY = window.IFRAME_PROXY ? window.IFRAME_PROXY : "should be defined in global workspace"; 593 var proxy = new Porthole.WindowProxy(IFRAME_PROXY, iframe_id); 594 Porthole.proxies[proxy.proxyIFrameName] = proxy; 595 596 var EventListener = undefined; 597 598 EventListener = function(messageEvent) { 599 ProcessIframeAnswer(messageEvent.data, 600 {OnComplete: function(){ 601 proxy.removeEventListener(EventListener); 602 delete Porthole.proxies[iframe_id]; 603 } } ); 604 }; 605 proxy.addEventListener(EventListener); 606 } 607 else { 608 609 iframe.load(function(e){ 610 var dataString = ''; 611 if($('#json_data', iframe.contents()).length){ 612 dataString = $('#json_data', iframe.contents()).text(); 613 }else{ 614 dataString = $('body', iframe.contents()).text(); 615 } 616 ProcessIframeAnswer(dataString); 617 }); 618 } 619 620 return false;
621 } 622 else { 623 var ext_data = params.ext_data || []; 624 625 if (typeof ext_data === 'function') { 626 ext_data = ext_data(selector, params); 627 } 628 629 var data = form.serializeArray(); 630 631 $.ajax({ type: 'post', 632 url: params.action || form.attr('action'), 633 data: data.concat(ext_data), 634 dataType: 'json', 635 success: OnSuccess, 636 error: OnError, 637 complete: OnComplete 638 }); 639 return true; 640 } 641 }, 642 643 submit_onFormError: function(form, error_message) { 644 var block = $('.b-message-error', form); 645 if (!block.length) { 646 block = $('<div class="b-message-error b-message-error__none" />').prependTo(form); 647 } 648 649 var text = $('.b-message-error-text', block); 650 if (!text.length) { 651 text = $('<div class="b-message-error-text" />').prependTo(block); 652 } 653 654 text.html(error_message); 655 block.parents('form').addClass('b-error-on-form'); 656 }, 657 658 submit_onFieldError: function(element_id, form, error_message) { 659 var field = $('#' + element_id, form); 660 if (!field.length) { 661 wgsdk.forms.submit_onFormError(form, element_id + ': ' + error_message); 662 return; 663 } 664 665 //trying to find elements for display error message 666 var block = false; 667 var owner = field.parent(); 668 for (var i = 0; i < 2; ++i) { 669 block = $('.b-error', owner); 670 if (block.length > 0) break; 671 672 owner = owner.parent(); 673 } 674 675 if (!block.length) { 676 block = $('<div class="b-error" />'); 677 var tinymce_object = field.parent().find('#'+element_id+'_parent'); 678 // If error for WYSIWYG TinyMCE editor field - display error under editor field 679 if( tinymce_object.length){ 680 tinymce_object.after(block); 681 }else{ 682 field.after(block); 683 } 684 } 685 686 var arrow = $('.arrow', block); 687 if (!arrow.length) { 688 arrow = $('<div class="arrow png"><!-- --></div>').appendTo(block); 689 } 690 691 var text = $('.b-error-text', block); 692 if (!text.length) { 693 text = $('<div class="b-error-text" />').appendTo(block); 694 } 695 696 text.html(error_message); 697 block.parents('fieldset').addClass('b-error-on-form-field'); 698 }, 699 700 /* 701 selector, 702 params: 703 text, 704 clear, | boolean 705 */ 706 add_text_to_element: function(selector, params) { 707 var element = $(selector); 708 if (params.clear && params.clear==true) element.html(''); 709 if (params.text) element.html((element.html() != "" ? element.html() + '<br />' : '') + params.text); 710 }, 711 712 713 // initialized dialogs on all popup_selector-s 714 // wrap submit function - open modal popup with form to wich connected wgsdk.forms.submit 715 // add some wrappers to submit callbacks (success, error) 716 // get all parameters which are available in submit 717 // ext parameters: 718 // - OnOpenCallback = function (popup_selector, form_selector, submit_params, ext_params) 719 // - OnCloseCallback = function (popup_selector, form_selector, submit_params, ext_params) 720 // - source - selector or url of the popup 721 submit_from_popup: function(popup_selector, form_selector, dialog_id, submit_params, ext_params) { 722 723 724 var src = ''; 725 if (ext_params.source) { 726 src = ext_params.source; 727 } 728 729 var OnClosed = function (e ,ui) { 730 var dialog = $(dialog_id); 731 var form = $(form_selector, dialog); 732 if (ext_params.OnCloseCallback) { 733 ext_params.OnCloseCallback(popup_selector, form_selector, submit_params, ext_params); 734 } 735 form.unbind(); 736 }; 737 738 739 var OnReady = function(e, ui) { 740 741 var dialog = $(dialog_id); 742 743 var success = submit_params.success; 744 745 var OnSuccess = function(data, textStatus, XmlHttpRequest) { 746 if (success) { success(data, textStatus, XmlHttpRequest); } 747 748 if (!ext_params.stayOpened) { 749 dialog.dialog('close'); 750 } 751 }; 752 753 submit_params.success = OnSuccess; 754 755 var form = $(form_selector, dialog); 756 757 if (ext_params.OnOpenCallback) { 758 ext_params.OnOpenCallback(popup_selector, form_selector, submit_params, ext_params); 759 } 760 761 wgsdk.forms.init_countables(); 762 763 wgsdk.set_focus(dialog); 764 765 form.submit(function (e){ 766 if (ext_params.OnSubmitCallback) 767 ext_params.OnSubmitCallback(); 768 769 if (wgsdk.forms.submit(form_selector, submit_params)) { 770 e.preventDefault(); 771 } 772 }); 773 774 dialog.dialog( "option", "position", 'center' ); 775 776 if (ext_params.OnReady) { 777 ext_params.OnReady(dialog); 778 } 779 if ($('.js-step').length) { 780 var IE='\v'=='v'; 781 var stepWrap = $(this); 782 if(IE) { 783 setTimeout(function() { 784 wgsdk.step(stepWrap); 785 }, 100); 786 } else { 787 wgsdk.step($(this)); 788 } 789 } 790 }; 791 792 var dialog_params = { 793 modal: true, 794 open: OnReady, 795 close: OnClosed, 796 type: ext_params.type || "get", 797 resizable: false 798 }; 799 if(typeof(ext_params.autoOpen)) dialog_params.autoOpen = ext_params.autoOpen; 800 801 var ShowDialog = function(e){ 802 //TODO: move to OnReady? 803 try { 804 //since src can be an url instead of selector 805 $(src).removeClass('js-hidden'); 806 } 807 catch(err){} 808 809 if (src) { 810 if (typeof ext_params.source === 'function') { 811 dialog_params.url = src(); 812 } 813 else { 814 dialog_params.url = src; 815 } 816 } 817 818 if (typeof ext_params.buttons !== 'undefined') { 819 dialog_params.buttons = ext_params.buttons; 820 } 821 822 if (ext_params.data) { 823 if (typeof ext_params.data === 'function') { 824 dialog_params.ext_data = ext_params.data(); 825 } 826 else { 827 dialog_params.ext_data = ext_params.data; 828 } 829 } 830 831 wgsdk.dialog(dialog_id, dialog_params); 832 833 if (e) e.preventDefault(); 834 } 835 836 if (popup_selector) { 837 $(popup_selector).click(ShowDialog); 838 } 839 else { 840 ShowDialog(); 841 } 842 843 }, 844 845 init_countables: function() { 846 847 $(".js-countable-input").add(".js-countable-field input[type=text]").add(".js-countable-field textarea").each( function(idx, field) {
848 $(field).closest(".js-countable-field").removeClass('js-countable-field'); 849 $(field).closest(".js-countable-input").removeClass('js-countable-input'); 850 851 var fieldset = $(field).closest('fieldset'); 852 if (fieldset.length != 1) { alert('js-countable: fieldset not found'); return; } 853 854 var max_value_el = $('.js-countable-max-value', fieldset); 855 if (max_value_el.length != 1) { alert('js-countable: max-value not specified'); return; } 856 857 var focusInColor = max_value_el.data('focusinColor'), 858 focusOutColor = max_value_el.data('focusoutColor'), 859 zeroNumColor = max_value_el.data('zeronumColor'), 860 defaultColor = max_value_el.css('color'), 861 isFocusColorsAvailable = (focusInColor !== undefined && focusOutColor !== undefined); 862 863 var addFocusInOutEvents = function (counter) { 864 if (isFocusColorsAvailable) { 865 var input = $('input', counter.closest('fieldset')); 866 867 input.focusout(function() { 868 if (counter.text() !== "0") { 869 counter.css('color', focusOutColor); 870 } 871 }); 872 873 input.focusin(function() { 874 if (counter.text() !== "0") { 875 counter.css('color', focusInColor); 876 } 877 }); 878 } 879 }; 880 881 var handleCounterColor = function (counter) { 882 if (counter.text() === "0" && zeroNumColor !== undefined) { 883 counter.css('color', zeroNumColor); 884 } else { 885 if (isFocusColorsAvailable) { 886 if ($('input', counter.closest('fieldset')).is(":focus")) { 887 counter.css('color', focusInColor); 888 } else { 889 counter.css('color', focusOutColor); 890 } 891 } else { 892 counter.css('color', defaultColor); 893 } 894 } 895 } 896 897 var max_value = parseInt(max_value_el.text()); 898 $(field).attr('maxlength', max_value); 899 max_value_el.text(wgsdk.thousands(max_value)); 900 901 var curr_number = $('.b-informer .number', fieldset); 902 if (curr_number.length != 1) { fieldset.append('<span class="number"></span>'); } 903 904 var onPress = function(e) { 905 var isCharacterKeyPress = function(evt) { 906 if (typeof evt.which == "undefined") { 907 // This is IE, which only fires keypress events for printable keys 908 return true; 909 } else if (typeof evt.which == "number" && evt.which > 0) { 910 // In other browsers except old versions of WebKit, evt.which is 911 // only greater than zero if the keypress is a printable key. 912 // We need to filter out backspace and ctrl/alt/meta key combinations 913 return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8; 914 } 915 return false; 916 }; 917 var value = $(field).val(); 918 if (!isCharacterKeyPress(e)) { 919 return true; 920 } 921 922 if (wgsdk.forms.calc_textarea_real_length(value) >= max_value) { 923 /* Allow user to change selected part of text, even if input value length equals maximum length */ 924 if ('selectionStart' in this) { /* IE9+ */ 925 if (this.selectionStart !== this.selectionEnd) { 926 return true; 927 } 928 } else if (document.selection.createRange) { /* IE7/8 */ 929 if (document.selection.createRange().text !== '') { 930 return true; 931 } 932 } 933 return false;
934 } 935 return true; 936 }; 937 var onChange = function(e){ 938 var value = $(field).val(); 939 if (wgsdk.forms.calc_textarea_real_length(value) > max_value) { 940 value = value.substring(0, max_value); 941 $(field).val(value); 942 } 943 curr_number.text( wgsdk.thousands(max_value - wgsdk.forms.calc_textarea_real_length($(field).val()) )); 944 handleCounterColor(curr_number); 945 }; 946 $(field).change(onChange); 947 $(field).keyup(onChange); 948 $(field).keypress(onPress); 949 addFocusInOutEvents(max_value_el); 950 onChange(); 951 }) 952 }, 953 954 calc_textarea_real_length: function(str) { 955 /* function find in passed string all newline symbols and redouble it when calculate the number of symbols. 956 * use when need to calc the length of string before sending to server. 957 * pass params: str - string, 958 * return: number - the patched length. */ 959 return (typeof str === 'string' || str instanceof String) ? str.replace(/\r?\n/gm, "\r\n").length : 0; 960 } 961 } 962 return obj; 963})($) 964 965 966$.extend(wgsdk.forms,{ 967 /* returned value from static/ajax validator shoud be in form: 968 * {'status': 'ok'|'error', 969 * 'error': 'Optional error description', 970 * 'text': 'Optional success text'} 971 */ 972 validate_input: function(input_selector, options) { 973 var defaults = { 974 'preprocessor': null, 975 'postprocessor': null, 976 'validator': null, 977 'ajaxValidator': null, 978 'ajaxDelay': 0, 979 'ignoreAccept': false, 980 'onStateChange': null, 981 'events': null, 982 'initValue': undefined 983 }; 984 985 options = $.extend({}, defaults, options); 986 987 var input = $(input_selector); 988 var fieldset = input.parents('fieldset:first'); 989 var accept = $('.b-accept', fieldset); 990 var decline = $('.b-decline', fieldset); 991 992 var context = { 993 'input': input, 994 'fieldset': fieldset 995 }; 996 997 var ON_BLUR_DELAY = 200; 998 var ON_SET_BLUR_CALLBACK_DELAY = 125; 999 1000 var onStateChange = options.onStateChange || function(){}; 1001 var setState = function(states) { 1002 fieldset.addClass(states); 1003 onStateChange(context); 1004 }; 1005 var clearState = function(states) { 1006 fieldset.removeClass(states || 'decline accept verification'); 1007 onStateChange(context); 1008 }; 1009 var hasAnyOfStates = function(states) { 1010 states = states.split(' '); 1011 for (var i in states) { 1012 var state = states[i]; 1013 if (state && fieldset.hasClass(state)) 1014 return true; 1015 } 1016 1017 return false; 1018 }; 1019 1020 function cleanResult(){ 1021 clearState(); 1022 accept.text(''); 1023 decline.text(''); 1024 } 1025 function isFailed(res){ 1026 return (!res.status || (res.status=='error')); 1027 } 1028 function processResult(res){ 1029 function set_text(el, text){ 1030 if(text) 1031 el.html(text); 1032 else 1033 el.html(' '); 1034 } 1035 cleanResult(); 1036 if(isFailed(res)){ 1037 setState('decline'); 1038 set_text(decline, res.error); 1039 return false; 1040 } 1041 1042 if (!options.ignoreAccept) { 1043 setState('accept'); 1044 set_text(accept, res.text); 1045 } 1046 return true; 1047 } 1048 1049 function inputEqualInitialValue(value) { 1050 if (options.initValue !== undefined) { 1051 return options.initValue === value; 1052 } else { 1053 return false; 1054 } 1055 } 1056 1057 function Validate(value, validateStatic, validateAjax, instant){ 1058 var isInputEqualInitialValue = inputEqualInitialValue(value); 1059 1060 if(validateStatic && options.validator && !isInputEqualInitialValue){ 1061 var res = options.validator(value); 1062 1063 // we'd like to cancel request before updating ui, 1064 // cause it can clean our changes through callback 1065 var failed = isFailed(res); 1066 if(failed) 1067 fetcher.cancelRequest(); 1068 1069 processResult(res); 1070 1071 if(failed) 1072 return; // already failed. do not need ajax 1073 } 1074 if(validateAjax && options.ajaxValidator && !isInputEqualInitialValue){ 1075 clearState('accept'); // not yet 1076 fetcher.sendRequest({'value': value}, instant); 1077 } 1078 1079 if (isInputEqualInitialValue) { 1080 cleanResult(); 1081 } 1082 } 1083 1084 function onChange(value, old_value){ 1085 if(value.length){ 1086 Validate(value, true, true, false); 1087 } else{ 1088 cleanResult(); 1089 fetcher.cancelRequest(); 1090 } 1091 } 1092 function onRequestStarted(settings){ 1093 cleanResult(); 1094 setState('verification'); 1095 } 1096 function onRequestFinished(data){ 1097 cleanResult(); 1098 if(data) 1099 processResult(data); 1100 } 1101 1102 // wrap in setTimeout, since we sometimes move focus in form (see submit_from_popup) right before 1103 // this code is executed and it cause processing an unexpecred OnBlur event in IE 1104 setTimeout(function() { 1105 input.blur(function(event) { 1106 setTimeout(function() { 1107 if (!hasAnyOfStates('accept decline verification')) { 1108 var value = watcher.getValue(); 1109 1110 // AJAX validation is pointless for empty values
1111 var validateAjax = value != ''; 1112 Validate(value, true, validateAjax, true); 1113 } 1114 }, ON_BLUR_DELAY); 1115 }); 1116 }, ON_SET_BLUR_CALLBACK_DELAY); 1117 1118 var watcher = new wgsdk.InputWatcher(input, options.preprocessor, onChange, options.postprocessor, options.events); 1119 var fetcher = new wgsdk.AjaxFetcher(options.ajaxValidator, onRequestStarted, onRequestFinished, options.ajaxDelay); 1120 var submitHandler = function(event){ 1121 if (!hasAnyOfStates('accept error decline verification')) 1122 Validate(watcher.getValue(), true, false, true); 1123 1124 if (hasAnyOfStates('error decline verification')) { 1125 event.preventDefault(); 1126 event.stopImmediatePropagation(); 1127 } 1128 }; 1129 input.parents('form:first').submit(submitHandler); 1130 input.bind('remove', function(){ 1131 $(this).parents('form:first').unbind('submit', submitHandler); 1132 }); 1133 }, 1134 1135 validate_input_size: function(inputSelector, params) { 1136 this.validate_input(inputSelector, {'validator': wgsdk.InputLengthValidator(inputSelector, params)}); 1137 } 1138}); 1139 1140wgsdk.forms.Forms = (function(){ 1141 var obj = { 1142 create: function(method, url, params, target) { 1143 var form = $('<form>') 1144 .attr('method', method) 1145 .attr('action', url); 1146 1147 if (target) { 1148 form.attr('target', target); 1149 } 1150 1151 $.each(params, function(key, value) { 1152 $('<input type="hidden">') 1153 .attr('name', key) 1154 .attr('value', value) 1155 .appendTo(form); 1156 }); 1157 1158 form.appendTo('body'); 1159 return form; 1160 }, 1161 send: function(method, url, params, target) { 1162 var form = wgsdk.forms.Forms.create(method, url, params, target); 1163 form.submit(); 1164 }, 1165 sendGet: function(url, params, target) { 1166 return wgsdk.forms.Forms.send('GET', url, params, target); 1167 }, 1168 sendPost: function(url, params, target) { 1169 return wgsdk.forms.Forms.send('POST', url, params, target); 1170 } 1171 }; 1172 return obj; 1173})($); 1174 1175 1176wgsdk.autocomplete = (function($, wgsdk) { 1177 'use strict'; 1178 1179 var globalAutocompleteCounter = 0, 1180 KEY_BACKSPACE = 8, 1181 KEY_ENTER = 13, 1182 KEY_ESCAPE = 27, 1183 KEY_DOWN = 40, 1184 KEY_UP = 38, 1185 ON_BLUR_HIDE_TIMEOUT = 200, 1186 CONTAINER_SELECTOR = '.js-autocomplete-container'; 1187 1188 var module = function (inputSelector, url, options) { 1189 1190 var autocompleteContainerId = 'js-autocomplete-container-' + (++globalAutocompleteCounter), 1191 defaults = { 1192 'autosubmit': false, /* Submit form on click/enter */ 1193 'minlength': 0, 1194 'preprocessor': function(value, prefix) { 1195 value = $.trim(value); 1196 prefix = $.trim(prefix); 1197 var matchedSubstrIndex = value.toLowerCase().indexOf(prefix.toLowerCase()); 1198 value = value.substr(0, matchedSubstrIndex) + '<span class="b-autocomplete_match">'+value.substr(matchedSubstrIndex, prefix.length)+'</span>'+value.substr(matchedSubstrIndex+prefix.length); 1199 return value; 1200 }, 1201 'zindex': null, 1202 'customWrapper': null, 1203 'postprocessor': null, 1204 'dataprocessor': null, /* AJAX params processor before send */ 1205 'changeCallback': null, 1206 'responseDataPreprocessor': null, 1207 'customClass': '' 1208 }, 1209 $input, $lines, $wrapper, $wrapperContainer, $template, watcher, fetcher, searchValue, $form; 1210 1211 options = $.extend({}, defaults, options); 1212 1213 function getItemContainer() { 1214 if (options.customWrapper === null) { 1215 return $wrapper; 1216 } else { 1217 return $wrapperContainer; 1218 } 1219 } 1220 1221 function updatePosition() { 1222 var inputOffset = $input.offset(); 1223 1224 $wrapper 1225 .outerWidth($input.outerWidth()) 1226 .css({ 1227 'top' : inputOffset.top + $input.outerHeight(), 1228 'left': inputOffset.left 1229 }); 1230 } 1231 1232 function getSelected() { 1233 return $('.b-autocomplete_item__selected:first'); 1234 } 1235 1236 function hasScroll() { 1237 var $container = getItemContainer(), 1238 scrollHeight = $container[$.fn.prop ? 'prop' : 'attr']('scrollHeight'); 1239 1240 return $container.height() < scrollHeight; 1241 } 1242 1243 function setSelected($sel) { 1244 getSelected().removeClass('b-autocomplete_item__selected'); 1245 1246 if ($sel && $sel.length > 0) { 1247 $sel.addClass('b-autocomplete_item__selected'); 1248 1249 if (hasScroll()) { 1250 var $container = getItemContainer(), 1251 offset = $sel.offset().top - $container.offset().top, 1252 scroll = $container.scrollTop(), 1253 elementHeight = $container.height(); 1254 1255 if (offset < 0) { 1256 $container.scrollTop(scroll + offset); 1257 } else if (offset >= elementHeight) { 1258 $container.scrollTop(scroll + offset - elementHeight + $sel.height()); 1259 } 1260 } 1261 } 1262 } 1263 1264 function updateInputWithSelected(applyFilter) { 1265 var $sel = getSelected(); 1266 1267 if ($sel.length) { 1268 watcher.setValue($sel.text(), applyFilter); 1269 if (typeof options.changeCallback === 'function') { 1270 options.changeCallback(); 1271 } 1272 } 1273 } 1274 1275 function restoreInput() { 1276 watcher.restoreValue(); 1277 if (typeof options.changeCallback === 'function') { 1278 options.changeCallback(); 1279 } 1280 } 1281 1282 function isSuggestionVisible(){ 1283 return $wrapper.css('display') !== 'none'; 1284 } 1285 1286 function setVisibility(show) { 1287 if (show !== isSuggestionVisible()) { 1288 if (show && $lines && $lines.length) { 1289 updatePosition(); 1290 $wrapper.show(); 1291 } else { 1292 $wrapper.hide(); 1293 } 1294 } 1295 } 1296 1297 function applySelected() { 1298 fetcher.cancelRequest(); 1299 updateInputWithSelected(true); 1300 setVisibility(false); 1301 1302 // value was set by .val() call, which doesn't trigger change event 1303 $input.change(); 1304 } 1305 1306 function onRequestComplete(data) { 1307 var template, i, len, content, $newElement; 1308 1309 if (data && data.result) { 1310 // overwrite template with new value or add to DOM 1311 if (data.tmpl) { 1312 template = $(data.tmpl).hide(); 1313 if ($template) { 1314 $template.replaceWith(template); 1315 } else { 1316 $input.after(template); 1317 $template = template; 1318 } 1319 } 1320 if (!$template && !data.tmpl) { 1321 $template = $('<div></div>'); 1322 } 1323 1324 $lines = undefined; 1325 getItemContainer().empty(); 1326 1327 if ($template) { 1328 1329 $('.js-autocomplete').remove(); 1330 1331 if (typeof options.responseDataPreprocessor === 'function') { 1332 data = options.responseDataPreprocessor(data); 1333 } 1334 1335 for (i = 0, len = data.result.length; i < len; ++i) { 1336 content = data.result[i].text; 1337 if (typeof options.preprocessor === 'function') { 1338 content = options.preprocessor(content, searchValue, data.result[i]); 1339 } 1340 $newElement = $template.clone().addClass('js-autocomplete b-autocomplete_item').html(content).show(); 1341 1342 getItemContainer().append($newElement); 1343 1344 } 1345 $lines = $('.js-autocomplete'); 1346 setVisibility(data.result.length > 0 ? true : false); 1347 } 1348 1349 $lines 1350 .on('click', function() { 1351 1352 applySelected(); 1353 $input.focus(); 1354 if (options.autosubmit) { 1355 $form = $input.closest('form'); 1356 $form.submit(); 1357 } 1358 1359 }) 1360 .hover( 1361 function(e) { setSelected($(this)); }, 1362 function(e) { setSelected(null); } 1363 ); 1364 1365 } else { 1366 setVisibility(false); 1367 } 1368 } 1369 1370 function preventAutocomplete() { 1371 fetcher.cancelRequest(); 1372 setVisibility(false); 1373 } 1374 1375 function destroy() { 1376 preventAutocomplete(); 1377 if ($input.length) { 1378 $wrapper.remove(); 1379 $input.off('.autocomplete'); 1380 $input.parents('form:first').off('.autocomplete'); 1381 } 1382 if (watcher) { 1383 watcher.destroy(); 1384 } 1385 } 1386 1387 function onValueChange(value, oldValue) { 1388 var data = {'fl': value}; 1389 1390 if (value.length === 0 || value.length < options.minlength) { 1391 fetcher.cancelRequest(); 1392 setVisibility(false); 1393 return; 1394 } 1395 1396 searchValue = value; 1397 1398 if (!$template) { 1399 data.tmpl = 1; 1400 } 1401 1402 if (typeof options.dataprocessor === 'function') { 1403 data = options.dataprocessor(data); 1404 } 1405 1406 fetcher.sendRequest(data, false); 1407 } 1408 1409 1410 $(document).ready(function() { 1411 1412 $input = $(inputSelector); 1413 1414 if ($input.length) { 1415 if (options.customWrapper === null) {
1416 $wrapper = $('<div class="b-autocomplete"></div>'); 1417 } else { 1418 $wrapper = $(options.customWrapper); 1419 $wrapperContainer = $wrapper.find(CONTAINER_SELECTOR); 1420 } 1421 1422 if (options.zindex !== null) { 1423 $wrapper.css('zIndex', options.zindex + globalAutocompleteCounter); 1424 } 1425 1426 $wrapper.addClass(options.customClass); 1427 1428 $wrapper 1429 .attr('id', autocompleteContainerId) 1430 .hide() 1431 .appendTo('body'); 1432 $wrapper.trigger('appended'); 1433 1434 $input.on('keydown.autocomplete', function(event) { 1435 if (event.keyCode === KEY_BACKSPACE) { 1436 setTimeout(function() { $input.trigger('input'); }, 1); // IE 9 doesn't trigger 'input' event on backspace 1437 } 1438 1439 if (event.keyCode === KEY_ENTER) { 1440 fetcher.cancelRequest(); 1441 } 1442 1443 if (!options.autosubmit && isSuggestionVisible() && event.keyCode === KEY_ENTER) { 1444 applySelected(); 1445 event.preventDefault(); 1446 } 1447 }); 1448 1449 $input.on('keyup.autocomplete', function(event) { 1450 var $selected; 1451 1452 if (!isSuggestionVisible()) { 1453 return; 1454 } 1455 1456 // suggestions navigation. 1457 if(event.keyCode === KEY_ESCAPE) { 1458 restoreInput(); 1459 setVisibility(false); 1460 } 1461 1462 if ($lines && (event.keyCode === KEY_UP || event.keyCode === KEY_DOWN)) { 1463 // select next element 1464 $selected = getSelected(); 1465 if ($selected.length) { 1466 setSelected((event.keyCode === KEY_UP) ? $selected.prev() : $selected.next()); 1467 } else { 1468 setSelected((event.keyCode === KEY_UP) ? $lines.last() : $lines.first()); 1469 } 1470 1471 watcher.stopWatch(); /* IE 7/8 fires propertychange */ 1472 // if no selection. restore user's input 1473 if (getSelected().length) { 1474 updateInputWithSelected(false); 1475 } else { 1476 restoreInput(); 1477 } 1478 watcher.startWatch(); 1479 } 1480 }); 1481 1482 $input.parents('form:first').on('submit.autocomplete', function(event) { 1483 if (isSuggestionVisible()) { 1484 applySelected(); 1485 } 1486 }); 1487 1488 $input.on('blur.autocomplete', function(event) { 1489 if (isSuggestionVisible()) { 1490 setTimeout(function() { 1491 setVisibility(false); 1492 }, ON_BLUR_HIDE_TIMEOUT); // give some time to process click on suggestion element 1493 } 1494 }); 1495 1496 watcher = new wgsdk.InputWatcher($input, null, onValueChange, options.postprocessor); 1497 if (typeof(url) === 'function') { 1498 fetcher = new wgsdk.NoAjaxFetcher(url, null, onRequestComplete); 1499 } else { 1500 fetcher = new wgsdk.AjaxFetcher({'url': url}, null, onRequestComplete, 600); 1501 } 1502 1503 } 1504 1505 }); 1506 1507 // API 1508 return { 1509 'setVisibility': setVisibility, 1510 'preventAutocomplete': preventAutocomplete, 1511 'destroy': destroy 1512 }; 1513 }; 1514 1515 return module; 1516 1517})(jQuery, wgsdk); 1518 1519 1520wgsdk.clearer = (function($) { 1521 'use strict'; 1522 1523 var module = function(inputSelector, clrSelector, options) { 1524 var $instance = $(clrSelector), 1525 $input = $(inputSelector), 1526 defaults = { 1527 clearCallback: undefined 1528 }; 1529 1530 options = $.extend({}, defaults, options); 1531 1532 if (!($input.length && $instance.length)) { 1533 return; 1534 } 1535 1536 function show() { 1537 $instance.css('display', 'block'); 1538 } 1539 1540 function hide() { 1541 $instance.css('display', 'none'); 1542 } 1543
1544 function update() { 1545 if ($input.val() !== '') { 1546 show(); 1547 } else { 1548 hide(); 1549 } 1550 } 1551 1552 $input.keyup(update); 1553 1554 $instance.click(function(e) { 1555 $instance.css('display', 'none'); 1556 if (typeof options.clearCallback === 'function') { 1557 options.clearCallback(e); 1558 } 1559 }); 1560 1561 // API 1562 return { 1563 'update': update, 1564 'hide': hide, 1565 'show': show 1566 }; 1567 }; 1568 1569 return module; 1570 1571})(jQuery); 1572 1573 1574$(document).ready( function() { 1575 wgsdk.forms.init_countables(); 1576});
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.