| Conditions | 130 |
| Total Lines | 485 |
| Code Lines | 287 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like chibi.js ➔ chibi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /*!chibi 3.0.9, Copyright 2012-2017 Kyle Barrow, released under MIT license */ |
||
| 211 | function chibi(selector) {
|
||
| 212 | let cb, nodes = [], json = false, nodelist, i; |
||
| 213 | |||
| 214 | if (selector) {
|
||
| 215 | |||
| 216 | // Element node, would prefer to use (selector instanceof HTMLElement) but no IE support |
||
| 217 | if (selector.nodeType && selector.nodeType === 1) {
|
||
| 218 | nodes = [selector]; // return element as node list |
||
| 219 | } else if (typeof selector === 'object') {
|
||
| 220 | // JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support |
||
| 221 | json = (typeof selector.length !== 'number'); |
||
| 222 | nodes = selector; |
||
| 223 | } else if (typeof selector === 'string') {
|
||
| 224 | |||
| 225 | // A very light querySelectorAll polyfill for IE < 8. It suits my needs but is restricted to IE CSS support, is no speed demon, and does leave older mobile browsers in the cold (that support neither querySelectorAll nor currentStyle/getComputedStyle). If you want to use a fuller featured selector engine like Qwery, Sizzle et al, just return results to the nodes array: nodes = altselectorengine(selector) |
||
| 226 | |||
| 227 | // IE < 8 |
||
| 228 | if (!d.querySelectorAll) {
|
||
| 229 | // Polyfill querySelectorAll |
||
| 230 | d.querySelectorAll = function (selector) {
|
||
| 231 | |||
| 232 | let style, head = d.getElementsByTagName('head')[0], allnodes, selectednodes = [], i;
|
||
| 233 | |||
| 234 | style = d.createElement('STYLE');
|
||
| 235 | style.type = 'text/css'; |
||
| 236 | |||
| 237 | if (style.styleSheet) {
|
||
| 238 | style.styleSheet.cssText = selector + ' {a:b}';
|
||
| 239 | |||
| 240 | head.appendChild(style); |
||
| 241 | |||
| 242 | allnodes = d.getElementsByTagName('*');
|
||
| 243 | |||
| 244 | for (i = 0; i < allnodes.length; i += 1) {
|
||
| 245 | if (computeStyle(allnodes[i], 'a') === 'b') {
|
||
| 246 | selectednodes.push(allnodes[i]); |
||
| 247 | } |
||
| 248 | } |
||
| 249 | |||
| 250 | head.removeChild(style); |
||
| 251 | } |
||
| 252 | |||
| 253 | return selectednodes; |
||
| 254 | }; |
||
| 255 | } |
||
| 256 | |||
| 257 | nodelist = d.querySelectorAll(selector); |
||
| 258 | |||
| 259 | // Convert node list to array so results have full access to array methods |
||
| 260 | // Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway |
||
| 261 | for (i = 0; i < nodelist.length; i += 1) {
|
||
| 262 | nodes[i] = nodelist[i]; |
||
| 263 | } |
||
| 264 | |||
| 265 | } |
||
| 266 | } |
||
| 267 | |||
| 268 | // Only attach nodes if not JSON |
||
| 269 | cb = json ? {} : nodes;
|
||
| 270 | |||
| 271 | // Public functions |
||
| 272 | |||
| 273 | // Fire on DOM ready |
||
| 274 | cb.ready = function (fn) {
|
||
| 275 | if (fn) {
|
||
| 276 | if (domready) {
|
||
| 277 | fn(); |
||
| 278 | return cb; |
||
| 279 | } else {
|
||
| 280 | readyfn.push(fn); |
||
| 281 | } |
||
| 282 | } |
||
| 283 | }; |
||
| 284 | // Fire on page loaded |
||
| 285 | cb.loaded = function (fn) {
|
||
| 286 | if (fn) {
|
||
| 287 | if (pageloaded) {
|
||
| 288 | fn(); |
||
| 289 | return cb; |
||
| 290 | } else {
|
||
| 291 | loadedfn.push(fn); |
||
| 292 | } |
||
| 293 | } |
||
| 294 | }; |
||
| 295 | // Executes a function on nodes |
||
| 296 | cb.each = function (fn) {
|
||
| 297 | if (typeof fn === 'function') {
|
||
| 298 | nodeLoop(function (elm) {
|
||
| 299 | // <= IE 8 loses scope so need to apply |
||
| 300 | return fn.apply(elm, arguments); |
||
| 301 | }, nodes); |
||
| 302 | } |
||
| 303 | return cb; |
||
| 304 | }; |
||
| 305 | // Find parent |
||
| 306 | cb.parent = function () {
|
||
| 307 | return nodes.length > 0 ? chibi(nodes[0].parentNode) : null; |
||
| 308 | }; |
||
| 309 | // Find first |
||
| 310 | cb.first = function () {
|
||
| 311 | return chibi(nodes.shift()); |
||
| 312 | }; |
||
| 313 | // Find last |
||
| 314 | cb.last = function () {
|
||
| 315 | return chibi(nodes.pop()); |
||
| 316 | }; |
||
| 317 | // Find odd |
||
| 318 | cb.odd = function () {
|
||
| 319 | let odds = [], i; |
||
| 320 | for (i = 0; i < nodes.length; i += 2) {
|
||
| 321 | odds.push(nodes[i]); |
||
| 322 | } |
||
| 323 | return chibi(odds); |
||
| 324 | }; |
||
| 325 | // Find even |
||
| 326 | cb.even = function () {
|
||
| 327 | let evens = [], i; |
||
| 328 | for (i = 1; i < nodes.length; i += 2) {
|
||
| 329 | evens.push(nodes[i]); |
||
| 330 | } |
||
| 331 | return chibi(evens); |
||
| 332 | }; |
||
| 333 | // Hide node |
||
| 334 | cb.hide = function () {
|
||
| 335 | nodeLoop(function (elm) {
|
||
| 336 | elm.style.display = 'none'; |
||
| 337 | }, nodes); |
||
| 338 | return cb; |
||
| 339 | }; |
||
| 340 | // Show node |
||
| 341 | cb.show = function () {
|
||
| 342 | nodeLoop(function (elm) {
|
||
| 343 | showCss(elm); |
||
| 344 | }, nodes); |
||
| 345 | return cb; |
||
| 346 | }; |
||
| 347 | // Toggle node display |
||
| 348 | cb.toggle = function () {
|
||
| 349 | nodeLoop(function (elm) {
|
||
| 350 | // computeStyle instead of style.display == 'none' catches elements that are hidden via style block |
||
| 351 | if (computeStyle(elm, 'display') === 'none') {
|
||
| 352 | showCss(elm); |
||
| 353 | } else {
|
||
| 354 | elm.style.display = 'none'; |
||
| 355 | } |
||
| 356 | |||
| 357 | }, nodes); |
||
| 358 | return cb; |
||
| 359 | }; |
||
| 360 | // Remove node |
||
| 361 | cb.remove = function () {
|
||
| 362 | nodeLoop(function (elm) {
|
||
| 363 | // Catch error in unlikely case elm has been removed |
||
| 364 | try {
|
||
| 365 | elm.parentNode.removeChild(elm); |
||
| 366 | } catch (e) {}
|
||
| 367 | }, nodes); |
||
| 368 | return chibi(); |
||
| 369 | }; |
||
| 370 | // Get/Set CSS |
||
| 371 | cb.css = function (property, value) {
|
||
| 372 | if (property) {
|
||
| 373 | if (value || value === '') {
|
||
| 374 | nodeLoop(function (elm) {
|
||
| 375 | setCss(elm, property, value); |
||
| 376 | }, nodes); |
||
| 377 | return cb; |
||
| 378 | } |
||
| 379 | if (nodes[0]) {
|
||
| 380 | if (nodes[0].style[cssCamel(property)]) {
|
||
| 381 | return nodes[0].style[cssCamel(property)]; |
||
| 382 | } |
||
| 383 | if (computeStyle(nodes[0], property)) {
|
||
| 384 | return computeStyle(nodes[0], property); |
||
| 385 | } |
||
| 386 | } |
||
| 387 | } |
||
| 388 | }; |
||
| 389 | // Get class(es) |
||
| 390 | cb.getClass = function () {
|
||
| 391 | if (nodes[0] && nodes[0].className.length > 0) {
|
||
| 392 | // Weak IE trim support |
||
| 393 | return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/,' '); |
||
| 394 | } |
||
| 395 | }; |
||
| 396 | // Set (replaces) classes |
||
| 397 | cb.setClass = function (classes) {
|
||
| 398 | if (classes || classes === '') {
|
||
| 399 | nodeLoop(function (elm) {
|
||
| 400 | elm.className = classes; |
||
| 401 | }, nodes); |
||
| 402 | } |
||
| 403 | return cb; |
||
| 404 | }; |
||
| 405 | // Add class |
||
| 406 | cb.addClass = function (classes) {
|
||
| 407 | if (classes) {
|
||
| 408 | nodeLoop(function (elm) {
|
||
| 409 | elm.className += ' ' + classes; |
||
| 410 | }, nodes); |
||
| 411 | } |
||
| 412 | return cb; |
||
| 413 | }; |
||
| 414 | // Remove class |
||
| 415 | cb.removeClass = function (classes) {
|
||
| 416 | classHelper(classes, 'remove', nodes); |
||
| 417 | return cb; |
||
| 418 | }; |
||
| 419 | // Toggle class |
||
| 420 | cb.toggleClass = function (classes) {
|
||
| 421 | classHelper(classes, 'toggle', nodes); |
||
| 422 | return cb; |
||
| 423 | }; |
||
| 424 | // Has class |
||
| 425 | cb.hasClass = function (classes) {
|
||
| 426 | return classHelper(classes, 'has', nodes); |
||
| 427 | }; |
||
| 428 | // Get/set HTML |
||
| 429 | cb.html = function (value) {
|
||
| 430 | if (value || value === '') {
|
||
| 431 | nodeLoop(function (elm) {
|
||
| 432 | elm.innerHTML = value; |
||
| 433 | }, nodes); |
||
| 434 | return cb; |
||
| 435 | } |
||
| 436 | if (nodes[0]) {
|
||
| 437 | return nodes[0].innerHTML; |
||
| 438 | } |
||
| 439 | }; |
||
| 440 | // Insert HTML before selector |
||
| 441 | cb.htmlBefore = function (value) {
|
||
| 442 | insertHtml(value, 'before', nodes); |
||
| 443 | return cb; |
||
| 444 | }; |
||
| 445 | // Insert HTML after selector |
||
| 446 | cb.htmlAfter = function (value) {
|
||
| 447 | insertHtml(value, 'after', nodes); |
||
| 448 | return cb; |
||
| 449 | }; |
||
| 450 | // Insert HTML after selector innerHTML |
||
| 451 | cb.htmlAppend = function (value) {
|
||
| 452 | insertHtml(value, 'append', nodes); |
||
| 453 | return cb; |
||
| 454 | }; |
||
| 455 | // Insert HTML before selector innerHTML |
||
| 456 | cb.htmlPrepend = function (value) {
|
||
| 457 | insertHtml(value, 'prepend', nodes); |
||
| 458 | return cb; |
||
| 459 | }; |
||
| 460 | // Get/Set HTML attributes |
||
| 461 | cb.attr = function (property, value) {
|
||
| 462 | if (property) {
|
||
| 463 | property = property.toLowerCase(); |
||
| 464 | // IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway |
||
| 465 | if (value || value === '') {
|
||
| 466 | nodeLoop(function (elm) {
|
||
| 467 | if (property === 'style') {
|
||
| 468 | elm.style.cssText = value; |
||
| 469 | } else if (property === 'class') {
|
||
| 470 | elm.className = value; |
||
| 471 | } else {
|
||
| 472 | elm.setAttribute(property, value); |
||
| 473 | } |
||
| 474 | }, nodes); |
||
| 475 | return cb; |
||
| 476 | } |
||
| 477 | if (nodes[0]) {
|
||
| 478 | if (property === 'style') {
|
||
| 479 | if (nodes[0].style.cssText) {
|
||
| 480 | return nodes[0].style.cssText; |
||
| 481 | } |
||
| 482 | } else if (property === 'class') {
|
||
| 483 | if (nodes[0].className) {
|
||
| 484 | return nodes[0].className; |
||
| 485 | } |
||
| 486 | } else {
|
||
| 487 | if (nodes[0].getAttribute(property)) {
|
||
| 488 | return nodes[0].getAttribute(property); |
||
| 489 | } |
||
| 490 | } |
||
| 491 | } |
||
| 492 | } |
||
| 493 | }; |
||
| 494 | // Get/Set HTML data property |
||
| 495 | cb.data = function (key, value) {
|
||
| 496 | if (key) {
|
||
| 497 | return cb.attr('data-'+key, value);
|
||
| 498 | } |
||
| 499 | }; |
||
| 500 | // Get/Set form element values |
||
| 501 | cb.val = function (value) {
|
||
| 502 | let values, i, j; |
||
| 503 | if (value || value === '') {
|
||
| 504 | nodeLoop(function (elm) {
|
||
| 505 | switch (elm.nodeName) {
|
||
| 506 | case 'SELECT': |
||
| 507 | if (typeof value === 'string' || typeof value === 'number') {
|
||
| 508 | value = [value]; |
||
| 509 | } |
||
| 510 | for (i = 0; i < elm.length; i += 1) {
|
||
| 511 | // Multiple select |
||
| 512 | for (j = 0; j < value.length; j += 1) {
|
||
| 513 | elm[i].selected = ''; |
||
| 514 | if (elm[i].value === value[j]) {
|
||
| 515 | elm[i].selected = 'selected'; |
||
| 516 | break; |
||
| 517 | } |
||
| 518 | } |
||
| 519 | } |
||
| 520 | break; |
||
| 521 | case 'INPUT': |
||
| 522 | case 'TEXTAREA': |
||
| 523 | case 'BUTTON': |
||
| 524 | elm.value = value; |
||
| 525 | break; |
||
| 526 | } |
||
| 527 | }, nodes); |
||
| 528 | |||
| 529 | return cb; |
||
| 530 | } |
||
| 531 | if (nodes[0]) {
|
||
| 532 | switch (nodes[0].nodeName) {
|
||
| 533 | case 'SELECT': |
||
| 534 | values = []; |
||
| 535 | for (i = 0; i < nodes[0].length; i += 1) {
|
||
| 536 | if (nodes[0][i].selected) {
|
||
| 537 | values.push(nodes[0][i].value); |
||
| 538 | } |
||
| 539 | } |
||
| 540 | return (values.length > 1) ? values : values[0]; |
||
| 541 | case 'INPUT': |
||
| 542 | case 'TEXTAREA': |
||
| 543 | case 'BUTTON': |
||
| 544 | return nodes[0].value; |
||
| 545 | } |
||
| 546 | } |
||
| 547 | }; |
||
| 548 | // Return matching checked checkbox or radios |
||
| 549 | cb.checked = function (check) {
|
||
| 550 | if (typeof check === 'boolean') {
|
||
| 551 | nodeLoop(function (elm) {
|
||
| 552 | if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {
|
||
| 553 | elm.checked = check; |
||
| 554 | } |
||
| 555 | }, nodes); |
||
| 556 | return cb; |
||
| 557 | } |
||
| 558 | if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {
|
||
| 559 | return (!!nodes[0].checked); |
||
| 560 | } |
||
| 561 | }; |
||
| 562 | // Add event handler |
||
| 563 | cb.on = function (event, fn) {
|
||
| 564 | if (selector === w || selector === d) {
|
||
| 565 | nodes = [selector]; |
||
| 566 | } |
||
| 567 | nodeLoop(function (elm) {
|
||
| 568 | if (d.addEventListener) {
|
||
| 569 | elm.addEventListener(event, fn, false); |
||
| 570 | } else if (d.attachEvent) {
|
||
| 571 | // <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions) |
||
| 572 | elm[event + fn] = function () { return fn.apply(elm, arguments); };
|
||
| 573 | elm.attachEvent('on' + event, elm[event + fn]);
|
||
| 574 | } |
||
| 575 | }, nodes); |
||
| 576 | return cb; |
||
| 577 | }; |
||
| 578 | // Remove event handler |
||
| 579 | cb.off = function (event, fn) {
|
||
| 580 | if (selector === w || selector === d) {
|
||
| 581 | nodes = [selector]; |
||
| 582 | } |
||
| 583 | nodeLoop(function (elm) {
|
||
| 584 | if (d.addEventListener) {
|
||
| 585 | elm.removeEventListener(event, fn, false); |
||
| 586 | } else if (d.attachEvent) {
|
||
| 587 | elm.detachEvent('on' + event, elm[event + fn]);
|
||
| 588 | // Tidy up |
||
| 589 | elm[event + fn] = null; |
||
| 590 | } |
||
| 591 | }, nodes); |
||
| 592 | return cb; |
||
| 593 | }; |
||
| 594 | // Basic XHR 1, no file support. Shakes fist at IE |
||
| 595 | cb.ajax = function (url, method, callback, nocache, nojsonp) {
|
||
| 596 | let xhr, |
||
| 597 | query = serializeData(nodes), |
||
| 598 | type = (method) ? method.toUpperCase() : 'GET', |
||
| 599 | hostsearch = new RegExp('http[s]?://(.*?)/', 'gi'),
|
||
| 600 | domain = hostsearch.exec(url), |
||
| 601 | timestamp = '_ts=' + (+new Date()), |
||
| 602 | head = d.getElementsByTagName('head')[0],
|
||
| 603 | jsonpcallback = 'chibi' + (+new Date()) + (jsonpcount += 1), |
||
| 604 | script; |
||
| 605 | |||
| 606 | if (query && (type === 'GET' || type === 'DELETE')) {
|
||
| 607 | url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
|
||
| 608 | query = null; |
||
| 609 | } |
||
| 610 | |||
| 611 | // JSONP if cross domain url |
||
| 612 | if (type === 'GET' && !nojsonp && domain && w.location.host !== domain[1]) {
|
||
| 613 | |||
| 614 | if (nocache) {
|
||
| 615 | url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
|
||
| 616 | } |
||
| 617 | |||
| 618 | // Replace possible encoded ? |
||
| 619 | url = url.replace('=%3F', '=?');
|
||
| 620 | |||
| 621 | // Replace jsonp ? with callback |
||
| 622 | if (callback && url.indexOf('=?') !== -1) {
|
||
| 623 | |||
| 624 | url = url.replace('=?', '=' + jsonpcallback);
|
||
| 625 | |||
| 626 | w[jsonpcallback] = function (data) {
|
||
| 627 | try {
|
||
| 628 | callback(data, 200); |
||
| 629 | } catch (e) {}
|
||
| 630 | |||
| 631 | // Tidy up |
||
| 632 | w[jsonpcallback] = undefined; |
||
| 633 | }; |
||
| 634 | } |
||
| 635 | |||
| 636 | // JSONP |
||
| 637 | script = document.createElement('script');
|
||
| 638 | script.async = true; |
||
| 639 | script.src = url; |
||
| 640 | |||
| 641 | // Tidy up |
||
| 642 | script.onload = function () {
|
||
| 643 | head.removeChild(script); |
||
| 644 | }; |
||
| 645 | |||
| 646 | head.appendChild(script); |
||
| 647 | |||
| 648 | } else {
|
||
| 649 | |||
| 650 | if (w.XMLHttpRequest) {
|
||
| 651 | xhr = new XMLHttpRequest(); |
||
| 652 | } else if (w.ActiveXObject) {
|
||
| 653 | xhr = new ActiveXObject('Microsoft.XMLHTTP'); // IE < 9
|
||
| 654 | } |
||
| 655 | |||
| 656 | if (xhr) {
|
||
| 657 | |||
| 658 | if (nocache) {
|
||
| 659 | url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
|
||
| 660 | } |
||
| 661 | |||
| 662 | // Douglas Crockford: "Synchronous programming is disrespectful and should not be employed in applications which are used by people" |
||
| 663 | xhr.open(type, url, true); |
||
| 664 | |||
| 665 | xhr.onreadystatechange = function () {
|
||
| 666 | if (xhr.readyState === 4) {
|
||
| 667 | if (callback) {
|
||
| 668 | callback(xhr.responseText, xhr.status); |
||
| 669 | } |
||
| 670 | } |
||
| 671 | }; |
||
| 672 | |||
| 673 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||
| 674 | |||
| 675 | if (type === 'POST' || type === 'PUT') {
|
||
| 676 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||
| 677 | } |
||
| 678 | |||
| 679 | xhr.send(query); |
||
| 680 | |||
| 681 | } |
||
| 682 | } |
||
| 683 | return cb; |
||
| 684 | }; |
||
| 685 | // Alias to cb.ajax(url, 'get', callback, nocache, nojsonp) |
||
| 686 | cb.get = function (url, callback, nocache, nojsonp) {
|
||
| 687 | return cb.ajax(url, 'get', callback, nocache, nojsonp); |
||
| 688 | }; |
||
| 689 | // Alias to cb.ajax(url, 'post', callback, nocache) |
||
| 690 | cb.post = function (url, callback, nocache) {
|
||
| 691 | return cb.ajax(url, 'post', callback, nocache); |
||
| 692 | }; |
||
| 693 | |||
| 694 | return cb; |
||
| 695 | } |
||
| 696 | |||
| 701 |