1/** 2 * @category Individ 3 * @link http://individ.ru 4 * @revision $Revision$ 5 * @date $Date$ 6 */ 7 8'use strict'; 9 10/** 11 * XXX: Individ namespace 12 */ 13var indi = new function() 14{ 15 /** 16 * ÐÑизнак иниÑиализаÑии 17 * 18 * @var boolean 19 */ 20 var initialized = false; 21 22 /** 23 * ÐниÑиализиÑÑÐµÑ Ð²Ñе ÑÑнкÑионалÑнÑе ÑаÑÑи 24 * 25 * @return void 26 */ 27 this.init = function() 28 { 29 if (initialized) { 30 return; 31 } 32 initialized = true; 33 34 indi.app.init(); 35 indi.ui.init(); 36 }; 37}; 38 39 40 41 42/** 43 * XXX: ÐÑиложение 44 */ 45indi.app = new function() 46{ 47 /** 48 * ÐниÑиализиÑÑÐµÑ Ð¿Ñиложение 49 * 50 * @return void 51 */ 52 this.init = function() 53 { 54 //ÐниÑиализиÑÑем Ð»Ð¾ÐºÐ°Ð»Ñ 55 this.locale.init(); 56 57 //ÐниÑиализиÑÑем ÑÑнкÑионалÑнÑе блоки 58 this.blocks.init(); 59 }; 60}; 61 62 63 64 65/** 66 * XXX: ФÑнкÑионалÑнÑе блоки пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ 67 */ 68indi.app.blocks = new function() 69{ 70 /** 71 * Ф-ии обÑаÑного вÑзова о гоÑовноÑÑи вÑÐµÑ ÑÑнкÑионалÑнÑÑ Ð±Ð»Ð¾ÐºÐ¾Ð² 72 * 73 * @var array 74 */ 75 var initCallbacks = []; 76 77 /** 78 * ÐаÑезеÑвиÑованнÑе Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð², коÑоÑÑе нелÑÐ·Ñ Ð¿ÐµÑеопÑеделÑÑÑ 79 * 80 * @var object 81 */ 82 var reserved = {}; 83 84 /** 85 * ÐобавлÑÐµÑ Ñ-Ñ Ð¾Ð±ÑаÑного вÑзова о гоÑовноÑÑи вÑÐµÑ Ð±Ð»Ð¾ÐºÐ¾Ð² 86 * 87 * @param object callback Ф-Ñ Ð¾Ð±ÑаÑного вÑзова 88 * @param object context ÐонÑекÑÑ Ð²Ñзова Ñ-ии 89 * @return void 90 */ 91 this.onInit = function(callback, context) 92 { 93 initCallbacks.push({ 94 callback: callback, 95 context: context = context || this 96 }); 97 }; 98 99 /** 100 * ÐниÑиализиÑÑÐµÑ ÑÑнкÑионалÑнÑе блоки 101 * 102 * @return void 103 */ 104 this.init = function() 105 { 106 for (var key in this) { 107 if (reserved[key]) { 108 continue; 109 } 110 111 var blockConstructor = this[key]; 112 if (typeof blockConstructor == 'function') { 113 var blockExists = blockConstructor.exists ? blockConstructor.exists() : true; 114 if (blockExists) { 115 this[key] = new blockConstructor(); 116 } 117 } 118 } 119 120 for (var i = 0; i < initCallbacks.length; i++) { 121 initCallbacks[i].callback.call( 122 initCallbacks[i].context 123 ); 124 }; 125 }; 126 127 //ÐаполнÑем заÑезеÑвиÑованнÑе Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð±Ð»Ð¾ÐºÐ¾Ð² 128 for (var key in this) { 129 reserved[key] = true; 130 } 131}; 132 133 134 135 136/** 137 * XXX: ÐÐ¾ÐºÐ°Ð»Ñ 138 */ 139indi.app.locale = new function() 140{ 141 /** 142 * ÐаÑÑÑойки локали 143 * 144 * @var object 145 */ 146 this.settings = { 147 date: 'dd.mm.yy', 148 time: 'hh:mm', 149 dateTime: 'dd.mm.yy hh:mm', 150 firstDay: 1, 151 isRTL: false 152 }; 153 154 /** 155 * СообÑÐµÐ½Ð¸Ñ Ð»Ð¾ÐºÐ°Ð»Ð¸ 156 * 157 * @var object 158 */ 159 this.messages = { 160 monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 161 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 162 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 163 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 164 dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], 165 close: 'Close', 166 datePicker: { 167 prev: '←Previous', 168 next: 'Next→', 169 current: 'Today', 170 showMonthAfterYear: false, 171 weekHeader: 'Wk', 172 yearSuffix: '' 173 }, 174 timePicker: { 175 timeOnlyTitle: 'Choose time', 176 timeText: 'Time', 177 hourText: 'Hours', 178 minuteText: 'Minutes', 179 secondText: 'Seconds', 180 millisecText: 'Milliseconds', 181 currentText: 'Now', 182 ampm: true 183 }, 184 alert: { 185 title: 'System message', 186 ok: 'Ok' 187 } 188 }; 189 190 /** 191 * XXX: ÐозвÑаÑÐ°ÐµÑ Ð¾ÑÑоÑмаÑиÑованнÑÑ ÑÑÑÐ¾ÐºÑ 192 * ТÑебÑеÑÑÑ jQuery UI datepicker. 193 * 194 * @param Date date ÐаÑа Ð´Ð»Ñ ÑоÑмаÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ 195 * @param String format ФоÑÐ¼Ð°Ñ (по-ÑмолÑÐ°Ð½Ð¸Ñ indi.app.locale.settings.date) 196 * @return String 197 */ 198 this.format = function(date, format) 199 { 200 format = format === undefined ? this.settings.date : format; 201 202 return $.datepicker.formatDate(format, date); 203 }; 204 205 /** 206 * XXX: РазбиÑÐ°ÐµÑ Ð¾ÑÑоÑмаÑиÑованнÑÑ ÑÑÑÐ¾ÐºÑ 207 * ТÑебÑеÑÑÑ jQuery UI datepicker. 208 * 209 * @param String date ÐÑÑоÑмаÑиÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð´Ð°Ñа 210 * @param String format ФоÑÐ¼Ð°Ñ (по-ÑмолÑÐ°Ð½Ð¸Ñ indi.app.locale.settings.date) 211 * @return Date 212 */ 213 this.parse = function(date, format) 214 { 215 format = format === undefined ? this.settings.date : format; 216 217 return $.datepicker.parseDate(format, date); 218 }; 219 220 /** 221 * ÐниÑиализиÑÑÐµÑ Ð»Ð¾ÐºÐ°Ð»Ñ 222 * 223 * @return void 224 */ 225 this.init = function() 226 { 227 if($.datepicker) 228 { 229 $.datepicker.regional[''] = { 230 closeText: this.messages.close, 231 prevText: this.messages.datePicker.prev, 232 nextText: this.messages.datePicker.next, 233 currentText: this.messages.datePicker.current, 234 monthNames: this.messages.monthNames, 235 monthNamesShort: this.messages.monthNamesShort, 236 dayNames: this.messages.dayNames, 237 dayNamesShort: this.messages.dayNamesShort, 238 dayNamesMin: this.messages.dayNamesMin, 239 weekHeader: this.messages.datePicker.weekHeader, 240 dateFormat: this.settings.date, 241 firstDay: this.settings.firstDay, 242 isRTL: this.settings.isRTL, 243 showMonthAfterYear: this.messages.datePicker.showMonthAfterYear, 244 yearSuffix: this.messages.datePicker.yearSuffix 245 }; 246 $.datepicker.setDefaults($.datepicker.regional['']); 247 } 248 249 if($.timepicker) 250 { 251 $.timepicker.regional[''] = { 252 timeOnlyTitle: this.messages.timePicker.timeOnlyTitle, 253 timeText: this.messages.timePicker.timeText, 254 hourText: this.messages.timePicker.hourText, 255 minuteText: this.messages.timePicker.minuteText, 256 secondText: this.messages.timePicker.secondText, 257 millisecText: this.messages.timePicker.millisecText, 258 currentText: this.messages.timePicker.currentText, 259 closeText: this.messages.close, 260 ampm: this.messages.timePicker.ampm 261 }; 262 $.timepicker.setDefaults($.timepicker.regional['']); 263 } 264 }; 265}; 266 267 268 269 270/** 271 * XXX: User interface 272 */ 273indi.ui = new function() 274{ 275 /** 276 * Ф-ии обÑаÑного вÑзова о гоÑовноÑÑи виджеÑов 277 * 278 * @var array 279 */ 280 var initCallbacks = []; 281 282 /** 283 * XXX: ÐÑобÑÐ°Ð¶Ð°ÐµÑ Ð´Ð¸Ð°Ð»Ð¾Ð³ Ñ ÑообÑением 284 * 285 * @param string messge ТекÑÑ ÑообÑениÑ
286 * @param object config ÐонÑигÑÑаÑÐ¸Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð° 287 * ÐонÑиг Ð¼Ð¾Ð¶ÐµÑ ÑодеÑжаÑÑ ÑледÑÑÑие паÑамеÑÑÑ type - Ñип оповеÑениÑ(модалÑное окно или замеÑение ÑлеменÑов), 288 * status - ÑÑаÑÑÑ Ð¾Ð¿Ð¾Ð²ÐµÑÐµÐ½Ð¸Ñ (success, warning, notification и Ñ.д.), elem - заменÑемÑй ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¾Ð±ÑзаÑелен Ð´Ð»Ñ Ð·Ð°Ð¼ÐµÑÐµÐ½Ð¸Ñ ÑлеменÑов 289 * @return void 290 */ 291 this.alert = function(message, config) 292 { 293 config = $.extend( 294 {type: 'modal', engine: 'bootstrap', status: 'notification'}, 295 config || {} 296 ); 297 298 switch(config.type){ 299 case 'modal': 300 if( config.engine == 'fancybox' && typeof $.fancybox == 'function' ){ 301 var message = '<p class="notification notification_' + config.status + '">' + 302 '<span class="notification__text">' + message + '</span>' + 303 '</p>'; 304 $.fancybox(message); 305 } 306 else{ 307 var message = '<div id="notification-modal" class="modal fade" tabindex="-1" role="dialog">' + 308 '<div class="modal-dialog">' + 309 '<div class="modal-content">' + 310 '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>' + 311 '<div class="modal-body">' + 312 '<p class="notification notification_' + config.status + '">' + 313 '<span class="notification__text">' + message + '</span>' + 314 '</p>' + 315 '</div>' + 316 '</div>' + 317 '</div>' + 318 '</div>'; 319 $(message).appendTo('body').modal('show'); 320 } 321 322 break; 323 324 case 'elem': 325 if( !(config.elem.length) ){ 326 return false; 327 } 328 329 var $messHtml = '<p class="notification notification_' + config.status + '">' + 330 '<span class="notification__text">' + message + '</span>' + 331 '</p>'; 332 config.elem.after($messHtml).hide(); 333 } 334 }; 335 336 /** 337 * ÐобавлÑÐµÑ Ñ-Ñ Ð¾Ð±ÑаÑного вÑзова пÑи иниÑиализаÑии UI 338 * 339 * @param object callback Ф-Ñ Ð¾Ð±ÑаÑного вÑзова 340 * @param object context ÐонÑекÑÑ Ð²Ñзова Ñ-ии 341 * @return void 342 */ 343 this.onInit = function(callback, context) 344 { 345 initCallbacks.push({ 346 callback: callback, 347 context: context || this 348 }); 349 }; 350 351 /** 352 * ÐниÑиализиÑÑÐµÑ UI 353 * 354 * @param string selector РодиÑелÑÑкий ÑÐ»ÐµÐ¼ÐµÐ½Ñ 355 * @return void 356 */ 357 this.init = function(selector) 358 { 359 if (selector === undefined) { 360 selector = $('body'); 361 } else { 362 selector = $(selector); 363 } 364 365 this.widgets.init(selector); 366 367 for (var i = 0; i < initCallbacks.length; i++) { 368 initCallbacks[i].callback.call( 369 initCallbacks[i].context, 370 selector 371 372 ); 373 }; 374 } 375}; 376 377/** 378 * XXX: ÐиджеÑÑ 379 */ 380indi.ui.widgets = new function() 381{ 382 /** 383 * ÐонÑÑÑÑкÑоÑÑ Ð²Ð¸Ð´Ð¶ÐµÑов 384 * 385 * @var object 386 */ 387 this.items = {}; 388 389 /** 390 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ ÑÑилизованное поле загÑÑзки Ñайла. ÐÑли Ñказан multiple - множеÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð·Ð°Ð³ÑÑзка 391 * ÐÑÐ¸Ð¼ÐµÑ Ð²Ñзова: 392 * <form method="post"enctype="multipart/form-data"> 393 * <div class="span_file js-file-add"> 394 * <input name="FILE[]" multiple data-max-files="3" type="file" class="widget uploadpicker" placeholder="ÐÑикÑепиÑÑ Ñайл"> 395 * <span class="question question--file" title="ÐапÑимеÑ, ÑоÑо пÑодÑкÑа. Ðе более 5 ÑÑÑк."></span> 396 * <div class="is-label"> 397 * <small class="block-form__delete"> 398 * <span class="upload-field-label"><i class="js-file-reset"></i></span> 399 * </small> 400 * </div> 401 * </div> 402 * <input type="submit"> 403 * </form> 404 * 405 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 406 * @return void 407 */ 408 this.items['uploadpicker'] = function(selector) 409 { 410 /*if (!$.uploadpicker) { 411 return; 412 }*/ 413 414 $(selector).each(function() { 415 var field = $(this); 416 var required = field.is('[required]'); 417 var disabled = field.is('[disabled]'); 418 var isMultiple = field.is('[multiple]'); 419 var placeholder = field.attr('placeholder'); 420 var maxFiles = field.data("max-files"); 421 if(!maxFiles) 422 maxFiles = 10; 423 424 field 425 .addClass('upload-field-overlay') 426 .removeAttr('required') 427 .css({ 428 cursor: 'pointer', 429 fontSize: '200px', 430 height: 'auto', 431 opacity: 0, 432 position: 'absolute', 433 right: 0, 434 top: '-0.5em', 435 width: 'auto' 436 })
437 .wrap('<span class="widget-upload-field"/>') 438 439 var wrapper = field.parent(); 440 wrapper 441 .css({ 442 backgroundColor: 'transparent', 443 display: 'block', 444 overflow: 'hidden', 445 position: 'relative' 446 }) 447 .prepend('<input class="upload-field-value form-control" type="text"' 448 + (required ? ' required=""' : '') 449 + (disabled ? ' disabled=""' : '') 450 + (placeholder ? ' placeholder="' + placeholder + '"' : '') 451 + ' />') 452 .prepend("<a class='add-file fake'>"+field.attr("placeholder")+"</a>"); 453 var $fileAdd = wrapper.closest(".js-file-add"); 454 var $fileAddLabel = $fileAdd.find('.upload-field-label'); 455 field.on({'change': function() { 456 //ÐÑли множеÑÑÐ²ÐµÐ½Ð½Ð°Ñ Ð·Ð°Ð³ÑÑзка 457 if(isMultiple){ 458 if($(this).closest(".js-new-add-container").length == 0){ 459 $(this).closest(".span_file").wrap("<div class='js-new-add-container'></div>"); 460 } 461 var count = selector.closest(".js-new-add-container").find(".js-file-add").length; 462 /*console.log(maxFiles); 463 console.log(count);*/ 464 if(maxFiles < count){ 465 alert("Ðожно пÑикÑепиÑÑ Ð¼Ð°ÐºÑимÑм "+maxFiles+" Ñайлов"); 466 return false; 467 } 468 469 $(this).closest(".js-new-add-container").append('<div class="span_file span_file--new js-file-add js-file-add--new">'+ 470 '<input name="FILE[]" type="file" multiple class="widget uploadpicker js-new-uploadpicker js-new-uploadpicker-'+count+'" data-max-files="'+maxFiles+'" placeholder="ÐÑе">'+ 471 '<div class="is-label">'+ 472 '<small class="block-form__delete">'+ 473 '<span class="upload-field-label"><i class="js-file-reset"></i></span>'+ 474 '</small>'+ 475 '</div>'+ 476 '</div>'); 477 indi.ui.widgets.items.uploadpicker($(".js-new-uploadpicker-"+count)); 478 $(this).closest(".js-new-add-container").find(".js-file-add--new:not(:last-child)").find(".add-file").remove(); 479 } 480 481 var values = [this.value.split(/[\/\\]/).pop()]; 482 if (this.files) { 483 values = []; 484 for (var i = 0; i < this.files.length; i++) { 485 values.push(this.files[i].name); 486 } 487 } 488 values.length ? wrapper.addClass('has-value') : wrapper.removeClass('has-value'); 489 wrapper.find('.upload-field-value').val(values.join(', ')); 490 }, 'keypress': function(event) { 491 if (event.key == 'Backspace') { 492 if (this.value) { 493 event.preventDefault(); 494 this.value = ''; 495 $(this).trigger('change'); 496 } 497 } 498 } 499 }); 500 }); 501 }; 502 503 /** 504 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ Ð¿Ð¾Ð»Ðµ вÑбоÑа даÑÑ 505 * 506 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 507 * @return void 508 * ÐаÑамеÑÑ config пеÑедаеÑÑÑ Ð² Ñаком виде data-config='{"minDate": 0}' 509 */ 510 this.items['datepicker'] = function (selector) { 511 if (!$.datepicker) { 512 return; 513 } 514 515 var defaults = indi.ui.widgets.items.datepicker.defaults; 516 517 $(selector).each(function () { 518 var element = $(this); 519 520 var $datapickerWrap = $(element).parent(); 521 $datapickerWrap.on('click', '.datepicker-clear', function() { 522 var $iconDatePicker = $datapickerWrap.find('.datepicker-icon'); 523 element.datepicker('setDate', null); 524 $iconDatePicker.show(); 525 $(this).hide(); 526 }); 527 528 element.datepicker($.extend( 529 {}, 530 defaults, 531 element.data('config') || {} 532 )); 533 534 if (element.is(':input')) { 535 element 536 .keypress(function (event) { 537 switch (event.keyCode) { 538 case 13: 539 //ÐÑли Enter нажимаеÑÑÑ Ð¿Ñи оÑкÑÑÑом календаÑе - ÑбиÑаем каленÑаÑÑ Ð¸ ÑабмиÑим ÑоÑÐ¼Ñ 540 if ($(this).datepicker('widget').css('display') != 'none') { 541 event.stopPropagation(); 542 $(this).datepicker('hide'); 543 if (this.form) { 544 $(this.form).trigger('submit'); 545 } 546 } 547 break; 548 } 549 }) 550 .after( 551 '<span class="datepicker-icon" title="ÐÑбÑаÑÑ Ð´Ð°ÑÑ"></span>' 552 ) 553 .mask("99.99.9999") 554 .next('.datepicker-icon') 555 .click(function () { 556 $(this).prev('.datepicker').datepicker('show'); 557 }); 558 } 559 }); 560 }; 561 562 this.items['datepicker'].defaults = {
563 changeMonth: false, 564 changeYear: false, 565 minDate: new Date(1900, 1, 1), 566 maxDate: '', 567 onClose: function (selectedDate, widgetInstance) { 568 if ($('.startDate').length && $('.endDate').length) { 569 if ($(widgetInstance.input[0]).hasClass('startDate')) 570 $('.endDate').datepicker("option", "minDate", selectedDate); 571 else if ($(widgetInstance.input[0]).hasClass('endDate')) 572 $('.startDate').datepicker("option", "maxDate", selectedDate); 573 } 574 }, 575 onSelect: function(date, inst) { 576 var $iconClear = $(this).parent().find('.datepicker-clear'); 577 var $iconDatePicker = $(this).parent().find('.datepicker-icon'); 578 if(!$iconClear.length) { 579 $(this).after( 580 '<span class="datepicker-clear" title="ÐÑиÑÑиÑÑ Ð´Ð°ÑÑ"></span>' 581 ) 582 } 583 else { 584 $iconClear.show(); 585 } 586 587 $iconDatePicker.hide(); 588 } 589 }; 590 591 /** 592 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ Ð¿Ð¾Ð»Ðµ вÑбоÑа вÑемени 593 * 594 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 595 * @return void 596 */ 597 this.items['timepicker'] = function(selector) 598 { 599 if (!$.timepicker || !$.mask) { 600 return; 601 } 602 603 $(selector) 604 .timepicker() 605 .mask('99:99'); 606 }; 607 608 /** 609 * ÐÐ¸Ð´Ð¶ÐµÑ ÐºÐ°ÑÑомизаÑии ÑелекÑов 610 * http://selectize.github.io/selectize.js/ 611 * 612 * @param selector 613 */ 614 this.items['selectize'] = function(selector) 615 { 616 if (!$.fn.selectize) { 617 return; 618 } 619 620 var defaults = indi.ui.widgets.items.selectize.defaults; 621 622 $(selector).each(function() { 623 var element = $(this); 624 625 var config = $.extend( 626 {}, 627 defaults, 628 element.data('config') || {} 629 ) 630 631 element.selectize(config); 632 }); 633 }; 634 635 this.items['selectize'].defaults = {}; 636 637 638 /** 639 * ÐÐ¸Ð´Ð¶ÐµÑ ÑлайдеÑа 640 * http://kenwheeler.github.io/slick/ 641 * 642 * @param selector 643 */ 644 this.items['slick'] = function(selector) 645 { 646 647 if (!$.fn.slick) { 648 return; 649 } 650 651 var defaults = indi.ui.widgets.items.slick.defaults; 652 653 $(selector).each(function() { 654 var element = $(this); 655 656 var config = $.extend( 657 {}, 658 defaults, 659 element.data('config') || {} 660 ) 661 662 element.slick(config); 663 }); 664 }; 665 666 this.items['slick'].defaults = { 667 initialSlide: 0, 668 autoplay: true, 669 autoplaySpeed: 5000 670 }; 671 672 /** 673 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ Ð¿ÐµÑеклÑÑаÑÐµÐ»Ñ Ð² виде закладок (Ñабов) 674 * ÐÑимеÑнÑй markup: 675 * <div class="widget tabpane"> 676 * <ul class="tabs"> 677 * <li><a class="fake" href="#tab-1">Tab 1</a></li> 678 * <li><a class="fake" href="#tab-2">Tab 2</a></li> 679 * </ul> 680 * <div class="panes"> 681 * <div id="tab-1" class="pane">Content 1</div> 682 * <div id="tab-2" class="pane">Content 2</div> 683 * </div> 684 * </div> 685 * 686 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 687 * @return void 688 */ 689 this.items['tabpane'] = function(selector) 690 { 691 var defaults = indi.ui.widgets.items.tabpane.defaults; 692 693 $(selector).each(function() { 694 //ÐÐ¸Ð´Ð¶ÐµÑ 695 var tabPane = $(this); 696 697 //ÐонÑигÑÑаÑÐ¸Ñ 698 var config = $.extend( 699 {}, 700 defaults, 701 tabPane.data('config') || {} 702 ); 703 704 //ÐÑÐµÑ ÐºÐ¾Ð½ÑÑÐ¾Ð»Ð»ÐµÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ¸ Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñм hash 705 var findTabController = function(hash) { 706 return tabPane.find(config.tabsSelector + ' a[href="' + hash + '"]'); 707 }; 708 709 //ÐкÑивиÑÑÐµÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñм hash 710 var activateTab = function(hash, reason) { 711 if (hash.substr(0, 1) != '#') { 712 if (reason == 'click') { 713 document.location.href = hash; 714 } 715 return; 716 } 717 var controller = findTabController(hash); 718 var item = controller.closest('li').length ? controller.closest('li') : controller; 719 item 720 .addClass('active') 721 .siblings().removeClass('active'); 722 723 tabPane.find(config.tabsSelector + ' a').each(function() { 724 var href = $(this).attr('href'); 725 if (href.substr(0, 1) == '#') { 726 var pane = tabPane.find( 727 config.panesSelector + href 728 ); 729 if (this === controller.get(0)) { 730 pane 731 .show() 732 .trigger('widget.tabpane:show') 733 } else { 734 pane 735 .hide() 736 .trigger('widget.tabpane:hide'); 737 } 738 } 739 }); 740 741 //ÐÑли Ð²Ð¸Ð´Ð¶ÐµÑ Ð² виджеÑе, Ñо нÑжно запÑÑÑиÑÑ ÑепоÑÐºÑ Ð¿ÐµÑеклÑÑений ввеÑÑ Ð¿Ð¾ DOM 742 if (!tabPane.is(':visible')) { 743 tabPane.closest(config.panesSelector).trigger('widget.tabpane:activate'); 744 } 745 }; 746 747 //СобÑÑие акÑиваÑии, позволÑÐµÑ ÑпÑавлÑÑÑ Ð²Ð¸Ð´Ð¶ÐµÑом извне 748 tabPane.on('widget.tabpane:activate', function(event) { 749 var id = $(event.target).attr('id'); 750 if (id) { 751 activateTab('#' + id, 'activate'); 752 } 753 }); 754 755 //ÐлаÑÑ Ð·Ð°ÐºÐ»Ð°Ð´Ð¾Ðº 756 if (config.tabsClass) { 757 tabPane.find(config.tabsSelector).addClass(config.tabsClass); 758 } 759 760 //Ðлики по закладкам 761 tabPane.find(config.tabsSelector + ' a').click(function(event) { 762 if (event.isPropagationStopped()) { 763 return false;
764 } 765 event.stopPropagation(); 766 767 activateTab($(this).attr('href'), 'click'); 768 769 return false; 770 }); 771 772 //Ðлики по ÑодиÑелÑм закладок 773 if (config.tabsHandleParents) { 774 tabPane.find(config.tabsSelector + ' a').parent().click(function(event) { 775 $(this).find('a').trigger('click'); 776 }); 777 } 778 779 //ÐлаÑÑ Ð¿Ð°Ð½ÐµÐ»ÐµÐ¹ 780 if (config.panesClass) { 781 tabPane.find(config.panesSelector).addClass(config.panesClass); 782 } 783 784 //Ðаголовки панелей 785 if (config.panesTitleAdd) { 786 tabPane.find(config.tabsSelector + ' a').each(function() { 787 var href = $(this).attr('href'); 788 if (href.substr(0, 1) == '#') { 789 var pane = tabPane.find( 790 config.panesSelector + href 791 ); 792 $('<' + config.panesTitleTag + '/>') 793 .addClass(config.panesTitleClass) 794 .html($(this).html()) 795 .prependTo(pane); 796 } 797 }); 798 } 799 800 //ÐкÑÐ¸Ð²Ð½Ð°Ñ Ð¿Ð¾ ÑмолÑÐ°Ð½Ð¸Ñ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ° 801 var activeTabLink = null; 802 if (config.followHash) { 803 activeTabLink = findTabController(document.location.hash); 804 } 805 if (!activeTabLink || !activeTabLink.length) { 806 activeTabLink = tabPane.find(config.tabsSelector + ' a:first'); 807 }
808 if (activeTabLink.length) { 809 activateTab(activeTabLink.attr('href'), 'init'); 810 } 811 }); 812 }; 813 814 this.items['tabpane'].defaults = { 815 tabsSelector: '> .tabs',//СелекÑÐ¾Ñ Ð·Ð°ÐºÐ»Ð°Ð´Ð¾Ðº 816 tabsClass: '',//ÐобавиÑÑ ÐºÐ»Ð°ÑÑ Ð´Ð»Ñ Ð·Ð°ÐºÐ»Ð°Ð´Ð¾Ðº 817 tabsHandleParents: true,//ÐÑÑлеживаÑÑ ÐºÐ»Ð¸ÐºÐ¸ по ÑодиÑелÑм ÑÑÑлок в Ð·Ð°ÐºÐ»Ð°Ð´ÐºÐ°Ñ 818 panesSelector: '> .panes > .pane',//СелекÑÐ¾Ñ Ð¿Ð°Ð½ÐµÐ»ÐµÐ¹ 819 panesClass: '',//ÐобавиÑÑ ÐºÐ»Ð°ÑÑ Ð² каждÑÑ Ð¿Ð°Ð½ÐµÐ»Ñ 820 panesTitleAdd: false,//ÐобавлÑÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº пеÑед панелÑми 821 panesTitleTag: 'h2',//Тег Ð´Ð»Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ° панели 822 panesTitleClass: 'pane-title',//ÐлаÑÑ Ð´Ð»Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ° панели 823 followHash: true//ÐкÑивиÑоваÑÑ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ Ð¿Ð¾ hash в document.location 824 }; 825 826 /** 827 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ ÑаблиÑÑ Ñ thead, ÑикÑиÑÑÑÑимÑÑ Ð¿Ñи пÑокÑÑÑке докÑменÑа в окне бÑаÑзеÑа 828 * 829 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 830 * @return void 831 */ 832 this.items['fixedtable'] = function(selector) 833 { 834 $(selector).each(function() { 835 var table = $(this); 836 var thead = table.find('> thead').eq(0); 837 var isFixed = null; 838 839 var applyWidth = function(cell) { 840 cell.find('> div').width(cell.width()); 841 }; 842 843 var onScroll = function() { 844 var scrollTop = $(window).scrollTop(); 845 var offset = table.offset(); 846 847 if ( 848 scrollTop > offset.top 849 && scrollTop < offset.top + table.height() - thead.height() 850 ) { 851 if(isFixed !== true) { 852 isFixed = true; 853 thead.css({'position': 'fixed'}); 854 } 855 } else { 856 if (isFixed !== false) { 857 isFixed = false; 858 thead.css({'position': 'absolute'}); 859 } 860 } 861 }; 862 863 table.css('position', 'relative'); 864 865 thead 866 .width(thead.width()) 867 .height(thead.height()); 868 869 table.find('> thead > tr > *, > tbody > tr > *').wrapInner( 870 $('<div>') 871 .addClass('fixedtable-cell-wrapper') 872 .css('min-height', '1px') 873 ); 874 table.find('> thead > tr > *').each(function() { 875 applyWidth($(this)); 876 }); 877 table.find('> tbody > tr:first > *').each(function() { 878 applyWidth($(this)); 879 }); 880 881 var theadPlacheholder = thead 882 .clone() 883 .css('visibility', 'hidden'); 884 theadPlacheholder.insertAfter(thead); 885 886 thead.css({'top': '0'}); 887 888 $(window).scroll(onScroll); 889 onScroll(); 890 }); 891 }; 892 893 /** 894 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ ÑаблиÑÑ Ñ Ð¸Ð½ÑеÑлейÑом 895 * 896 * @param string|object selector СелекÑÐ¾Ñ Ñзлов DOM 897 * @return void 898 */ 899 this.items['interlace'] = function(selector) 900 { 901 $(selector).find('tr:even').addClass('even'); 902 $(selector).find('tr:odd').addClass('odd'); 903 }; 904 905 /** 906 * ÐниÑиализиÑÑÐµÑ Ð²Ð¸Ð´Ð¶ÐµÑÑ 907 * 908 * @param string selector РодиÑелÑÑкий ÑÐ»ÐµÐ¼ÐµÐ½Ñ 909 * @return void 910 */ 911 this.init = function(selector) 912 { 913 if (selector === undefined) { 914 selector = $('body'); 915 } else { 916 selector = $(selector); 917 } 918 919 $.each(this.items, function(name) { 920 this.call(this, selector.find('.widget.' + name)); 921 }); 922 }; 923}; 924 925 926 927 928/** 929 * XXX: Ð¡Ð¾Ð·Ð´Ð°ÐµÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¾Ñ Ð·Ð°Ð³ÑÑзки 930 * ÐÑÐ¸Ð¼ÐµÑ Ð¸ÑполÑзованиÑ: 931 * var loading = new indi.ui.loading('#content'); 932 * ... 933 * loading.hide(); 934 * 935 * @param string|object selector СелекÑÐ¾Ñ ÑлеменÑа, Ñ ÐºÐ¾ÑоÑого оÑобÑажаеÑÑÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¾Ñ 936 * @return void 937 */ 938indi.ui.loading = function(selector) 939{ 940 if (indi.ui.loading.template === undefined) { 941 indi.ui.loading.template = '<div class="loading-layer"></div>' + 942 '<div class="loading-icon">' + 943 $('#loading-indicator-template').html() + 944 '</div>'; 945 } 946 947 /** 948 * ÐоказÑÐ²Ð°ÐµÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¾Ñ Ð·Ð°Ð³ÑÑзки 949 * 950 * @return void 951 */ 952 this.show = function() 953 { 954 $(selector) 955 .addClass('loading-indicator') 956 .append(indi.ui.loading.template); 957 }; 958 959 /** 960 * СкÑÑÐ²Ð°ÐµÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¾Ñ Ð·Ð°Ð³ÑÑзки 961 * 962 * @return void 963 */ 964 this.hide = function() 965 { 966 $(selector) 967 .removeClass('loading-indicator') 968 .find('> .loading-layer, > .loading-icon').remove(); 969 }; 970 971 selector = selector || 'body'; 972 973 this.show(); 974}; 975 976/** 977 * XXX: РабоÑа Ñ Ð¸ÑÑоÑией бÑаÑзеÑа 978 * 979 * @param string callback ÐÐ¼Ñ Ñ-ии обÑаÑного вÑзова, вÑзÑваемой пÑи пеÑÐµÑ Ð¾Ð´Ð°Ñ Ð¿Ð¾ иÑÑоÑии 980 * @param object data ÐаннÑе ÑекÑÑей ÑÑÑаниÑÑ 981 */ 982indi.history = function(callback, data) 983{ 984 /** 985 * ФоÑмиÑÑÐµÑ history state 986 * 987 * @param object data State data 988 * @return object 989 */ 990 var buildState = function(data) 991 { 992 var state = { 993 data: data instanceof Object ? data : {} 994 }; 995 996 if (state.data.title === undefined) { 997 state.data.title = document.title; 998 } 999 1000 state.generatedByIndiHistory = true; 1001 state.handledBy = callback; 1002 1003 return state; 1004 }; 1005 1006 /** 1007 * XXX: ÐобавлÑÐµÑ Ð¾Ð±ÑабоÑÑик бÑаÑзеÑного ÑобÑÑÐ¸Ñ 1008 * 1009 * @return void 1010 */ 1011 var addListener = function() 1012 { 1013 if (window.addEventListener) { 1014 window.addEventListener('popstate', function(event) { 1015 //ÐÑопÑÑкаем ÑобÑÑиÑ, ÑозданнÑе не ÑеÑез indi.history (напÑимеÑ, Chrome Ñакие генеÑиÑÑеÑ) 1016 if (!(event.state instanceof Object) 1017 || event.state.generatedByIndiHistory === undefined 1018 ) { 1019 return; 1020 } 1021 1022 if (event.state.data !== undefined 1023 && event.state.data.title !== undefined 1024 ) { 1025 document.title = event.state.data.title; 1026 } 1027 1028 //ÐеÑгаем Ñ-ии обÑаÑного вÑзова ÑолÑко Ð´Ð»Ñ ÑÐ²Ð¾Ð¸Ñ Ñ Ð¾Ð·Ñев 1029 if (event.state.handledBy && event.state.handledBy == callback) { 1030 (new Function( 1031 'url, data', 1032 event.state.handledBy + '(url, data);' 1033 ))( 1034 document.location.href, 1035 event.state.data 1036 ); 1037 } 1038 }, false); 1039 } 1040 }; 1041 1042 /** 1043 * XXX: ÐозвÑаÑÐ°ÐµÑ ÑекÑÑий пÑÐ½ÐºÑ Ð¸ÑÑоÑии 1044 * 1045 * @return object 1046 */ 1047 this.current = function() 1048 { 1049 return history.state; 1050 }; 1051 1052 /** 1053 * XXX: ÐбновлÑÐµÑ ÑекÑÑий пÑÐ½ÐºÑ Ð¸ÑÑоÑии 1054 * 1055 * @param string url URL 1056 * @param object data ÐаннÑе 1057 * @return void 1058 */ 1059 this.replace = function(url, data) 1060 { 1061 if (history.replaceState) { 1062 var state = buildState(data); 1063 1064 history.replaceState(state, state.data.title, indi.utils.url.getFull(url)); 1065 } 1066 }; 1067 1068 /** 1069 * XXX: ÐобавлÑÐµÑ Ð½Ð¾Ð²Ñй пÑÐ½ÐºÑ Ð² иÑÑоÑÐ¸Ñ 1070 * 1071 * @param string url URL 1072 * @param object data ÐаннÑе 1073 * @return void 1074 */ 1075 this.push = function(url, data) 1076 { 1077 if (history.pushState) { 1078 var state = buildState(data); 1079 1080 history.pushState(state, state.data.title, indi.utils.url.getFull(url)); 1081 } 1082 }; 1083 1084 1085 1086
1087 /** 1088 * ÐниÑÐ¸Ð°Ð»Ð¸Ð·Ð¸Ñ 1089 */ 1090 this.replace(document.location.href, data); 1091 1092 addListener(); 1093}; 1094 1095/** 1096 * ÐозволÑÐµÑ Ð¿Ð¾Ð»ÑÑиÑÑ singleton instance indi.history 1097 * 1098 * @param string callback ÐÐ¼Ñ Ñ-ии обÑаÑного вÑзова, вÑзÑваемой пÑи пеÑÐµÑ Ð¾Ð´Ð°Ñ 1099 * @param object data ÐаннÑе ÑекÑÑей ÑÑÑаниÑÑ 1100 * 1101 * @return indi.history 1102 */ 1103indi.history.getInstance = function(callback, data) 1104{ 1105 if (this.instances === undefined) { 1106 this.instances = {}; 1107 } 1108 1109 if (this.instances[callback] === undefined) { 1110 this.instances[callback] = new indi.history(callback, data); 1111 } 1112 1113 return this.instances[callback]; 1114}; 1115 1116 1117 1118 1119/** 1120 * XXX: УÑилиÑÑ Ð´Ð»Ñ ÑабоÑÑ Ñ Cookie 1121 */ 1122indi.cookie = { 1123 /** 1124 * XXX: Set cookie 1125 * 1126 * @param string name Cookie name 1127 * @param string value Cookie value 1128 * @param string time Lifetime 1129 * @param string path 1130 * @return void 1131 */ 1132 set: function(name, value, time, path) 1133 { 1134 var time = time === undefined ? 0 : time; 1135 var path = path === undefined ? '/' : path; 1136 1137 var expires = new Date(); 1138 time = expires.getTime() + time * 1000; 1139 expires.setTime(time); 1140 1141 document.cookie = name + '=' + value + '; expires=' + expires.toGMTString() + '; path=' + path; 1142 }, 1143 1144 /** 1145 * XXX: Get cookie 1146 * 1147 * @param string name Cookie name 1148 * @return string Cookie value 1149 */ 1150 get: function(name) 1151 { 1152 var cookie = ' ' + document.cookie; 1153 var search = ' ' + name + '='; 1154 var setStr = null; 1155 var offset = 0; 1156 var end = 0; 1157 if (cookie.length > 0) { 1158 offset = cookie.indexOf(search); 1159 if (offset != -1) { 1160 offset += search.length; 1161 end = cookie.indexOf(';', offset); 1162 if (end == -1) { 1163 end = cookie.length; 1164 } 1165 setStr = unescape(cookie.substring(offset, end)); 1166 } 1167 } 1168 1169 return setStr; 1170 } 1171}; 1172 1173 1174 1175 1176/** 1177 * XXX: User-agent полÑзоваÑÐµÐ»Ñ 1178 */ 1179indi.ua = new function() 1180{ 1181 /** 1182 * User agent - iPad 1183 * 1184 * @var boolean 1185 */ 1186 this.isIPad = /iPad/.test(navigator.userAgent); 1187 1188 /** 1189 * User agent - iPhone 1190 * 1191 * @var boolean 1192 */ 1193 this.isIPhone = /iPhone/.test(navigator.userAgent); 1194 1195 /** 1196 * User agent - iPod 1197 * 1198 * @var boolean 1199 */ 1200 this.isIPod = /iPod/.test(navigator.userAgent); 1201 1202 /** 1203 * User agent - iOS 1204 * 1205 * @var boolean 1206 */ 1207 this.isIOS = this.isIPad || this.isIPhone || this.isIPod; 1208 1209 /** 1210 * User agent - Android 1211 * 1212 * @var boolean 1213 */ 1214 this.isAndroid = /Android/.test(navigator.userAgent); 1215 1216 /** 1217 * User agent ÑабоÑÐ°ÐµÑ Ð½Ð° WebKit 1218 * 1219 * @var boolean 1220 */ 1221 this.isWebKit = /WebKit/.test(navigator.userAgent); 1222 1223 /** 1224 * User agent поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ Ñоuch инÑеÑÑÐµÐ¹Ñ 1225 * 1226 * @var boolean 1227 */ 1228 this.isTouchable = function() 1229 { 1230 var result = (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch); 1231 this.isTouchable = function() { 1232 return result; 1233 }; 1234 return result; 1235 }; 1236}; 1237 1238 1239 1240 1241/** 1242 * XXX: УÑилиÑÑ 1243 */ 1244indi.utils = { 1245 /** 1246 * XXX: ÐаÑледÑÐµÑ Ð¾Ð´Ð¸Ð½ клаÑÑ Ð¾Ñ Ð´ÑÑгого 1247 * 1248 * @param object child ÐоÑомок 1249 * @param object parent РодиÑÐµÐ»Ñ 1250 * @param object overrides ÐеÑезапиÑÑваемÑе Ñв-ва и меÑÐ¾Ð´Ñ 1251 * @return object ÐоÑомок 1252 */ 1253 extend: function(child, parent, overrides) 1254 { 1255 if (typeof parent == 'object') { 1256 overrides = parent; 1257 parent = child; 1258 child = function() { 1259 child.superclass.constructor.apply(this, arguments) 1260 }; 1261 } 1262 1263 var f = function(){}; 1264 f.prototype = parent.prototype; 1265 child.prototype = new f(); 1266 child.prototype.constructor = child; 1267 child.superclass = parent.prototype; 1268 1269 this.override(child, overrides); 1270 1271 return child; 1272 }, 1273 1274 /** 1275 * XXX: ÐеÑезапиÑÑÐ²Ð°ÐµÑ Ñв-ва и меÑÐ¾Ð´Ñ ÐºÐ»Ð°ÑÑа 1276 * 1277 * @param object clss ÐеÑезапиÑÑваемÑй клаÑÑ 1278 * @param object parent РодиÑÐµÐ»Ñ 1279 * @param object overrides ÐеÑезапиÑÑваемÑе Ñв-ва и меÑÐ¾Ð´Ñ 1280 * @return void 1281 */ 1282 override: function(clss, overrides) 1283 { 1284 this.apply(clss.prototype, overrides); 1285 }, 1286 1287 /** 1288 * XXX: РаÑÑиÑÑÐµÑ Ñво-ва одного обÑекÑа дÑÑгим 1289 * 1290 * @param object object РаÑÑиÑÑемÑй обÑÐµÐºÑ 1291 * @param object overrides ÐеÑезапиÑÑваемÑе Ñв-ва 1292 * @return void 1293 */ 1294 apply: function(object, overrides) 1295 { 1296 overrides = overrides || {}; 1297 var primitiveObject = {}; 1298 for (var i in overrides) { 1299 if (typeof primitiveObject[i] == 'undefined' || primitiveObject[i] != overrides[i]) { 1300 object[i] = overrides[i]; 1301 } 1302 } 1303 }, 1304 1305 /** 1306 * XXX: ÐозвÑаÑÐ°ÐµÑ ÑникалÑнÑй ID 1307 * 1308 * @return integer|string 1309 */ 1310 getId: function(prefix) 1311 { 1312 return prefix + (new Date().getTime()) + Math.floor(999 * Math.random()); 1313 }, 1314 1315 /** 1316 * XXX: ÐаменÑÐµÑ Ð² Ñаблоне конÑÑÑÑкÑии {name} на знаÑÐµÐ½Ð¸Ñ Ð¸Ð· обÑекÑа Ñ Ð´Ð°Ð½Ð½Ñми 1317 * ÐÑимеÑ: 1318 * indi.utils.parse('<a href="{url}">{title}</a>', {url: 'http://my.server/', title: 'My link'}); 1319 * 1320 * @param string template Шаблон 1321 * @param object data ÐаннÑе 1322 * @param string def ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ 1323 * @return string 1324 */ 1325 parse: function(template, data, def) 1326 { 1327 def = def || ''; 1328 return template.replace(/{([^}]*)}/gm, function() { 1329 return arguments.length > 1 ? data[arguments[1]] : ''; 1330 }); 1331 }, 1332 1333 /** 1334 * XXX: ÐозвÑаÑÐ°ÐµÑ ÑекÑÑ Ð² аÑÑибÑÑе href гипеÑÑÑÑлки, ÑÑоÑÑий поÑле # 1335 * УÑиÑÑÐ²Ð°ÐµÑ Ð±Ð°Ð³ IE, коÑоÑÑй вÑÐ´Ð°ÐµÑ Ð¿Ð¾Ð»Ð½Ñй URL Ð´Ð»Ñ Ð°ÑÑибÑÑа href 1336 * 1337 * @param object|string link ÐлеменÑ-ÑÑÑлка 1338 * @return string 1339 */ 1340 getHashWord: function(link) 1341 { 1342 return $(link).attr('href').replace(/^.*#/, '#'); 1343 }, 1344 1345 /** 1346 * XXX: ÐÑедзагÑÑзÑик изобÑажений Ñ Ð¿Ð¾Ð´Ð´ÐµÑжкой jQuery deferred 1347 * ÐÑимеÑ: 1348 * $.when( 1349 * indi.utils.preloadImage(src1), 1350 * indi.utils.preloadImage([src2, src3]) 1351 * ).done(function() 1352 * { 1353 * //Images are preloaded 1354 * }); 1355 * 1356 * @param string|array|jQuery sources ÐдÑеÑ(а) изобÑажений 1357 * @return object 1358 */ 1359 preloadImage: function(sources) 1360 { 1361 if (sources instanceof jQuery) { 1362 var urls = []; 1363 sources.each(function() { 1364 if ($(this).is('img')) { 1365 urls.push($(this).attr('src')); 1366 } else if ($(this).is('a')) { 1367 urls.push($(this).attr('href')); 1368 } 1369 }); 1370 return this.preloadImage(urls); 1371 } 1372 1373 if (!(sources instanceof Array)) { 1374 sources = [sources]; 1375 } 1376 1377 var defer = $.Deferred(); 1378 var images = {}; 1379 var totalCount = 0; 1380 for (var i = 0; i < sources.length; i++) { 1381 var url = sources[i]; 1382 var id = 'id' + url.replace(/[^A-z0-9]/g, ''); 1383 if (images[id] === undefined) { 1384 images[id] = { 1385 image: new Image(), 1386 url: url 1387 }; 1388 totalCount++; 1389 } 1390 } 1391 var loadedCount = 0; 1392 for (var id in images) { 1393 images[id].image.onload = function() { 1394 if (++loadedCount >= totalCount) { 1395 defer.resolve(); 1396 } 1397 }; 1398 images[id].image.src = images[id].url; 1399 } 1400 1401 return defer.promise(); 1402 }, 1403 1404 /** 1405 * XXX: СклонÑÐµÑ ÑÑÑеÑÑвиÑелÑное Ñ ÑиÑлиÑелÑнÑм 1406 * 1407 * @param integer number ЧиÑло 1408 * @param array cases ÐаÑианÑÑ ÑÑÑеÑÑвиÑелÑного в ÑазнÑÑ Ð¿Ð°Ð´ÐµÐ¶Ð°Ñ Ð¸ ÑиÑÐ»Ð°Ñ (nominativ, genetiv, plural). ÐÑимеÑ: ['комменÑаÑий', 'комменÑаÑиÑ', 'комменÑаÑиев'] 1409 * @param boolean incNum ÐобавиÑÑ Ñамо ÑиÑло в ÑезÑлÑÑÐ°Ñ (по ÑмолÑÐ°Ð½Ð¸Ñ true) 1410 * @return string 1411 */ 1412 getNumEnding: function(number, cases, incNum) 1413 { 1414 var numberMod = number % 100; 1415 incNum = incNum === undefined ? true : incNum; 1416 var result = ''; 1417 1418 if (numberMod >= 11 && numberMod <= 19) { 1419 result = cases[2]; 1420 } else { 1421 numberMod = numberMod % 10; 1422 switch (numberMod) { 1423 case 1: 1424 result = cases[0]; 1425 break; 1426 case 2: 1427 case 3:
1428 case 4: 1429 result = cases[1]; 1430 break; 1431 default: 1432 result = cases[2]; 1433 } 1434 } 1435 1436 return incNum ? number + ' ' + result : result; 1437 }, 1438 1439 /** 1440 * XXX: ФоÑмаÑиÑÑÐµÑ ÑиÑло 1441 * 1442 * @param mixed number ЧиÑло 1443 * @param integer decimals Ðол-во знаков поÑле запÑÑой (по ÑмолÑÐ°Ð½Ð¸Ñ 0) 1444 * @param string decPoint РазделиÑÐµÐ»Ñ Ñелой и дÑобной ÑаÑÑи (по ÑмолÑÐ°Ð½Ð¸Ñ '.') 1445 * @param string thousandsSep РазделиÑÐµÐ»Ñ ÑоÑен (по ÑмолÑÐ°Ð½Ð¸Ñ '`') 1446 * @return string 1447 */ 1448 numberFormat: function(number, decimals, decPoint, thousandsSep) 1449 { 1450 number = (number + '').replace(/[^0-9+\-Ee.]/g, ''); 1451 var n = !isFinite(+number) ? 0 : +number, 1452 prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), 1453 sep = (typeof thousandsSep === 'undefined') ? '`' : thousandsSep, 1454 dec = (typeof decPoint === 'undefined') ? '.' : decPoint, 1455 s = '', 1456 toFixedFix = function(n, prec) { 1457 var k = Math.pow(10, prec); 1458 return '' + Math.round(n * k) / k; 1459 }; 1460 1461 // Fix for IE parseFloat(0.55).toFixed(0) = 0; 1462 s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.'); 1463 1464 if (s[0].length > 3) { 1465 s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); 1466 } 1467 if ((s[1] || '').length < prec) { 1468 s[1] = s[1] || ''; 1469 s[1] += new Array(prec - s[1].length + 1).join('0'); 1470 } 1471 1472 return s.join(dec); 1473 } 1474}; 1475 1476/** 1477 * XXX: УÑилиÑÑ Ð´Ð»Ñ ÑабоÑÑ Ñ URL 1478 */ 1479indi.utils.url = 1480{ 1481 /** 1482 * XXX: ÐозвÑаÑÐ°ÐµÑ Ð¿Ð¾Ð»Ð½Ñй URL ÑекÑÑей ÑÑÑаниÑÑ, вклÑÑÐ°Ñ Ð´Ð¾Ð¼ÐµÐ½ и пÑоÑоколÑнÑй пÑеÑÐ¸ÐºÑ 1483 * 1484 * @param string path Pathname 1485 * @return string 1486 */ 1487 getFull: function(path) 1488 { 1489 return path.search('//') == -1 ? 1490 document.location.protocol + '//' + document.location.host + path 1491 : 1492 path; 1493 }, 1494 1495 /** 1496 * XXX: РазбиÑÐ°ÐµÑ URL на ÑаÑÑи 1497 * 1498 * @param string url URL 1499 * @return object {protocol, host, port, pathname, query, hash} 1500 */ 1501 parse: function(url) 1502 { 1503 var result = { 1504 protocol: '', 1505 host: '', 1506 port: '', 1507 pathname: '', 1508 query: '', 1509 hash: '' 1510 } 1511 1512 //Get protocol 1513 url = url.split('://'); 1514 if (url.length > 1) { 1515 result.protocol = url.shift(); 1516 url[0] = '//' + url[0]; 1517 } 1518 url = url.join('://'); 1519 1520 //Get host 1521 url = url.split('//'); 1522 if (url.length > 1) { 1523 url.shift(); 1524 url = url.join('//').split('/'); 1525 result.host = url.shift(); 1526 url = '/' + url.join('/'); 1527 } else { 1528 url = url.join('//'); 1529 } 1530 1531 //Get port 1532 result.host = result.host.split(':'); 1533 if (result.host.length > 1) { 1534 result.port = result.host.pop(); 1535 } 1536 result.host = result.host.join(':'); 1537 1538 //Get hash 1539 url = url.split('#'); 1540 if (url.length > 1) { 1541 result.hash = url.pop(); 1542 } 1543 url = url.join('#'); 1544 1545 //Get query 1546 url = url.split('?'); 1547 if (url.length > 1) { 1548 result.query = url.pop(); 1549 } 1550 url = url.join('?'); 1551 1552 //Get path 1553 result.pathname = url; 1554 1555 return result; 1556 } 1557};
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.