summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/snippet/collapsible_input.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/snippet/collapsible_input.js')
-rw-r--r--app/assets/javascripts/snippet/collapsible_input.js45
1 files changed, 45 insertions, 0 deletions
diff --git a/app/assets/javascripts/snippet/collapsible_input.js b/app/assets/javascripts/snippet/collapsible_input.js
new file mode 100644
index 00000000000..e7225162f86
--- /dev/null
+++ b/app/assets/javascripts/snippet/collapsible_input.js
@@ -0,0 +1,45 @@
+const hide = el => el.classList.add('d-none');
+const show = el => el.classList.remove('d-none');
+
+const setupCollapsibleInput = el => {
+ const collapsedEl = el.querySelector('.js-collapsed');
+ const expandedEl = el.querySelector('.js-expanded');
+ const collapsedInputEl = collapsedEl.querySelector('textarea,input,select');
+ const expandedInputEl = expandedEl.querySelector('textarea,input,select');
+ const formEl = el.closest('form');
+
+ const collapse = () => {
+ hide(expandedEl);
+ show(collapsedEl);
+ };
+
+ const expand = () => {
+ hide(collapsedEl);
+ show(expandedEl);
+ };
+
+ // NOTE:
+ // We add focus listener to all form inputs so that we can collapse
+ // when something is focused that's not the expanded input.
+ formEl.addEventListener('focusin', e => {
+ if (e.target === collapsedInputEl) {
+ expand();
+ expandedInputEl.focus();
+ } else if (!el.contains(e.target) && !expandedInputEl.value) {
+ collapse();
+ }
+ });
+};
+
+/**
+ * Usage in HAML
+ *
+ * .js-collapsible-input
+ * .js-collapsed{ class: ('d-none' if is_expanded) }
+ * = input
+ * .js-expanded{ class: ('d-none' if !is_expanded) }
+ * = big_input
+ */
+export default () => {
+ Array.from(document.querySelectorAll('.js-collapsible-input')).forEach(setupCollapsibleInput);
+};