Completed
Push — master ( c4abea...06c649 )
by Jochen
03:38
created

byceps/static/behavior/utils.js (1 issue)

1
/**
2
 * Provide an alternative `forEach` function as `NodeList.forEach` is
3
 * not available on Firefox < v50 and MSIE.
4
 */
5
function forEach(array, callback, scope) {
6
  for (var i = 0; i < array.length; i++) {
7
    callback.call(scope, array[i]);
8
  }
9
};
10
11
12
/**
13
 * Register a function to be called when the document is "ready", i.e.
14
 * all the markup has been placed on the page.
15
 *
16
 * It does not wait until additional resources (stylesheets, images,
17
 * subframes) have been loaded.
18
 */
19
function onDomReady(callback) {
20
  if (document.readyState === 'complete' || document.readyState !== 'loading') {
21
    // The document has already fully loaded.
22
    callback();
23
  } else {
24
    document.addEventListener('DOMContentLoaded', callback);
25
  }
26
}
27
28
29
// ---------------------------------------------------------------------
30
// XHR requests
31
32
function send_post_request(url, onload_callback, onerror_callback) {
33
  const request = new XMLHttpRequest();
34
  request.open('POST', url);
35
  request.onload = onload_callback;
36
  request.onerror = onerror_callback;
37
  request.send();
38
}
39
40
function post_on_click(selector) {
41
  _request_on_click(selector, 'POST');
42
}
43
44
function post_on_click_then_reload(selector) {
45
  _request_on_click_then_reload(selector, 'POST');
46
}
47
48
function confirmed_post_on_click(selector, confirmation_label) {
49
  _confirmed_request_on_click(selector, confirmation_label, 'POST');
50
}
51
52
function confirmed_post_on_click_then_reload(selector, confirmation_label) {
53
  _confirmed_request_on_click_then_reload(selector, confirmation_label, 'POST');
54
}
55
56
function delete_on_click(selector) {
57
  _request_on_click(selector, 'DELETE');
58
}
59
60
function delete_on_click_then_reload(selector) {
61
  _request_on_click_then_reload(selector, 'DELETE');
62
}
63
64
function confirmed_delete_on_click(selector, confirmation_label) {
65
  _confirmed_request_on_click(selector, confirmation_label, 'DELETE');
66
}
67
68
function confirmed_delete_on_click_then_reload(selector, confirmation_label) {
69
  _confirmed_request_on_click_then_reload(selector, confirmation_label, 'DELETE');
70
}
71
72
function _request_on_click(selector, method) {
73
  $(selector).click(function() {
74
    var request_url = $(this).attr('href');
75
    _ajax_then_redirect_to_location_response_header(method, request_url);
76
    return false;
77
  });
78
}
79
80
function _request_on_click_then_reload(selector, method) {
81
  $(selector).click(function() {
82
    var request_url = $(this).attr('href');
83
    _ajax_then_reload(method, request_url);
84
    return false;
85
  });
86
}
87
88
function _confirmed_request_on_click(selector, confirmation_label, method) {
89
  $(selector).click(function() {
90
    if (confirm(confirmation_label)) {
91
      var request_url = $(this).attr('href');
92
      _ajax_then_redirect_to_location_response_header(method, request_url);
93
    };
94
    return false;
95
  });
96
}
97
98
function _confirmed_request_on_click_then_reload(selector, confirmation_label, method) {
99
  $(selector).click(function() {
100
    if (confirm(confirmation_label)) {
101
      var request_url = $(this).attr('href');
102
      _ajax_then_reload(method, request_url);
103
    };
104
    return false;
105
  });
106
}
107
108
function _ajax_then_redirect_to_location_response_header(method, request_url) {
109
  _ajax(method, request_url, function(xhr, text_status) {
110
    if (text_status == 'nocontent') {
111
      var redirect_url = _get_location(xhr);
112
      location.href = redirect_url;
113
    }
114
  });
115
}
116
117
function _ajax_then_reload(method, request_url) {
118
  _ajax(method, request_url, function(xhr, text_status) {
119
    if (text_status == 'nocontent') {
120
      location.href = location.href;
121
    }
122
  });
123
}
124
125
function _ajax(method, request_url, on_complete) {
126
  $.ajax({
127
    type: method,
128
    url: request_url,
129
    complete: on_complete
130
  });
131
}
132
133
function _get_location(xhr) {
134
  return xhr.getResponseHeader('Location');
135
}
136
137
138
// ---------------------------------------------------------------------
139
// dropdown menus
140
141
142
/**
143
 * Make dropdown menus open if their respective trigger is clicked.
144
 */
145
function enableDropdownMenuToggles() {
146
  const dropdownToggles = document.querySelectorAll('.dropdown .dropdown-toggle');
147
  forEach(dropdownToggles, function(triggerElement) {
148
    triggerElement.addEventListener('click', function(event) {
149
      const dropdown = triggerElement.parentNode;
150
      dropdown.classList.toggle('open');
151
152
      event.preventDefault();
153
    });
154
  });
155
}
156
157
158
/**
159
 * Close all open dropdown menus but the one that has been clicked (if
160
 * any).
161
 */
162
function closeOpenDropdownMenus(clickTarget) {
163
  const openDropdowns = document.querySelectorAll('.dropdown.open');
164
  forEach(openDropdowns, function(openDropdown) {
165
    if (!openDropdown.contains(clickTarget)) {
166
      // Click was outside of this dropdown menu, so close it.
167
      openDropdown.classList.remove('open');
168
    }
169
  });
170
}
171
172
173
/**
174
 * Add behavior to dropdown menus.
175
 */
176
onDomReady(function() {
177
  enableDropdownMenuToggles();
178
179
  // Close open dropdowns if user clicks outside of an open dropdown.
180
  document.addEventListener('click', function(event) {
181
    closeOpenDropdownMenus(event.target);
182
  });
183
});
184
185
186
// ---------------------------------------------------------------------
187
// clipboard
188
189
190
/**
191
 * Register an element as click trigger to copy the value of a field to
192
 * the clipboard.
193
 */
194
function enableCopyToClipboard(triggerElementId) {
195
  const triggerElement = document.getElementById(triggerElementId);
196
197
  triggerElement.addEventListener('click', function() {
198
    const fieldId = this.dataset.fieldId;
199
    const field = document.getElementById(fieldId);
200
201
    field.focus();
202
    field.select();
203
    try {
204
      document.execCommand('copy');
205
    } catch (err) {}
206
    field.blur();
207
  });
208
}
209
210
211
// ---------------------------------------------------------------------
212
// forms
213
214
215
/**
216
 * Disable the submit button of forms with class
217
 * `disable-submit-button-on-submit` on submit.
218
 */
219
onDomReady(function() {
220
  const formsWhoseSubmitButtonShouldBeDisabledOnSubmit = document
221
      .querySelectorAll('form.disable-submit-button-on-submit');
222
223
  forEach(formsWhoseSubmitButtonShouldBeDisabledOnSubmit, function(form) {
224
    form.addEventListener('submit', function(event) {
0 ignored issues
show
The parameter event is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
225
      const submitButton = form.querySelector('button[type="submit"]');
226
      submitButton.disabled = true;
227
      submitButton.innerHTML += ' <svg class="icon spinning"><use xlink:href="/static/style/icons.svg#spinner"></use></svg>';
228
    });
229
  });
230
});
231