1/* masalygin 0.0.2 */ 2'use strict'; 3 4(function (factory) { 5 6 if (typeof define === 'function' && define.amd) { 7 8 define(['jquery', 's3/misc/math/0.0.1/s3.math', 's3/misc/eventable/0.0.1/s3.eventable'], factory); 9 10 } else { 11 12 factory(jQuery, s3Math); 13 14 } 15 16})(function ($, math) { 17 18 function debug(menu) { 19 20 var points = {}; 21 22 $.each(['a', 'b', 'c'], function (key, value) { 23 24 var attr = { 25 id: 's3-menu-allin-point-' + value, 26 'class': 's3-menu-allin-point', 27 html: value 28 }; 29 30 points[value] = $('<div></div>', attr); 31 32 $(document.body).append(points[value]); 33 34 }); 35 36 setInterval(function () { 37 38 $.each(points, function (name, point) { 39 40 point.css({ 41 left: menu.triangle[name].x, 42 top: menu.triangle[name].y 43 }); 44 45 }); 46 47 }, 0); 48 49 } 50 51 var popupEvents = { 52 53 activate: function (params) { 54 55 var $siblings = params.$item.siblings(); 56 params.$item.addClass(this.settings.activeClass); 57 $siblings.removeClass(this.settings.activeClass); 58 this.hide($siblings.children('ul')); 59 this.show(params.$sub); 60 this.hide(params.$sub.find('ul')); 61 62 }, 63 64 deactivate: function (params, c) { 65 66 params.$item.removeClass(this.settings.activeClass); 67 this.hide(params.$sub); 68 69 }, 70 71 exit: function () { 72 73 this.$li.removeClass(this.settings.activeClass); 74 this.hide(this.$ul); 75 76 } 77 78 }; 79 80 81 function dropdownPlus(menu, direction) { 82 83 var $el = menu.$el.children('li'); 84 85 var dropDownMenu = $.extend({}, menu, { 86 $el: $el 87 }); 88 89 $.s3MenuAllInTypes.dropdown(dropDownMenu, '> a'); 90 91 $el.children('ul').s3MenuAllIn($.extend({}, menu.settings, {type: direction})); 92 93 } 94 95 $.s3MenuAllInTypes = { 96 97 bottom: function (menu) { 98 99 menu.on('activate', function (params) { 100 101 var winWidth = $(window).width(); 102 103 var $sub = params.$sub; 104 var $item = params.$item; 105 var isHidden = $sub.is(':hidden'); 106 107 $sub.removeClass(this.settings.revertClass); 108 $sub.show(); 109 110 var iPos = $item.position(); 111 var iOffset = $item.offset(); 112 var iWidth = $item.width(); 113 var sWidth = $sub.width(); 114 var sPos = {}; 115 116 var b = this.triangle.b; 117 var c = this.triangle.c; 118 119 var left; 120 var revert = false; 121 122 if (params.level === 1) { 123 124 left = iOffset.left + sWidth; 125 126 if (left > winWidth) { 127 128 sPos.left = iPos.left + iWidth - sWidth; 129 130 } else { 131 132 sPos.left = iPos.left; 133 134 } 135 136 sPos.top = iPos.top + $item.height(); 137 138 } else { 139 140 left = iOffset.left + iWidth + sWidth; 141 142 if (left > winWidth) { 143 144 sPos.left = iPos.left - sWidth; 145 revert = true; 146 147 } else { 148 149 sPos.left = iPos.left + iWidth; 150 151 } 152 153 sPos.top = iPos.top; 154 155 } 156 157 $sub.css(sPos); 158 159 var sOffset = $sub.offset(); 160 161 if (params.level === 1) { 162 163 b.y = c.y = sOffset.top; 164 b.x = sOffset.left; 165 c.x = sOffset.left + sWidth; 166 167 } else { 168 169 b.y = sOffset.top; 170 c.y = sOffset.top + $sub.height(); 171 b.x = c.x = revert ? sOffset.left + sWidth : sOffset.left; 172 173 } 174 175 if (revert) { 176 $sub.addClass(this.settings.revertClass); 177 } 178 179 if (isHidden) { 180 $sub.hide(); 181 } 182 183 184 }); 185 186 menu.on(popupEvents); 187 188 }, 189 190 top: function (menu) { 191 192 menu.on('activate', function (params) { 193 194 var winWidth = $(window).width(); 195 196 var $sub = params.$sub; 197 var $item = params.$item; 198 var isHidden = $sub.is(':hidden'); 199 200 $sub.removeClass(this.settings.revertClass); 201 $sub.show(); 202 203 var iPos = $item.position(); 204 var iOffset = $item.offset(); 205 var iWidth = $item.width(); 206 var iHeight = $item.height(); 207 var sWidth = $sub.width(); 208 var sHeight = $sub.height(); 209 var sPos = {}; 210 211 var b = this.triangle.b; 212 var c = this.triangle.c; 213 214 var left; 215 var revert = false; 216 217 if (params.level === 1) { 218 219 left = iOffset.left + sWidth; 220 221 if (left > winWidth) { 222 223 sPos.left = iPos.left + iWidth - sWidth; 224 225 } else { 226 227 sPos.left = iPos.left; 228 229 } 230 231 sPos.top = iPos.top - sHeight; 232 233 } else { 234 235 left = iOffset.left + iWidth + sWidth; 236 237 if (left > winWidth) { 238 239 sPos.left = iPos.left - sWidth; 240 revert = true; 241 242 } else { 243 244 sPos.left = iPos.left + iWidth; 245 246 } 247 248 sPos.top = iPos.top - sHeight + iHeight; 249 250 } 251 252 $sub.css(sPos); 253 254 var sOffset = $sub.offset(); 255 256 if (params.level === 1) { 257 258 b.y = c.y = sOffset.top + sHeight;
259 b.x = sOffset.left; 260 c.x = sOffset.left + sWidth; 261 262 } else { 263 264 b.y = sOffset.top; 265 c.y = sOffset.top + $sub.height(); 266 b.x = c.x = revert ? sOffset.left + sWidth : sOffset.left; 267 268 } 269 270 if (revert) { 271 $sub.addClass(this.settings.revertClass); 272 } 273 274 if (isHidden) { 275 $sub.hide(); 276 } 277 278 }); 279 280 menu.on(popupEvents); 281 282 }, 283 284 right: function (menu) { 285 286 menu.on('activate', function (params) { 287 288 var winWidth = $(window).width(); 289 290 var $sub = params.$sub; 291 var $item = params.$item; 292 var isHidden = $sub.is(':hidden'); 293 294 $sub.show(); 295 296 var iPos = $item.position(); 297 var iOffset = $item.offset(); 298 var iWidth = $item.width(); 299 var sWidth = $sub.width(); 300 var sPos = {}; 301 302 var b = this.triangle.b; 303 var c = this.triangle.c; 304 305 var left; 306 var revert = false; 307 308 left = iOffset.left + iWidth + sWidth; 309 310 sPos.top = iPos.top; 311 312 if (left > winWidth) { 313 314 sPos.left = iPos.left - sWidth; 315 revert = true; 316 317 } else { 318 319 sPos.left = iPos.left + iWidth; 320 321 } 322 323 $sub.css(sPos); 324 325 var sOffset = $sub.offset(); 326 327 b.y = sOffset.top; 328 c.y = sOffset.top + $sub.height(); 329 b.x = c.x = revert ? sOffset.left + sWidth : sOffset.left; 330 331 if (isHidden) { 332 $sub.hide(); 333 } 334 335 336 }); 337 338 menu.on(popupEvents); 339 340 }, 341 342 left: function (menu) { 343 344 menu.on('activate', function (params) { 345 346 var $sub = params.$sub; 347 var $item = params.$item; 348 var isHidden = $sub.is(':hidden'); 349 350 $sub.show(); 351 352 var iPos = $item.position(); 353 var iOffset = $item.offset(); 354 var iWidth = $item.width(); 355 var sWidth = $sub.width(); 356 var sPos = {}; 357 358 var b = this.triangle.b; 359 var c = this.triangle.c; 360 361 var left; 362 var revert = false; 363 364 left = iOffset.left - sWidth; 365 366 sPos.top = iPos.top; 367 368 if (left < 0) { 369 370 sPos.left = iPos.left + sWidth; 371 revert = true; 372 373 } else { 374 375 sPos.left = iPos.left - iWidth; 376 377 } 378 379 $sub.css(sPos); 380 381 var sOffset = $sub.offset(); 382 383 b.y = sOffset.top; 384 c.y = sOffset.top + $sub.height(); 385 b.x = c.x = revert ? sOffset.left : sOffset.left + sWidth; 386 387 if (isHidden) { 388 $sub.hide(); 389 } 390 391 }); 392 393 menu.on(popupEvents); 394 395 }, 396 397 dropdown: function (menu, selector) { 398 399 selector = selector || 'a'; 400 401 menu.$el.on({ 402 403 click: function () { 404 405 var $a = $(this); 406 var $item = $a.closest('li'); 407 var $sub = $item.children('ul'); 408 409 if (!$sub.length) { 410 return true; 411 } 412 413 if ($sub.is(':animated')) { 414 return false; 415 } 416 417 if ($sub.is(':hidden')) { 418 419 menu.show($sub, function () { 420 $a.addClass(menu.settings.openClass); 421 }); 422 423 } else { 424 425 menu.hide($sub, function () { 426 $a.removeClass(menu.settings.openClass); 427 }); 428 429 } 430 431 return false; 432 433 } 434 435 }, selector); 436 437 }, 438 439 'dropdown+left': function (menu) { 440 441 dropdownPlus(menu, 'left'); 442 443 }, 444 445 'dropdown+right': function(menu) { 446 447 dropdownPlus(menu, 'right'); 448 449 } 450 451 }; 452 453 $.fn.s3MenuAllIn = function (settings) { 454 455 settings = $.extend({ 456 457 deviation: 10, 458 type: 'right', 459 exitTimeout: 250, 460 activateTimeout: 0, 461 deactivateTimeout: 100, 462 exclude: 'ul', 463 debug: false, 464 showFn: $.fn.show, 465 showTime: 0, 466 hideFn: $.fn.hide, 467 hideTime: 0, 468 activeClass: 's3-menu-allin-active', 469 hasClass: 's3-menu-allin-has', 470 openClass: 's3-menu-allin-open', 471 revertClass: 's3-menu-allin-revert' 472 473 }, settings); 474 475 return this.each(function () { 476 477 var $el = $(this); 478 479 var menu = $.s3Eventable({ 480 481 settings: settings, 482 triangle: new math.Triangle({}, {}, {}), 483 $el: $el, 484 $li: $el.find('li'), 485 $ul: $el.find('ul'), 486 isBlocked: false, 487 isExit: true, 488 active: {} 489 490 }); 491 492 if (settings.hasClass) { 493 menu.$ul.parent('li').addClass(settings.hasClass); 494 } 495 496 $.each(['show', 'hide'], function (key, value) { 497 498 menu[value] = function ($el, callback) { 499 500 callback = callback || $.noop; 501 502 if ($el.length) { 503 504 $el.stop(true, true); 505 this.settings[value + 'Fn'].call($el, this.settings[value + 'Time'], callback); 506 507 } 508 509 }; 510 511 }); 512 513 if (settings.debug) { 514 debug(menu); 515 } 516 517 518 $(document).on('mousemove', function (e) { 519 520 if (menu.isBlocked) { 521 522 var $item = $(e.target).not(settings.exclude).closest('li'); 523 var isSub = false;
524 var isMenu = false; 525 526 if ($item.get(0)) { 527 528 if (menu.active.$sub) { 529 isSub = $item.closest('ul').get(0) === menu.active.$sub.get(0); 530 } 531 532 isMenu = !!menu.$el.has($item).length; 533 534 } 535 536 var hasPoint = menu.triangle.hasPoint({x: e.pageX, y: e.pageY}, settings.deviation); 537 538 if (isMenu) { 539 540 menu.isExit = false; 541 clearTimeout(menu.exitTimeoutId); 542 543 } 544 545 if (isSub) { 546 547 menu.isBlocked = false; 548 clearTimeout(menu.deactivateTimeoutId); 549 $item.trigger('mouseenter'); 550 551 } else if (isMenu) { 552 553 clearTimeout(menu.deactivateTimeoutId); 554 555 if (hasPoint) { 556 557 (function(params) { 558 559 menu.deactivateTimeoutId = setTimeout(function () { 560 561 menu.isBlocked = false; 562 menu.trigger('deactivate', params, 1); 563 $item.trigger('mouseenter'); 564 565 }, settings.deactivateTimeout); 566 567 })($.extend({}, menu.active)); 568 569 } else { 570 571 menu.isBlocked = false; 572 menu.trigger('deactivate', $.extend({}, menu.active), 2); 573 $item.trigger('mouseenter'); 574 575 } 576 577 } else { 578 579 if (hasPoint) { 580 581 menu.isExit = false; 582 583 clearTimeout(menu.exitTimeoutId); 584 585 menu.exitTimeoutId = setTimeout(function () { 586 587 menu.isExit = false; 588 menu.trigger('exit'); 589 590 }, settings.deactivateTimeout); 591 592 } else { 593 594 if (!menu.isExit) { 595 596 menu.isExit = true; 597 598 clearTimeout(menu.exitTimeoutId); 599 menu.exitTimeoutId = setTimeout(function () { 600 601 menu.isExit = false; 602 menu.trigger('exit'); 603 604 }, settings.exitTimeout); 605 606 } 607 608 } 609 610 } 611 612 } 613 614 }); 615 616 menu.$el.on({ 617 618 mouseenter: function (e) { 619 620 e.stopPropagation(); 621 menu.isExit = false; 622 623 if (menu.isBlocked) { 624 return; 625 } 626 627 var $item = $(this); 628 629 if ($item.hasClass('dropdown-wrap')) return; 630 631 var $sub = $item.children('ul'); 632 633 if (!$sub.length) { 634 return; 635 } 636 637 var $parents = $sub.parentsUntil(menu.$el, 'li'); 638 639 (function(params) { 640 641 clearTimeout(menu.activateTimeoutId); 642 menu.activateTimeoutId = setTimeout(function () { 643 if (!menu.isExit) { 644 menu.trigger('activate', params); 645 } 646 }, menu.settings.activateTimeout); 647 648 })({ 649 $item: $item, 650 $sub: $sub, 651 $parents: $parents, 652 $ul: $item.parent(), 653 level: $parents.length 654 }); 655 656 }, 657 658 mouseleave: function (e) { 659 660 e.stopPropagation(); 661 662 if (!menu.isBlocked) { 663 menu.triangle.a.x = e.pageX; 664 menu.triangle.a.y = e.pageY; 665 menu.isBlocked = true; 666 } 667 668 var $item = $(this); 669 var $sub = $item.children('ul'); 670 var $parents = $sub.parentsUntil(menu.$el, 'li'); 671 672 menu.active = { 673 $item: $item, 674 $sub: $sub, 675 $parents: $parents, 676 $ul: $item.parent(), 677 level: $parents.length 678 }; 679 680 } 681 682 }, 'li'); 683 684 $.s3MenuAllInTypes[settings.type](menu); 685 686 }); 687 688 }; 689 690});
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.