summaryrefslogtreecommitdiffstats
path: root/jquery.once.js
blob: 5361c741ba384d1f732fe9b5e627d2e61f8d98c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*!
 * @file jQuery Once
 * @description Act on jQuery elements only once.
 * @version 2.0.0-alpha.5
 * @link http://github.com/robloach/jquery-once
 *
 * @example
 * // Change the color to green only once.
 * $('p').once('changecolor', function() {
 *   $(this).css('color', 'green');
 * });
 *
 * @see once
 * @see removeOnce
 * @see findOnce
 *
 * @author Rob Loach (http://robloach.net)
 * @license MIT, GPL-2.0
 */

(function (factory) {
  "use strict";
  if (typeof exports === 'object') {
    factory(require('jquery'));
  } else if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else {
    factory(jQuery);
  }
}(function ($) {
  "use strict";
  var cache = {}, uuid = 0;

  /**
   * Filters elements by whether they have not yet been processed.
   *
   * @param {(string|function)} [id]
   *   (Optional) If this is a string, then it will be the data ID used
   *   to determine whether it has already been processed or not.
   *
   *   If the id parameter is a function, it will be passed off to the fn
   *   parameter and the id will become a unique identifier, represented as a
   *   number.
   *
   *   When the id is neither a string or a function, it becomes a unique
   *   identifier, depicted as a number. The element's data ID will then be
   *   represented in the form of "jquery-once-#".
   * @param {function} [fn]
   *   (Optional) If given, this function will be called for each element that
   *   has not yet been processed. The function's return value follows the same
   *   logic as $.each(). Returning true will continue to the next matched
   *   element in the set, while returning false will entirely break the
   *   iteration.
   * @returns jQuery element collection of elements that have now run once.
   *
   * @public
   * @global
   */
  $.fn.once = function (id, fn) {
    if (typeof id !== 'string') {
      // Generate a numeric ID if the id passed can't be used as a CSS class.
      if (!(id in cache)) {
        cache[id] = ++uuid;
      }
      // When the fn parameter is not passed, we interpret it from the id.
      if (!fn) {
        fn = id;
      }
      id = cache[id];
    }

    // Filter the elements by which do not have the data yet.
    var name = 'jquery-once-' + id;
    var elements = this.filter(function() {
      return $(this).data(name) !== true;
    }).data(name, true);

    return $.isFunction(fn) ? elements.each(fn) : elements;
  };

  /**
   * Removes the once data from the given elements, based on the given ID.
   *
   * @param {string} id
   *   A required string representing the name of the data id which should be used
   *   when filtering the elements. This only filters elements that have already
   *   been processed by the once function. The id should be the same id that
   *   was originally passed to the once() function.
   * @param {function} [fn]
   *   (Optional) If given, this function will be called for each element that
   *   whose element's once data was removed. The function's return value
   *   follows the same logic as $.each(). Returning true will continue to the
   *   next matched element in the set, while returning false will entirely
   *   break the iteration.
   * @returns jQuery element collection of elements that now have their once
   *   data removed.
   *
   * @public
   * @global
   */
  $.fn.removeOnce = function (id, fn) {
    // Filter through the elements to find the once'd elements.
    var elements = this.findOnce(id);

    // Remove the once data from the elements.
    elements.removeData('jquery-once-' + id);

    return $.isFunction(fn) ? elements.each(fn) : elements;
  };

  /**
   * Filters elements that have already been processed once.
   *
   * @param {string} id
   *   A required string representing the name of the data id which should be used
   *   when filtering the elements. This only filters elements that have already
   *   been processed by the once function. The id should be the same id that
   *   was originally passed to the once() function.
   * @param {function} [fn]
   *   (Optional) If given, this function will be called for each element that
   *   has not yet been processed. The function's return value follows the same
   *   logic as $.each(). Returning true will continue to the next matched
   *   element in the set, while returning false will entirely break the
   *   iteration.
   * @returns jQuery element collection of elements that have been run once.
   *
   * @public
   * @global
   */
  $.fn.findOnce = function (id, fn) {
    // Filter the elements by which do have the data.
    var name = 'jquery-once-' + id;
    var elements = this.filter(function() {
      return $(this).data(name) === true;
    });

    return $.isFunction(fn) ? elements.each(fn) : elements;
  };
}));