Created
June 19, 2021 12:32
-
-
Save aryanshridhar/cac0a951ffe6de12db164faa5e4e14b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import $ from "jquery"; | |
import render_dropdown_list from "../templates/settings/dropdown_list.hbs"; | |
import * as blueslip from "./blueslip"; | |
import * as ListWidget from "./list_widget"; | |
import _ from 'lodash'; | |
export function DropdownListWidget({ | |
widget_name, | |
data, | |
default_text, | |
render_text = (item_name) => item_name, | |
null_value = null, | |
include_current_item = true, | |
value, | |
on_update = () => {}, | |
}) { | |
this.widget_name = widget_name; | |
this.data = data; | |
this.default_text = default_text; | |
this.render_text = render_text; | |
this.null_value = null; | |
this.include_current_item = include_current_item; | |
this.value = value; | |
this.on_update = on_update; | |
this.container_id = `${widget_name}_widget`; | |
this.value_id = `id_${widget_name}`; | |
if (value === undefined) { | |
this.value = null_value; | |
blueslip.warn("dropdown-list-widget: Called without a default value; using null value"); | |
} | |
this.setup(); | |
} | |
DropdownListWidget.prototype.render_default_text = function (elem) { | |
elem.text(this.default_text); | |
elem.addClass("text-warning"); | |
elem.closest(".input-group").find(".dropdown_list_reset_button:enabled").hide(); | |
}; | |
DropdownListWidget.prototype.render = function (value) { | |
$(`#${CSS.escape(this.container_id)} #${CSS.escape(this.value_id)}`).data("value", value); | |
const elem = $(`#${CSS.escape(this.container_id)} #${CSS.escape(this.widget_name)}_name`); | |
if (!value || value === this.null_value) { | |
this.render_default_text(elem); | |
return; | |
} | |
// Happy path | |
const item = this.data.find((x) => x.value === value.toString()); | |
if (item === undefined) { | |
this.render_default_text(elem); | |
return; | |
} | |
const text = this.render_text(item.name); | |
elem.text(text); | |
elem.removeClass("text-warning"); | |
elem.closest(".input-group").find(".dropdown_list_reset_button:enabled").show(); | |
}; | |
DropdownListWidget.prototype.update = function (value) { | |
this.render(value); | |
this.on_update(value); | |
}; | |
DropdownListWidget.prototype.register_event_handlers = function () { | |
$(`#${CSS.escape(this.container_id)} .dropdown-list-body`).on( | |
"click keypress", | |
".list_item", | |
(e) => { | |
const setting_elem = $(this).closest(`.${CSS.escape(this.widget_name)}_setting`); | |
if (e.type === "keypress") { | |
if (e.key === "Enter") { | |
setting_elem.find(".dropdown-menu").dropdown("toggle"); | |
} else { | |
return; | |
} | |
} | |
const value = $(e.target.closest("li")).attr("data-value"); | |
this.update(value); | |
}, | |
); | |
$(`#${CSS.escape(this.container_id)} .dropdown_list_reset_button`).on("click", (e) => { | |
this.update(this.null_value); | |
e.preventDefault(); | |
}); | |
}; | |
DropdownListWidget.prototype.setup_dropdown_widget = function (data) { | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
const search_input = $(`#${CSS.escape(this.container_id)} .dropdown-search > input[type=text]`); | |
const get_data = () => { | |
if (this.include_current_item) { | |
return data; | |
} | |
return data.filter((x) => x.value !== this.value.toString()); | |
}; | |
ListWidget.create(dropdown_list_body, get_data(data), { | |
name: `${CSS.escape(this.widget_name)}_list`, | |
modifier(item) { | |
return render_dropdown_list({item}); | |
}, | |
filter: { | |
element: search_input, | |
predicate(item, value) { | |
return item.name.toLowerCase().includes(value); | |
}, | |
}, | |
simplebar_container: $(`#${CSS.escape(this.container_id)} .dropdown-list-wrapper`), | |
}); | |
}; | |
DropdownListWidget.prototype.setup = function () { | |
// populate the dropdown | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
const search_input = $(`#${CSS.escape(this.container_id)} .dropdown-search > input[type=text]`); | |
const dropdown_toggle = $(`#${CSS.escape(this.container_id)} .dropdown-toggle`); | |
this.setup_dropdown_widget(this.data); | |
$(`#${CSS.escape(this.container_id)} .dropdown-search`).on("click", (e) => { | |
e.stopPropagation(); | |
}); | |
dropdown_toggle.on("click", () => { | |
search_input.val("").trigger("input"); | |
}); | |
dropdown_toggle.on("focus", (e) => { | |
// On opening a Bootstrap Dropdown, the parent element receives focus. | |
// Here, we want our search input to have focus instead. | |
e.preventDefault(); | |
// This function gets called twice when focusing the | |
// dropdown, and only in the second call is the input | |
// field visible in the DOM; so the following visibility | |
// check ensures we wait for the second call to focus. | |
if (dropdown_list_body.is(":visible")) { | |
search_input.trigger("focus"); | |
} | |
}); | |
search_input.on("keydown", (e) => { | |
const {key, keyCode, which} = e; | |
const navigation_keys = ["ArrowUp", "ArrowDown", "Escape"]; | |
if (!navigation_keys.includes(key)) { | |
return; | |
} | |
e.preventDefault(); | |
e.stopPropagation(); | |
// We pass keyCode instead of key here because the outdated | |
// bootstrap library we have at static/third/ still uses the | |
// deprecated keyCode & which properties. | |
const custom_event = new $.Event("keydown.dropdown.data-api", {keyCode, which}); | |
dropdown_toggle.trigger(custom_event); | |
}); | |
this.render(this.value); | |
this.register_event_handlers(); | |
}; | |
DropdownListWidget.prototype.get_value = function () { | |
let val = $(`#${CSS.escape(this.container_id)} #${CSS.escape(this.value_id)}`).data("value"); | |
if (val === null) { | |
val = ""; | |
} | |
return val; | |
}; | |
export function MultiSelectDropdownListWidget({ | |
widget_name, | |
data, | |
default_text, | |
null_value = null, | |
on_update = () => {}, | |
value, | |
limit, | |
}) { | |
this.limit = limit; | |
this.selected_data = []; // Populate the data enetered by the user. | |
DropdownListWidget.call(this, { | |
widget_name, | |
data, | |
default_text, | |
null_value, | |
on_update, | |
value, | |
}); | |
if (this.limit === undefined) { | |
this.limit = 2; | |
blueslip.warn( | |
"Multiselect dropdown-list-widget: Called without limit value; using 2 as the value", | |
); | |
} | |
if(value){ | |
this.selected_data = [...value]; | |
} | |
this.initialize_intial_values(value); | |
} | |
MultiSelectDropdownListWidget.prototype = Object.create(DropdownListWidget.prototype); | |
MultiSelectDropdownListWidget.prototype.set_text = function (elem, limit) { | |
const items_selected = this.selected_data.length; | |
let text = ""; | |
if(items_selected === 0){ | |
this.render_default_text(elem); | |
return; | |
} | |
else if (limit >= items_selected) { | |
const data_selected = this.data.filter((data) => this.selected_data.includes(data.value)); | |
text = data_selected.map((data) => data.name).toString(); | |
} else { | |
text = `${items_selected} selected`; | |
} | |
elem.text(text); | |
elem.removeClass("text-warning"); | |
elem.closest(".input-group").find(".dropdown_list_reset_button:enabled").show(); | |
}; | |
MultiSelectDropdownListWidget.prototype.render = function(value){ | |
$(`#${CSS.escape(this.container_id)} #${CSS.escape(this.value_id)}`).data("value", value); | |
const elem = $(`#${CSS.escape(this.container_id)} #${CSS.escape(this.widget_name)}_name`); | |
if (!value || value === this.null_value) { | |
this.render_default_text(elem); | |
return; | |
} | |
this.set_text(elem, this.limit); | |
}; | |
MultiSelectDropdownListWidget.prototype.initialize_intial_values = function(values){ | |
if(values === undefined){ | |
return; | |
} | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
for(const value of values){ | |
console.log(typeof value); | |
const element = dropdown_list_body.find(`li[data-value = "${value}"]`) | |
this.add_check_mark(element, value); | |
} | |
} | |
MultiSelectDropdownListWidget.prototype.setup_dropdown_widget = function (data) { | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
const search_input = $(`#${CSS.escape(this.container_id)} .dropdown-search > input[type=text]`); | |
ListWidget.create(dropdown_list_body, data, { | |
name: `${CSS.escape(this.widget_name)}_list`, | |
modifier(item) { | |
return render_dropdown_list({item}); | |
}, | |
filter: { | |
element: search_input, | |
predicate(item, value) { | |
return item.name.toLowerCase().includes(value); | |
}, | |
multiselect: { | |
selected_items: this.selected_data, | |
}, | |
}, | |
simplebar_container: $(`#${CSS.escape(this.container_id)} .dropdown-list-wrapper`), | |
}); | |
}; | |
MultiSelectDropdownListWidget.prototype.reset_dropdown_items = function(){ | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
if(this.checked_items === undefined){ | |
$(`#${CSS.escape(this.container_id)} .dropdown-list-body`).find("li").each((e) =>{ | |
const item = $($(`#${CSS.escape(this.container_id)} .dropdown-list-body`).find("li")[e]); | |
const value = item.attr("data-value"); | |
if(item.hasClass("checked")){ | |
console.log("Haha") | |
this.remove_check_mark(item,value); | |
} | |
}) | |
} | |
else{ | |
if(!(_.isEqual(this.selected_data,this.checked_items))){ | |
const diff_values = _.difference(this.selected_data, this.checked_items).concat(_.difference(this.checked_items, this.selected_data)); | |
for(const value of diff_values){ | |
const element = dropdown_list_body.find(`li[data-value = "${value}"]`) | |
// User unselected the current value. | |
if(this.checked_items.includes(value)){ | |
this.add_check_mark(element, value); | |
} | |
// User selected a bunch of more values. | |
else{ | |
this.remove_check_mark(element, value); | |
} | |
} | |
} | |
} | |
} | |
MultiSelectDropdownListWidget.prototype.add_check_mark = function(element,value){ | |
const link_elem = element.find("a").expectOne(); | |
element.addClass("checked"); | |
link_elem.prepend('<i class="fa fa-check" aria-hidden="true"></i>'); | |
this.selected_data.push(value); | |
} | |
MultiSelectDropdownListWidget.prototype.remove_check_mark = function(element,value){ | |
const icon = element.find("i").expectOne(); | |
const index = this.selected_data.indexOf(value); | |
console.log(typeof value); | |
if (index > -1) { | |
icon.remove(); | |
element.removeClass("checked"); | |
this.selected_data.splice(index, 1); | |
} | |
} | |
MultiSelectDropdownListWidget.prototype.register_event_handlers = function () { | |
const dropdown_toggle = $(`#${CSS.escape(this.container_id)} .dropdown-toggle`); | |
const search_input = $(`#${CSS.escape(this.container_id)} .dropdown-search > input[type=text]`); | |
const dropdown_list_body = $( | |
`#${CSS.escape(this.container_id)} .dropdown-list-body`, | |
).expectOne(); | |
dropdown_toggle.on("click", () => { | |
this.reset_dropdown_items(); | |
search_input.val("").trigger("input"); | |
}); | |
dropdown_list_body.on("click keypress", ".list_item", (e) => { | |
const item_pressed = $(e.target.closest("li")); | |
const value = item_pressed.attr("data-value"); | |
if (item_pressed.hasClass("checked")) { | |
console.log("chekced"); | |
this.remove_check_mark(item_pressed, value); | |
} else { | |
console.log("lol"); | |
this.add_check_mark(item_pressed, value); | |
} | |
e.stopPropagation(); | |
}); | |
$(`#${CSS.escape(this.container_id)} .dropdown_list_reset_button`).on("click", (e) => { | |
// Default back the value. | |
this.checked_items = undefined; | |
this.update(this.null_value); | |
e.preventDefault(); | |
}); | |
$(`#${CSS.escape(this.container_id)} .multiselect_btn`).on("click", (e) => { | |
e.preventDefault(); | |
this.checked_items = [...this.selected_data]; | |
this.update(this.selected_data); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment