Added the possibility to select icons within the permission editor
parent
c0601d4682
commit
64fce4f3c6
|
@ -591,15 +591,31 @@ class IconManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadIcon(id: number) : Promise<Icon> {
|
download_icon(id: number) : Promise<Icon> {
|
||||||
return this._loading_promises[id] || (this._loading_promises[id] = this._load_icon(id));
|
return this._loading_promises[id] || (this._loading_promises[id] = this._load_icon(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async resolve_icon(id: number) : Promise<Icon> {
|
||||||
|
id = id >>> 0;
|
||||||
|
try {
|
||||||
|
return await this.resolved_cached(id);
|
||||||
|
} catch(error) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await this.download_icon(id);
|
||||||
|
} catch(error) {
|
||||||
|
console.error(tr("Icon download failed of icon %d: %o"), id, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "icon not found";
|
||||||
|
}
|
||||||
|
|
||||||
generateTag(id: number, options?: {
|
generateTag(id: number, options?: {
|
||||||
animate?: boolean
|
animate?: boolean
|
||||||
}) : JQuery<HTMLDivElement> {
|
}) : JQuery<HTMLDivElement> {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
id = id >>> 0;
|
||||||
if(id == 0)
|
if(id == 0)
|
||||||
return $.spawn("div").addClass("icon_empty");
|
return $.spawn("div").addClass("icon_empty");
|
||||||
else if(id < 1000)
|
else if(id < 1000)
|
||||||
|
@ -617,18 +633,7 @@ class IconManager {
|
||||||
icon_load_image.appendTo(icon_container);
|
icon_load_image.appendTo(icon_container);
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
let icon: Icon;
|
let icon: Icon = await this.resolve_icon(id);
|
||||||
try {
|
|
||||||
icon = await this.resolved_cached(id);
|
|
||||||
} catch(error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!icon)
|
|
||||||
icon = await this.loadIcon(id);
|
|
||||||
|
|
||||||
if(!icon)
|
|
||||||
throw "failed to download icon";
|
|
||||||
|
|
||||||
icon_image.attr("src", icon.url);
|
icon_image.attr("src", icon.url);
|
||||||
icon_container.append(icon_image).removeClass("icon_empty");
|
icon_container.append(icon_image).removeClass("icon_empty");
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace Modals {
|
||||||
|
|
||||||
private entry_editor: ui.PermissionEditor;
|
private entry_editor: ui.PermissionEditor;
|
||||||
|
|
||||||
|
icon_resolver: (id: number) => Promise<HTMLImageElement>;
|
||||||
|
icon_selector: (current_id: number) => Promise<number>;
|
||||||
|
|
||||||
constructor(permissions: GroupedPermissions[]) {
|
constructor(permissions: GroupedPermissions[]) {
|
||||||
this.permissions = permissions;
|
this.permissions = permissions;
|
||||||
this.entry_editor = new ui.PermissionEditor(permissions);
|
this.entry_editor = new ui.PermissionEditor(permissions);
|
||||||
|
@ -167,6 +170,15 @@ namespace Modals {
|
||||||
element.flag_negate = entry.flag_negate;
|
element.flag_negate = entry.flag_negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(permission.name === "i_icon_id") {
|
||||||
|
this.icon_resolver(entry.value).then(e => {
|
||||||
|
entry.set_icon_id_image(e);
|
||||||
|
entry.request_full_draw();
|
||||||
|
this.entry_editor.request_draw(false);
|
||||||
|
}).catch(error => {
|
||||||
|
console.warn(tr("Failed to load icon for permission editor: %o"), error);
|
||||||
|
});
|
||||||
|
}
|
||||||
entry.request_full_draw();
|
entry.request_full_draw();
|
||||||
this.entry_editor.request_draw(false);
|
this.entry_editor.request_draw(false);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -301,10 +313,21 @@ namespace Modals {
|
||||||
entry.value = value.value;
|
entry.value = value.value;
|
||||||
entry.flag_skip = value.flag_skip;
|
entry.flag_skip = value.flag_skip;
|
||||||
entry.flag_negate = value.flag_negate;
|
entry.flag_negate = value.flag_negate;
|
||||||
|
if(permission.name === "i_icon_id") {
|
||||||
|
this.icon_resolver(value.value).then(e => {
|
||||||
|
entry.set_icon_id_image(e);
|
||||||
|
entry.request_full_draw();
|
||||||
|
this.entry_editor.request_draw(false);
|
||||||
|
}).catch(error => {
|
||||||
|
console.warn(tr("Failed to load icon for permission editor: %o"), error);
|
||||||
|
});
|
||||||
|
entry.on_icon_select = this.icon_selector;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
entry.value = undefined;
|
entry.value = undefined;
|
||||||
entry.flag_skip = false;
|
entry.flag_skip = false;
|
||||||
entry.flag_negate = false;
|
entry.flag_negate = false;
|
||||||
|
entry.set_icon_id_image(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(value && value.hasGrant()) {
|
if(value && value.hasGrant()) {
|
||||||
|
@ -353,6 +376,22 @@ namespace Modals {
|
||||||
let tag = $("#tmpl_server_permissions").renderTag(properties);
|
let tag = $("#tmpl_server_permissions").renderTag(properties);
|
||||||
const pe = new PermissionEditor(connection.permissions.groupedPermissions());
|
const pe = new PermissionEditor(connection.permissions.groupedPermissions());
|
||||||
pe.build_tag();
|
pe.build_tag();
|
||||||
|
pe.icon_resolver = id => connection.fileManager.icons.resolve_icon(id).then(async icon => {
|
||||||
|
if(!icon)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
const tag = document.createElement("img");
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
tag.onerror = reject;
|
||||||
|
tag.onload = resolve;
|
||||||
|
tag.src = icon.url;
|
||||||
|
});
|
||||||
|
return tag;
|
||||||
|
});
|
||||||
|
pe.icon_selector = current_icon => new Promise<number>(resolve => {
|
||||||
|
spawnIconSelect(connection, id => resolve(new Int32Array([id])[0]), current_icon);
|
||||||
|
});
|
||||||
|
|
||||||
/* initialisation */
|
/* initialisation */
|
||||||
{
|
{
|
||||||
const pe_server = tag.find("permission-editor.group-server");
|
const pe_server = tag.find("permission-editor.group-server");
|
||||||
|
@ -972,6 +1011,7 @@ namespace Modals {
|
||||||
let current_group;
|
let current_group;
|
||||||
|
|
||||||
/* list all groups */
|
/* list all groups */
|
||||||
|
let update_icon: (icon_id: number) => any;
|
||||||
{
|
{
|
||||||
let group_list = tab_tag.find(".list-group-server .entries");
|
let group_list = tab_tag.find(".list-group-server .entries");
|
||||||
|
|
||||||
|
@ -986,7 +1026,10 @@ namespace Modals {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let tag = $.spawn("div").addClass("group").attr("group-id", group.id);
|
let tag = $.spawn("div").addClass("group").attr("group-id", group.id);
|
||||||
connection.fileManager.icons.generateTag(group.properties.iconid).appendTo(tag);
|
let icon_tag = connection.fileManager.icons.generateTag(group.properties.iconid);
|
||||||
|
icon_tag.appendTo(tag);
|
||||||
|
const _update_icon = icon_id => icon_tag.replaceWith(icon_tag = connection.fileManager.icons.generateTag(icon_id));
|
||||||
|
|
||||||
{
|
{
|
||||||
let name = $.spawn("a").text(group.name + " (" + group.id + ")").addClass("name");
|
let name = $.spawn("a").text(group.name + " (" + group.id + ")").addClass("name");
|
||||||
if(group.properties.savedb)
|
if(group.properties.savedb)
|
||||||
|
@ -999,6 +1042,7 @@ namespace Modals {
|
||||||
|
|
||||||
tag.on('click', event => {
|
tag.on('click', event => {
|
||||||
current_group = group;
|
current_group = group;
|
||||||
|
update_icon = _update_icon;
|
||||||
group_list.find(".selected").removeClass("selected");
|
group_list.find(".selected").removeClass("selected");
|
||||||
tag.addClass("selected");
|
tag.addClass("selected");
|
||||||
editor.trigger_update();
|
editor.trigger_update();
|
||||||
|
@ -1042,6 +1086,10 @@ namespace Modals {
|
||||||
return connection.serverConnection.send_command("servergroupdelperm", {
|
return connection.serverConnection.send_command("servergroupdelperm", {
|
||||||
sgid: current_group.id,
|
sgid: current_group.id,
|
||||||
permid: permission.id,
|
permid: permission.id,
|
||||||
|
}).then(e => {
|
||||||
|
if(permission.name === "i_icon_id" && update_icon)
|
||||||
|
update_icon(0);
|
||||||
|
return e;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log.info(LogCategory.PERMISSIONS, tr("Removing server group grant permission %s. permission.id: %o"),
|
log.info(LogCategory.PERMISSIONS, tr("Removing server group grant permission %s. permission.id: %o"),
|
||||||
|
@ -1072,6 +1120,10 @@ namespace Modals {
|
||||||
permvalue: value.value,
|
permvalue: value.value,
|
||||||
permskip: value.flag_skip,
|
permskip: value.flag_skip,
|
||||||
permnegate: value.flag_negate
|
permnegate: value.flag_negate
|
||||||
|
}).then(e => {
|
||||||
|
if(permission.name === "i_icon_id" && update_icon)
|
||||||
|
update_icon(value.value);
|
||||||
|
return e;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log.info(LogCategory.PERMISSIONS, tr("Adding or updating server group grant permission %s. permission.{id: %o, value: %o}"),
|
log.info(LogCategory.PERMISSIONS, tr("Adding or updating server group grant permission %s. permission.{id: %o, value: %o}"),
|
||||||
|
|
|
@ -459,7 +459,9 @@ namespace ui {
|
||||||
private _listener_value: InteractionListener;
|
private _listener_value: InteractionListener;
|
||||||
private _listener_grant: InteractionListener;
|
private _listener_grant: InteractionListener;
|
||||||
private _listener_general: InteractionListener;
|
private _listener_general: InteractionListener;
|
||||||
|
private _icon_image: HTMLImageElement | undefined;
|
||||||
|
|
||||||
|
on_icon_select?: (current_id: number) => Promise<number>;
|
||||||
on_context_menu?: (x: number, y: number) => any;
|
on_context_menu?: (x: number, y: number) => any;
|
||||||
on_grant_change?: () => any;
|
on_grant_change?: () => any;
|
||||||
on_change?: () => any;
|
on_change?: () => any;
|
||||||
|
@ -469,6 +471,16 @@ namespace ui {
|
||||||
this._permission = permission;
|
this._permission = permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_icon_id_image(image: HTMLImageElement | undefined) {
|
||||||
|
if(this._icon_image === image)
|
||||||
|
return;
|
||||||
|
this._icon_image = image;
|
||||||
|
if(image) {
|
||||||
|
image.height = 16;
|
||||||
|
image.width = 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
permission() { return this._permission; }
|
permission() { return this._permission; }
|
||||||
|
|
||||||
draw(ctx: CanvasRenderingContext2D, full: boolean) {
|
draw(ctx: CanvasRenderingContext2D, full: boolean) {
|
||||||
|
@ -561,11 +573,19 @@ namespace ui {
|
||||||
const x = w + PermissionEntry.COLUMN_VALUE - PermissionEntry.CHECKBOX_HEIGHT;
|
const x = w + PermissionEntry.COLUMN_VALUE - PermissionEntry.CHECKBOX_HEIGHT;
|
||||||
const y = 1;
|
const y = 1;
|
||||||
|
|
||||||
|
this._listener_value.region.width = PermissionEntry.CHECKBOX_HEIGHT;
|
||||||
this._listener_value.region.x = original_x + x;
|
this._listener_value.region.x = original_x + x;
|
||||||
this._listener_value.region.y = original_y + y;
|
this._listener_value.region.y = original_y + y;
|
||||||
|
|
||||||
this._draw_checkbox_field(ctx, this.colors.permission.value_b, x, y, PermissionEntry.CHECKBOX_HEIGHT, this.value > 0, this.flag_value_hovered);
|
this._draw_checkbox_field(ctx, this.colors.permission.value_b, x, y, PermissionEntry.CHECKBOX_HEIGHT, this.value > 0, this.flag_value_hovered);
|
||||||
|
} else if(this._permission.name === "i_icon_id" && this._icon_image) {
|
||||||
|
this._listener_value.region.x = original_x + w;
|
||||||
|
this._listener_value.region.y = original_y;
|
||||||
|
this._listener_value.region.width = PermissionEntry.CHECKBOX_HEIGHT;
|
||||||
|
|
||||||
|
this._draw_icon_field(ctx, this.colors.permission.value_b, w, 0, PermissionEntry.COLUMN_VALUE, this.flag_value_hovered, this._icon_image);
|
||||||
} else {
|
} else {
|
||||||
|
this._listener_value.region.width = PermissionEntry.COLUMN_VALUE;
|
||||||
this._listener_value.region.x = original_x + w;
|
this._listener_value.region.x = original_x + w;
|
||||||
this._listener_value.region.y = original_y;
|
this._listener_value.region.y = original_y;
|
||||||
|
|
||||||
|
@ -600,6 +620,20 @@ namespace ui {
|
||||||
this._listener_general.region.x = -1e8;
|
this._listener_general.region.x = -1e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _draw_icon_field(ctx: CanvasRenderingContext2D, scheme: scheme.CheckBox, x: number, y: number, width: number, hovered: boolean, image: HTMLImageElement) {
|
||||||
|
const line = ctx.lineWidth;
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.fillStyle = scheme.border;
|
||||||
|
ctx.strokeRect(x + 1, y + 1, PermissionEntry.HEIGHT - 2, PermissionEntry.HEIGHT - 2);
|
||||||
|
ctx.lineWidth = line;
|
||||||
|
|
||||||
|
ctx.fillStyle = hovered ? scheme.background_hovered : scheme.background;
|
||||||
|
ctx.fillRect(x + 1, y + 1, PermissionEntry.HEIGHT - 2, PermissionEntry.HEIGHT - 2);
|
||||||
|
|
||||||
|
const center_y = y + PermissionEntry.HEIGHT / 2;
|
||||||
|
const center_x = x + PermissionEntry.HEIGHT / 2;
|
||||||
|
ctx.drawImage(image, center_x - image.width / 2, center_y - image.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
private _draw_number_field(ctx: CanvasRenderingContext2D, scheme: scheme.TextField, x: number, y: number, width: number, value: number, hovered: boolean) {
|
private _draw_number_field(ctx: CanvasRenderingContext2D, scheme: scheme.TextField, x: number, y: number, width: number, value: number, hovered: boolean) {
|
||||||
ctx.fillStyle = hovered ? scheme.background_hovered : scheme.background;
|
ctx.fillStyle = hovered ? scheme.background_hovered : scheme.background;
|
||||||
|
@ -721,6 +755,14 @@ namespace ui {
|
||||||
if(this.on_change)
|
if(this.on_change)
|
||||||
this.on_change();
|
this.on_change();
|
||||||
return RepaintMode.REPAINT_OBJECT_FULL;
|
return RepaintMode.REPAINT_OBJECT_FULL;
|
||||||
|
} else if(this._permission.name === "i_icon_id") {
|
||||||
|
this.on_icon_select(this.value).then(value => {
|
||||||
|
this.value = value;
|
||||||
|
if(this.on_change)
|
||||||
|
this.on_change();
|
||||||
|
}).catch(error => {
|
||||||
|
console.warn(tr("Failed to select icon: %o"), error);
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
this._spawn_number_edit(
|
this._spawn_number_edit(
|
||||||
this._listener_value.region.x,
|
this._listener_value.region.x,
|
||||||
|
|
Loading…
Reference in New Issue