2021-03-11 05:43:45 +01:00
|
|
|
import $ from "jquery";
|
2021-02-28 21:34:05 +01:00
|
|
|
import {Sortable} from "sortablejs";
|
2020-08-01 03:43:15 +02:00
|
|
|
|
2022-06-21 13:42:10 +02:00
|
|
|
import render_confirm_delete_profile_field_option from "../templates/confirm_dialog/confirm_delete_profile_field_option.hbs";
|
2021-04-24 20:05:44 +02:00
|
|
|
import render_admin_profile_field_list from "../templates/settings/admin_profile_field_list.hbs";
|
2021-02-28 21:34:05 +01:00
|
|
|
import render_settings_profile_field_choice from "../templates/settings/profile_field_choice.hbs";
|
2020-07-28 00:50:12 +02:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
import * as channel from "./channel";
|
2022-06-21 13:42:10 +02:00
|
|
|
import * as confirm_dialog from "./confirm_dialog";
|
|
|
|
import {$t_html} from "./i18n";
|
2021-02-28 21:34:05 +01:00
|
|
|
import * as loading from "./loading";
|
2021-03-25 22:35:45 +01:00
|
|
|
import {page_params} from "./page_params";
|
2022-06-21 13:42:10 +02:00
|
|
|
import * as people from "./people";
|
2021-02-28 21:34:05 +01:00
|
|
|
import * as settings_ui from "./settings_ui";
|
2021-02-10 17:09:37 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const meta = {
|
2017-12-14 05:51:45 +01:00
|
|
|
loaded: false,
|
|
|
|
};
|
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function maybe_disable_widgets() {
|
2018-12-08 17:37:57 +01:00
|
|
|
if (page_params.is_admin) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$(".organization-box [data-name='profile-field-settings']")
|
2020-07-15 00:34:28 +02:00
|
|
|
.find("input, button, select")
|
2020-07-22 02:59:06 +02:00
|
|
|
.prop("disabled", true);
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2018-12-08 17:37:57 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let order = [];
|
|
|
|
const field_types = page_params.custom_profile_field_types;
|
2018-04-08 18:13:37 +02:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function field_type_id_to_string(type_id) {
|
2020-02-08 05:09:09 +01:00
|
|
|
for (const field_type of Object.values(field_types)) {
|
2018-08-15 11:35:18 +02:00
|
|
|
if (field_type.id === type_id) {
|
2018-08-15 13:28:51 +02:00
|
|
|
// Few necessary modifications in field-type-name for
|
|
|
|
// table-list view of custom fields UI in org settings
|
|
|
|
if (field_type.name === "Date picker") {
|
2020-02-08 05:09:09 +01:00
|
|
|
return "Date";
|
2018-08-15 13:28:51 +02:00
|
|
|
} else if (field_type.name === "Person picker") {
|
2020-02-08 05:09:09 +01:00
|
|
|
return "Person";
|
2018-08-15 13:28:51 +02:00
|
|
|
}
|
2020-02-08 05:09:09 +01:00
|
|
|
return field_type.name;
|
2018-08-15 11:35:18 +02:00
|
|
|
}
|
2020-02-08 05:09:09 +01:00
|
|
|
}
|
2020-09-24 07:50:36 +02:00
|
|
|
return undefined;
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2018-08-15 13:37:40 +02:00
|
|
|
function update_profile_fields_table_element() {
|
2022-01-25 11:36:19 +01:00
|
|
|
const $profile_fields_table = $("#admin_profile_fields_table").expectOne();
|
2018-08-15 13:37:40 +02:00
|
|
|
|
|
|
|
// If there are no custom fields, hide the table headers at the top
|
|
|
|
if (page_params.custom_profile_fields.length < 1) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$profile_fields_table.hide();
|
2018-08-15 13:37:40 +02:00
|
|
|
} else {
|
2022-01-25 11:36:19 +01:00
|
|
|
$profile_fields_table.show();
|
2018-08-15 13:37:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-14 05:51:45 +01:00
|
|
|
function delete_profile_field(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
2018-04-10 20:47:15 +02:00
|
|
|
|
|
|
|
settings_ui.do_settings_change(
|
|
|
|
channel.del,
|
2020-07-15 01:29:15 +02:00
|
|
|
"/json/realm/profile_fields/" + encodeURIComponent($(this).attr("data-profile-field-id")),
|
2020-07-15 00:34:28 +02:00
|
|
|
{},
|
|
|
|
$("#admin-profile-field-status").expectOne(),
|
|
|
|
);
|
2018-08-15 13:37:40 +02:00
|
|
|
update_profile_fields_table_element();
|
2017-12-14 05:51:45 +01:00
|
|
|
}
|
|
|
|
|
2022-06-20 16:55:05 +02:00
|
|
|
function read_select_field_data_from_form(field_elem, old_field_data) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const field_data = {};
|
|
|
|
let field_order = 1;
|
2022-06-20 16:55:05 +02:00
|
|
|
|
|
|
|
const old_option_value_map = new Map();
|
|
|
|
if (old_field_data !== undefined) {
|
|
|
|
for (const [value, choice] of Object.entries(old_field_data)) {
|
|
|
|
old_option_value_map.set(choice.text, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
$(field_elem)
|
|
|
|
.find("div.choice-row")
|
|
|
|
.each(function () {
|
|
|
|
const text = $(this).find("input")[0].value;
|
|
|
|
if (text) {
|
2022-06-20 16:55:05 +02:00
|
|
|
if (old_option_value_map.get(text) !== undefined) {
|
|
|
|
// Resetting the data-value in the form is
|
|
|
|
// important if the user removed an option string
|
|
|
|
// and then added it back again before saving
|
|
|
|
// changes.
|
|
|
|
$(this).attr("data-value", old_option_value_map.get(text));
|
|
|
|
}
|
|
|
|
const value = $(this).attr("data-value");
|
|
|
|
field_data[value] = {text, order: field_order.toString()};
|
2020-07-15 00:34:28 +02:00
|
|
|
field_order += 1;
|
|
|
|
}
|
|
|
|
});
|
2018-08-02 19:31:17 +02:00
|
|
|
|
2018-04-12 11:17:52 +02:00
|
|
|
return field_data;
|
|
|
|
}
|
|
|
|
|
2019-05-27 10:59:55 +02:00
|
|
|
function read_external_account_field_data(field_elem) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const field_data = {};
|
2020-07-15 01:29:15 +02:00
|
|
|
field_data.subtype = $(field_elem).find("select[name=external_acc_field_type]").val();
|
2019-05-27 10:59:55 +02:00
|
|
|
if (field_data.subtype === "custom") {
|
2020-07-15 01:29:15 +02:00
|
|
|
field_data.url_pattern = $(field_elem).find("input[name=url_pattern]").val();
|
2019-05-27 10:59:55 +02:00
|
|
|
}
|
|
|
|
return field_data;
|
|
|
|
}
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
function update_choice_delete_btn($container, display_flag) {
|
|
|
|
const no_of_choice_row = $container.find(".choice-row").length;
|
2018-08-11 19:47:58 +02:00
|
|
|
|
|
|
|
// Disable delete button if there only one choice row
|
|
|
|
// Enable choice delete button more one than once choice
|
|
|
|
if (no_of_choice_row === 1) {
|
|
|
|
if (display_flag === true) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$container.find(".choice-row .delete-choice").show();
|
2018-08-11 19:47:58 +02:00
|
|
|
} else {
|
2022-01-25 11:36:19 +01:00
|
|
|
$container.find(".choice-row .delete-choice").hide();
|
2018-08-11 19:47:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-20 16:55:05 +02:00
|
|
|
function get_value_for_new_option(container) {
|
|
|
|
const $choice_rows = $(container).find(".choice-row");
|
|
|
|
if ($choice_rows.length === 0) {
|
|
|
|
// Value for the first option is 0.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const existing_option_values = [];
|
|
|
|
$choice_rows.each(function () {
|
|
|
|
existing_option_values.push(Number.parseInt($(this).attr("data-value"), 10));
|
|
|
|
});
|
|
|
|
existing_option_values.sort();
|
|
|
|
return existing_option_values[existing_option_values.length - 1] + 1;
|
|
|
|
}
|
|
|
|
|
2018-08-11 17:02:46 +02:00
|
|
|
function create_choice_row(container) {
|
2022-06-20 16:55:05 +02:00
|
|
|
const context = {value: get_value_for_new_option(container)};
|
2019-11-02 00:06:25 +01:00
|
|
|
const row = render_settings_profile_field_choice(context);
|
2018-05-10 13:36:09 +02:00
|
|
|
$(container).append(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
function clear_form_data() {
|
2019-07-30 00:10:23 +02:00
|
|
|
$("#profile_field_name").val("").closest(".control-group").show();
|
|
|
|
$("#profile_field_hint").val("").closest(".control-group").show();
|
2021-05-10 07:02:14 +02:00
|
|
|
// Set default type "Short text" in field type dropdown
|
2018-08-15 13:17:15 +02:00
|
|
|
$("#profile_field_type").val(field_types.SHORT_TEXT.id);
|
2021-03-24 12:24:52 +01:00
|
|
|
// Clear data from select field form
|
2018-05-10 13:36:09 +02:00
|
|
|
$("#profile_field_choices").html("");
|
2018-08-11 17:02:46 +02:00
|
|
|
create_choice_row($("#profile_field_choices"));
|
2018-08-11 19:47:58 +02:00
|
|
|
update_choice_delete_btn($("#profile_field_choices"), false);
|
2018-05-10 13:36:09 +02:00
|
|
|
$("#profile_field_choices_row").hide();
|
2019-05-27 10:59:55 +02:00
|
|
|
// Clear external account field form
|
|
|
|
$("#custom_field_url_pattern").val("");
|
|
|
|
$("#custom_external_account_url_pattern").hide();
|
|
|
|
$("#profile_field_external_accounts").hide();
|
2019-07-30 00:10:23 +02:00
|
|
|
$("#profile_field_external_accounts_type").val(
|
2022-03-16 22:29:41 +01:00
|
|
|
$("#profile_field_external_accounts_type option:first-child").val(),
|
2020-07-15 00:34:28 +02:00
|
|
|
);
|
2019-07-30 00:10:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function set_up_create_field_form() {
|
2022-01-25 11:36:19 +01:00
|
|
|
const $field_elem = $("#profile_field_external_accounts");
|
|
|
|
const $field_url_pattern_elem = $("#custom_external_account_url_pattern");
|
2019-07-30 00:10:23 +02:00
|
|
|
|
2020-10-07 09:17:30 +02:00
|
|
|
if (Number.parseInt($("#profile_field_type").val(), 10) === field_types.EXTERNAL_ACCOUNT.id) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$field_elem.show();
|
2020-07-15 01:29:15 +02:00
|
|
|
if ($("#profile_field_external_accounts_type").val() === "custom") {
|
2022-01-25 11:36:19 +01:00
|
|
|
$field_url_pattern_elem.show();
|
2019-07-30 00:10:23 +02:00
|
|
|
$("#profile_field_name").val("").closest(".control-group").show();
|
|
|
|
$("#profile_field_hint").val("").closest(".control-group").show();
|
|
|
|
} else {
|
2022-01-25 11:36:19 +01:00
|
|
|
$field_url_pattern_elem.hide();
|
2019-07-30 00:10:23 +02:00
|
|
|
$("#profile_field_name").closest(".control-group").hide();
|
|
|
|
$("#profile_field_hint").closest(".control-group").hide();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$("#profile_field_name").closest(".control-group").show();
|
|
|
|
$("#profile_field_hint").closest(".control-group").show();
|
2022-01-25 11:36:19 +01:00
|
|
|
$field_url_pattern_elem.hide();
|
|
|
|
$field_elem.hide();
|
2019-07-30 00:10:23 +02:00
|
|
|
}
|
2018-05-10 13:36:09 +02:00
|
|
|
}
|
|
|
|
|
2022-06-20 16:55:05 +02:00
|
|
|
function read_field_data_from_form(field_type_id, field_elem, old_field_data) {
|
2021-03-24 12:24:52 +01:00
|
|
|
// Only read field data if we are creating a select field
|
2019-05-27 10:59:55 +02:00
|
|
|
// or external account field.
|
2021-03-24 11:41:29 +01:00
|
|
|
if (field_type_id === field_types.SELECT.id) {
|
2022-06-20 16:55:05 +02:00
|
|
|
return read_select_field_data_from_form(field_elem, old_field_data);
|
2019-05-27 10:59:55 +02:00
|
|
|
} else if (field_type_id === field_types.EXTERNAL_ACCOUNT.id) {
|
|
|
|
return read_external_account_field_data(field_elem);
|
2019-06-07 08:19:00 +02:00
|
|
|
}
|
2020-09-24 07:50:36 +02:00
|
|
|
return undefined;
|
2019-06-07 08:19:00 +02:00
|
|
|
}
|
|
|
|
|
2017-12-14 05:51:45 +01:00
|
|
|
function create_profile_field(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let field_data = {};
|
2020-07-15 01:29:15 +02:00
|
|
|
const field_type = $("#profile_field_type").val();
|
2019-11-02 00:06:25 +01:00
|
|
|
const opts = {
|
2018-05-10 13:36:09 +02:00
|
|
|
success_continuation: clear_form_data,
|
|
|
|
};
|
2020-10-07 09:17:30 +02:00
|
|
|
field_data = read_field_data_from_form(
|
|
|
|
Number.parseInt(field_type, 10),
|
|
|
|
$(".new-profile-field-form"),
|
|
|
|
);
|
2019-07-30 00:10:23 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const form_data = {
|
2018-08-02 18:35:33 +02:00
|
|
|
name: $("#profile_field_name").val(),
|
2020-07-20 22:18:43 +02:00
|
|
|
field_type,
|
2018-08-02 18:35:33 +02:00
|
|
|
hint: $("#profile_field_hint").val(),
|
|
|
|
field_data: JSON.stringify(field_data),
|
|
|
|
};
|
2018-04-12 11:17:52 +02:00
|
|
|
|
2020-07-15 00:34:28 +02:00
|
|
|
settings_ui.do_settings_change(
|
|
|
|
channel.post,
|
|
|
|
"/json/realm/profile_fields",
|
|
|
|
form_data,
|
|
|
|
$("#admin-add-profile-field-status").expectOne(),
|
|
|
|
opts,
|
|
|
|
);
|
2018-08-15 13:37:40 +02:00
|
|
|
update_profile_fields_table_element();
|
2018-04-12 11:17:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function add_choice_row(e) {
|
2018-08-12 14:50:16 +02:00
|
|
|
if ($(e.target).parent().next().hasClass("choice-row")) {
|
|
|
|
return;
|
|
|
|
}
|
2019-11-02 00:06:25 +01:00
|
|
|
const choices_div = e.delegateTarget;
|
2018-08-12 14:50:16 +02:00
|
|
|
update_choice_delete_btn($(choices_div), true);
|
2018-08-11 17:02:46 +02:00
|
|
|
create_choice_row(choices_div);
|
2018-04-12 11:17:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function delete_choice_row(e) {
|
2022-01-25 11:36:19 +01:00
|
|
|
const $row = $(e.currentTarget).parent();
|
|
|
|
const $container = $row.parent();
|
|
|
|
$row.remove();
|
|
|
|
update_choice_delete_btn($container, false);
|
2018-04-12 11:17:52 +02:00
|
|
|
}
|
|
|
|
|
2022-06-21 13:42:10 +02:00
|
|
|
function show_modal_for_deleting_options(field, deleted_values, update_profile_field) {
|
|
|
|
const active_user_ids = people.get_active_user_ids();
|
|
|
|
let users_count_with_deleted_option_selected = 0;
|
|
|
|
for (const user_id of active_user_ids) {
|
|
|
|
const field_value = people.get_custom_profile_data(user_id, field.id);
|
|
|
|
if (field_value && deleted_values.has(field_value.value)) {
|
|
|
|
users_count_with_deleted_option_selected += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const html_body = render_confirm_delete_profile_field_option({
|
|
|
|
count: users_count_with_deleted_option_selected,
|
|
|
|
field_name: field.name,
|
|
|
|
});
|
|
|
|
|
|
|
|
confirm_dialog.launch({
|
|
|
|
html_heading: $t_html({defaultMessage: "Delete option"}),
|
|
|
|
html_body,
|
|
|
|
on_click: update_profile_field,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-14 05:51:45 +01:00
|
|
|
function get_profile_field_info(id) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const info = {};
|
2022-01-25 11:36:19 +01:00
|
|
|
info.$row = $(`tr.profile-field-row[data-profile-field-id='${CSS.escape(id)}']`);
|
|
|
|
info.$form = $(`tr.profile-field-form[data-profile-field-id='${CSS.escape(id)}']`);
|
2017-12-14 05:51:45 +01:00
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2018-05-10 13:36:09 +02:00
|
|
|
function get_profile_field(id) {
|
2020-10-07 10:41:58 +02:00
|
|
|
return page_params.custom_profile_fields.find((field) => field.id === id);
|
2018-05-10 13:36:09 +02:00
|
|
|
}
|
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function parse_field_choices_from_field_data(field_data) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const choices = [];
|
2020-02-06 06:34:47 +01:00
|
|
|
for (const [value, choice] of Object.entries(field_data)) {
|
2018-08-06 20:35:50 +02:00
|
|
|
choices.push({
|
2020-07-20 22:18:43 +02:00
|
|
|
value,
|
2018-08-06 20:35:50 +02:00
|
|
|
text: choice.text,
|
|
|
|
order: choice.order,
|
|
|
|
});
|
2020-02-06 06:34:47 +01:00
|
|
|
}
|
2022-06-20 16:55:05 +02:00
|
|
|
choices.sort((a, b) => a.order - b.order);
|
2018-08-06 20:35:50 +02:00
|
|
|
return choices;
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2018-08-06 20:35:50 +02:00
|
|
|
|
2019-05-27 10:59:55 +02:00
|
|
|
function set_up_external_account_field_edit_form(field_elem, url_pattern_val) {
|
2022-01-25 11:36:19 +01:00
|
|
|
if (field_elem.$form.find("select[name=external_acc_field_type]").val() === "custom") {
|
|
|
|
field_elem.$form.find("input[name=url_pattern]").val(url_pattern_val);
|
|
|
|
field_elem.$form.find(".custom_external_account_detail").show();
|
|
|
|
field_elem.$form.find("input[name=name]").val("").closest(".control-group").show();
|
|
|
|
field_elem.$form.find("input[name=hint]").val("").closest(".control-group").show();
|
2019-05-27 10:59:55 +02:00
|
|
|
} else {
|
2022-01-25 11:36:19 +01:00
|
|
|
field_elem.$form.find("input[name=name]").closest(".control-group").hide();
|
|
|
|
field_elem.$form.find("input[name=hint]").closest(".control-group").hide();
|
|
|
|
field_elem.$form.find(".custom_external_account_detail").hide();
|
2019-05-27 10:59:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 12:24:52 +01:00
|
|
|
function set_up_select_field_edit_form(profile_field, field_data) {
|
|
|
|
// Re-render field choices in edit form to load initial select data
|
2022-01-25 11:36:19 +01:00
|
|
|
const $choice_list = profile_field.$form.find(".edit_profile_field_choices_container");
|
|
|
|
$choice_list.off();
|
|
|
|
$choice_list.html("");
|
2019-06-06 13:14:34 +02:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
const choices_data = parse_field_choices_from_field_data(field_data);
|
2019-06-06 13:14:34 +02:00
|
|
|
|
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
|
|
|
for (const choice of choices_data) {
|
2022-01-25 11:36:19 +01:00
|
|
|
$choice_list.append(
|
2019-07-09 21:24:00 +02:00
|
|
|
render_settings_profile_field_choice({
|
2019-06-06 13:14:34 +02:00
|
|
|
text: choice.text,
|
2022-06-20 16:55:05 +02:00
|
|
|
value: choice.value,
|
2020-07-02 02:16:03 +02:00
|
|
|
}),
|
2019-06-06 13:14:34 +02:00
|
|
|
);
|
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
|
|
|
}
|
2019-06-06 13:14:34 +02:00
|
|
|
|
|
|
|
// Add blank choice at last
|
2022-01-25 11:36:19 +01:00
|
|
|
create_choice_row($choice_list);
|
|
|
|
update_choice_delete_btn($choice_list, false);
|
|
|
|
Sortable.create($choice_list[0], {
|
2020-07-20 22:18:43 +02:00
|
|
|
onUpdate() {},
|
2021-03-15 13:25:35 +01:00
|
|
|
filter: "input",
|
|
|
|
preventOnFilter: false,
|
2019-06-06 13:14:34 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-14 05:51:45 +01:00
|
|
|
function open_edit_form(e) {
|
2020-10-07 09:17:30 +02:00
|
|
|
const field_id = Number.parseInt($(e.currentTarget).attr("data-profile-field-id"), 10);
|
2019-11-02 00:06:25 +01:00
|
|
|
const profile_field = get_profile_field_info(field_id);
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$row.hide();
|
|
|
|
profile_field.$form.show();
|
2020-01-16 20:40:59 +01:00
|
|
|
const field = get_profile_field(field_id);
|
2019-11-02 00:06:25 +01:00
|
|
|
let field_data = {};
|
2019-06-06 13:14:34 +02:00
|
|
|
if (field.field_data) {
|
|
|
|
field_data = JSON.parse(field.field_data);
|
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2021-03-24 11:41:29 +01:00
|
|
|
if (Number.parseInt(field.type, 10) === field_types.SELECT.id) {
|
2021-03-24 12:24:52 +01:00
|
|
|
set_up_select_field_edit_form(profile_field, field_data);
|
2018-08-02 19:31:17 +02:00
|
|
|
}
|
|
|
|
|
2020-10-07 09:17:30 +02:00
|
|
|
if (Number.parseInt(field.type, 10) === field_types.EXTERNAL_ACCOUNT.id) {
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form.find("select[name=external_acc_field_type]").val(field_data.subtype);
|
2019-05-27 10:59:55 +02:00
|
|
|
set_up_external_account_field_edit_form(profile_field, field_data.url_pattern);
|
|
|
|
}
|
|
|
|
|
2022-02-28 15:36:05 +01:00
|
|
|
// Set initial value in edit form
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form.find("input[name=name]").val(field.name);
|
|
|
|
profile_field.$form.find("input[name=hint]").val(field.hint);
|
2022-02-28 15:36:05 +01:00
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form.find(".reset").on("click", () => {
|
2022-06-21 13:42:10 +02:00
|
|
|
// If we do not turn off the click handler, the code is called twice in case
|
|
|
|
// when the edit form is closed and then opened again. And in such case two
|
|
|
|
// modals are opened and one of them is shown randomly.
|
|
|
|
profile_field.$form.find(".submit").off("click");
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form.hide();
|
|
|
|
profile_field.$row.show();
|
2017-12-14 05:51:45 +01:00
|
|
|
});
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form.find(".submit").on("click", () => {
|
2017-12-14 05:51:45 +01:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
const $profile_field_status = $("#admin-profile-field-status").expectOne();
|
2017-12-14 05:51:45 +01:00
|
|
|
|
|
|
|
// For some reason jQuery's serialize() is not working with
|
|
|
|
// channel.patch even though it is supported by $.ajax.
|
2019-11-02 00:06:25 +01:00
|
|
|
const data = {};
|
2019-07-30 00:10:23 +02:00
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
data.name = profile_field.$form.find("input[name=name]").val();
|
|
|
|
data.hint = profile_field.$form.find("input[name=hint]").val();
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2022-06-21 13:42:10 +02:00
|
|
|
const new_field_data = read_field_data_from_form(
|
|
|
|
Number.parseInt(field.type, 10),
|
|
|
|
profile_field.$form,
|
|
|
|
field_data,
|
2020-07-15 00:34:28 +02:00
|
|
|
);
|
2022-06-21 13:42:10 +02:00
|
|
|
data.field_data = JSON.stringify(new_field_data);
|
|
|
|
|
|
|
|
function update_profile_field() {
|
|
|
|
settings_ui.do_settings_change(
|
|
|
|
channel.patch,
|
|
|
|
"/json/realm/profile_fields/" + field_id,
|
|
|
|
data,
|
|
|
|
$profile_field_status,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (field.type === field_types.SELECT.id) {
|
|
|
|
const old_values = new Set(Object.keys(field_data));
|
|
|
|
const new_values = new Set(Object.keys(new_field_data));
|
|
|
|
const deleted_values = new Set(
|
|
|
|
[...old_values].filter((value) => !new_values.has(value)),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (deleted_values.size !== 0) {
|
|
|
|
show_modal_for_deleting_options(field, deleted_values, update_profile_field);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update_profile_field();
|
2017-12-14 05:51:45 +01:00
|
|
|
});
|
2018-04-12 11:17:52 +02:00
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form
|
2020-07-15 00:34:28 +02:00
|
|
|
.find(".edit_profile_field_choices_container")
|
|
|
|
.on("input", ".choice-row input", add_choice_row);
|
2022-01-25 11:36:19 +01:00
|
|
|
profile_field.$form
|
2020-07-15 00:34:28 +02:00
|
|
|
.find(".edit_profile_field_choices_container")
|
|
|
|
.on("click", "button.delete-choice", delete_choice_row);
|
2020-07-15 01:29:15 +02:00
|
|
|
$(".profile_field_external_accounts_edit select").on("change", (e) => {
|
2020-10-07 09:17:30 +02:00
|
|
|
const field_id = Number.parseInt(
|
2020-07-15 00:34:28 +02:00
|
|
|
$(e.target).closest(".profile-field-form").attr("data-profile-field-id"),
|
|
|
|
10,
|
|
|
|
);
|
2019-11-02 00:06:25 +01:00
|
|
|
const field_form = get_profile_field_info(field_id);
|
2019-05-27 10:59:55 +02:00
|
|
|
set_up_external_account_field_edit_form(field_form, "");
|
|
|
|
});
|
2017-12-14 05:51:45 +01:00
|
|
|
}
|
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function reset() {
|
2017-12-14 05:51:45 +01:00
|
|
|
meta.loaded = false;
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2018-06-09 09:37:59 +02:00
|
|
|
function update_field_order() {
|
|
|
|
order = [];
|
2020-07-15 01:29:15 +02:00
|
|
|
$(".profile-field-row").each(function () {
|
2020-10-07 09:17:30 +02:00
|
|
|
order.push(Number.parseInt($(this).attr("data-profile-field-id"), 10));
|
2018-06-09 09:37:59 +02:00
|
|
|
});
|
2020-07-15 00:34:28 +02:00
|
|
|
settings_ui.do_settings_change(
|
|
|
|
channel.patch,
|
|
|
|
"/json/realm/profile_fields",
|
|
|
|
{order: JSON.stringify(order)},
|
|
|
|
$("#admin-profile-field-status").expectOne(),
|
|
|
|
);
|
2018-06-09 09:37:59 +02:00
|
|
|
}
|
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function populate_profile_fields(profile_fields_data) {
|
2017-12-14 05:51:45 +01:00
|
|
|
if (!meta.loaded) {
|
2018-06-11 21:02:00 +02:00
|
|
|
// If outside callers call us when we're not loaded, just
|
|
|
|
// exit and we'll draw the widgets again during set_up().
|
2017-12-14 05:51:45 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-02-28 21:34:05 +01:00
|
|
|
do_populate_profile_fields(profile_fields_data);
|
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function do_populate_profile_fields(profile_fields_data) {
|
2018-06-11 21:02:00 +02:00
|
|
|
// We should only call this internally or from tests.
|
2022-01-25 11:36:19 +01:00
|
|
|
const $profile_fields_table = $("#admin_profile_fields_table").expectOne();
|
2018-06-09 09:37:59 +02:00
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
$profile_fields_table.find("tr.profile-field-row").remove(); // Clear all rows.
|
|
|
|
$profile_fields_table.find("tr.profile-field-form").remove(); // Clear all rows.
|
2018-04-08 18:13:37 +02:00
|
|
|
order = [];
|
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
|
|
|
|
|
|
|
for (const profile_field of profile_fields_data) {
|
2018-04-08 18:13:37 +02:00
|
|
|
order.push(profile_field.id);
|
2019-11-02 00:06:25 +01:00
|
|
|
let field_data = {};
|
2019-06-07 08:19:00 +02:00
|
|
|
if (profile_field.field_data) {
|
2018-04-12 11:17:52 +02:00
|
|
|
field_data = JSON.parse(profile_field.field_data);
|
|
|
|
}
|
2019-11-02 00:06:25 +01:00
|
|
|
let choices = [];
|
2021-03-24 11:41:29 +01:00
|
|
|
if (profile_field.type === field_types.SELECT.id) {
|
2021-02-28 21:34:05 +01:00
|
|
|
choices = parse_field_choices_from_field_data(field_data);
|
2018-04-12 11:17:52 +02:00
|
|
|
}
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
$profile_fields_table.append(
|
2019-07-09 21:24:00 +02:00
|
|
|
render_admin_profile_field_list({
|
|
|
|
profile_field: {
|
|
|
|
id: profile_field.id,
|
|
|
|
name: profile_field.name,
|
|
|
|
hint: profile_field.hint,
|
2021-02-28 21:34:05 +01:00
|
|
|
type: field_type_id_to_string(profile_field.type),
|
2020-07-20 22:18:43 +02:00
|
|
|
choices,
|
2021-03-24 11:41:29 +01:00
|
|
|
is_select_field: profile_field.type === field_types.SELECT.id,
|
2020-07-15 00:34:28 +02:00
|
|
|
is_external_account_field:
|
|
|
|
profile_field.type === field_types.EXTERNAL_ACCOUNT.id,
|
2019-07-09 21:24:00 +02:00
|
|
|
},
|
|
|
|
can_modify: page_params.is_admin,
|
|
|
|
realm_default_external_accounts: page_params.realm_default_external_accounts,
|
2020-07-02 02:16:03 +02:00
|
|
|
}),
|
2017-12-14 05:51:45 +01:00
|
|
|
);
|
js: Automatically convert _.each to for…of.
This commit was automatically generated by the following script,
followed by lint --fix and a few small manual lint-related cleanups.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import { Context } from "ast-types/lib/path-visitor";
import K from "ast-types/gen/kinds";
import { NodePath } from "ast-types/lib/node-path";
import assert from "assert";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
const checkStatement = (node: n.Node): node is K.StatementKind =>
n.Statement.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
let inLoop = false;
let replaceReturn = false;
const visitLoop = (...args: string[]) =>
function(this: Context, path: NodePath) {
for (const arg of args) {
this.visit(path.get(arg));
}
const old = { inLoop };
inLoop = true;
this.visit(path.get("body"));
inLoop = old.inLoop;
return false;
};
recast.visit(ast, {
visitDoWhileStatement: visitLoop("test"),
visitExpressionStatement(path) {
const { expression, comments } = path.node;
let valueOnly;
if (
n.CallExpression.check(expression) &&
n.MemberExpression.check(expression.callee) &&
!expression.callee.computed &&
n.Identifier.check(expression.callee.object) &&
expression.callee.object.name === "_" &&
n.Identifier.check(expression.callee.property) &&
["each", "forEach"].includes(expression.callee.property.name) &&
[2, 3].includes(expression.arguments.length) &&
checkExpression(expression.arguments[0]) &&
(n.FunctionExpression.check(expression.arguments[1]) ||
n.ArrowFunctionExpression.check(expression.arguments[1])) &&
[1, 2].includes(expression.arguments[1].params.length) &&
n.Identifier.check(expression.arguments[1].params[0]) &&
((valueOnly = expression.arguments[1].params[1] === undefined) ||
n.Identifier.check(expression.arguments[1].params[1])) &&
(expression.arguments[2] === undefined ||
n.ThisExpression.check(expression.arguments[2]))
) {
const old = { inLoop, replaceReturn };
inLoop = false;
replaceReturn = true;
this.visit(
path
.get("expression")
.get("arguments")
.get(1)
.get("body")
);
inLoop = old.inLoop;
replaceReturn = old.replaceReturn;
const [right, { body, params }] = expression.arguments;
const loop = b.forOfStatement(
b.variableDeclaration("let", [
b.variableDeclarator(
valueOnly ? params[0] : b.arrayPattern([params[1], params[0]])
),
]),
valueOnly
? right
: b.callExpression(
b.memberExpression(right, b.identifier("entries")),
[]
),
checkStatement(body) ? body : b.expressionStatement(body)
);
loop.comments = comments;
path.replace(loop);
changed = true;
}
this.traverse(path);
},
visitForStatement: visitLoop("init", "test", "update"),
visitForInStatement: visitLoop("left", "right"),
visitForOfStatement: visitLoop("left", "right"),
visitFunction(path) {
this.visit(path.get("params"));
const old = { replaceReturn };
replaceReturn = false;
this.visit(path.get("body"));
replaceReturn = old.replaceReturn;
return false;
},
visitReturnStatement(path) {
if (replaceReturn) {
assert(!inLoop); // could use labeled continue if this ever fires
const { argument, comments } = path.node;
if (argument === null) {
const s = b.continueStatement();
s.comments = comments;
path.replace(s);
} else {
const s = b.expressionStatement(argument);
s.comments = comments;
path.replace(s, b.continueStatement());
}
return false;
}
this.traverse(path);
},
visitWhileStatement: visitLoop("test"),
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-06 06:19:47 +01:00
|
|
|
}
|
|
|
|
|
2018-06-09 09:37:59 +02:00
|
|
|
if (page_params.is_admin) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const field_list = $("#admin_profile_fields_table")[0];
|
2021-03-10 06:36:44 +01:00
|
|
|
Sortable.create(field_list, {
|
2018-06-09 09:37:59 +02:00
|
|
|
onUpdate: update_field_order,
|
2021-03-15 13:25:35 +01:00
|
|
|
filter: "input",
|
|
|
|
preventOnFilter: false,
|
2018-06-09 09:37:59 +02:00
|
|
|
});
|
|
|
|
}
|
2018-08-15 13:37:40 +02:00
|
|
|
|
|
|
|
update_profile_fields_table_element();
|
2020-07-15 01:29:15 +02:00
|
|
|
loading.destroy_indicator($("#admin_page_profile_fields_loading_indicator"));
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2021-03-24 12:24:52 +01:00
|
|
|
function set_up_select_field() {
|
2020-07-15 01:29:15 +02:00
|
|
|
create_choice_row("#profile_field_choices");
|
2018-08-11 19:47:58 +02:00
|
|
|
update_choice_delete_btn($("#profile_field_choices"), false);
|
2018-04-12 11:17:52 +02:00
|
|
|
|
2018-08-24 06:40:40 +02:00
|
|
|
if (page_params.is_admin) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const choice_list = $("#profile_field_choices")[0];
|
2021-03-10 06:36:44 +01:00
|
|
|
Sortable.create(choice_list, {
|
2020-07-20 22:18:43 +02:00
|
|
|
onUpdate() {},
|
2021-03-15 13:25:35 +01:00
|
|
|
filter: "input",
|
|
|
|
preventOnFilter: false,
|
2018-08-24 06:40:40 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
const field_type = $("#profile_field_type").val();
|
2018-08-02 19:31:17 +02:00
|
|
|
|
2021-03-24 11:41:29 +01:00
|
|
|
if (Number.parseInt(field_type, 10) !== field_types.SELECT.id) {
|
2021-03-24 12:24:52 +01:00
|
|
|
// If 'Select' type is already selected, show choice row.
|
2018-04-12 11:17:52 +02:00
|
|
|
$("#profile_field_choices_row").hide();
|
|
|
|
}
|
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
$("#profile_field_type").on("change", (e) => {
|
2020-10-07 09:17:30 +02:00
|
|
|
const selected_field_id = Number.parseInt($(e.target).val(), 10);
|
2021-03-24 11:41:29 +01:00
|
|
|
if (selected_field_id === field_types.SELECT.id) {
|
2018-04-12 11:17:52 +02:00
|
|
|
$("#profile_field_choices_row").show();
|
|
|
|
} else {
|
|
|
|
$("#profile_field_choices_row").hide();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-08-12 14:50:16 +02:00
|
|
|
$("#profile_field_choices").on("input", ".choice-row input", add_choice_row);
|
2018-04-12 11:17:52 +02:00
|
|
|
$("#profile_field_choices").on("click", "button.delete-choice", delete_choice_row);
|
|
|
|
}
|
|
|
|
|
2019-05-27 10:59:55 +02:00
|
|
|
function set_up_external_account_field() {
|
2020-07-15 01:29:15 +02:00
|
|
|
$("#profile_field_type").on("change", () => {
|
2019-07-30 00:10:23 +02:00
|
|
|
set_up_create_field_form();
|
2019-05-27 10:59:55 +02:00
|
|
|
});
|
2019-07-30 00:10:23 +02:00
|
|
|
|
2020-07-02 01:45:54 +02:00
|
|
|
$("#profile_field_external_accounts_type").on("change", () => {
|
2019-07-30 00:10:23 +02:00
|
|
|
set_up_create_field_form();
|
2019-05-27 10:59:55 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function get_external_account_link(field) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const field_subtype = field.field_data.subtype;
|
|
|
|
let field_url_pattern;
|
2019-05-27 10:59:55 +02:00
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
if (field_subtype === "custom") {
|
2019-05-27 10:59:55 +02:00
|
|
|
field_url_pattern = field.field_data.url_pattern;
|
|
|
|
} else {
|
2020-07-15 00:34:28 +02:00
|
|
|
field_url_pattern = page_params.realm_default_external_accounts[field_subtype].url_pattern;
|
2019-05-27 10:59:55 +02:00
|
|
|
}
|
2020-07-15 01:29:15 +02:00
|
|
|
return field_url_pattern.replace("%(username)s", field.value);
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|
2019-05-27 10:59:55 +02:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function set_up() {
|
|
|
|
build_page();
|
|
|
|
maybe_disable_widgets();
|
|
|
|
}
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2021-02-28 21:34:05 +01:00
|
|
|
export function build_page() {
|
2017-12-14 05:51:45 +01:00
|
|
|
// create loading indicators
|
2020-07-15 01:29:15 +02:00
|
|
|
loading.make_indicator($("#admin_page_profile_fields_loading_indicator"));
|
2017-12-14 05:51:45 +01:00
|
|
|
// Populate profile_fields table
|
2021-02-28 21:34:05 +01:00
|
|
|
do_populate_profile_fields(page_params.custom_profile_fields);
|
2018-06-11 21:02:00 +02:00
|
|
|
meta.loaded = true;
|
2017-12-14 05:51:45 +01:00
|
|
|
|
2020-07-15 01:29:15 +02:00
|
|
|
$("#admin_profile_fields_table").on("click", ".delete", delete_profile_field);
|
2018-08-02 18:35:33 +02:00
|
|
|
$("#profile-field-settings").on("click", "#add-custom-profile-field-btn", create_profile_field);
|
2017-12-14 05:51:45 +01:00
|
|
|
$("#admin_profile_fields_table").on("click", ".open-edit-form", open_edit_form);
|
2021-03-24 12:24:52 +01:00
|
|
|
set_up_select_field();
|
2019-05-27 10:59:55 +02:00
|
|
|
set_up_external_account_field();
|
2018-08-15 13:38:18 +02:00
|
|
|
clear_form_data();
|
2021-02-28 21:34:05 +01:00
|
|
|
}
|