mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0360: Cannot handle mouse-clicks in the tabpanel
Problem: Cannot handle mouse-clicks in the tabpanel
Solution: Add support using the %[FuncName] atom for the tabpanel
(Yasuhiro Matsumoto)
Extend the statusline/tabline click region mechanism to work with
'tabpanel'. The callback receives a dict with "area" set to "tabpanel"
and a "tabnr" key indicating which tab page label was clicked.
closes: #19960
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
25e9fc44a8
commit
1c299f2631
@@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 9.2. Last change: 2026 Apr 15
|
||||
*options.txt* For Vim version 9.2. Last change: 2026 Apr 16
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -8689,7 +8689,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
*stl-%[FuncName]*
|
||||
%[ defines clickable regions in the statusline. When the user clicks
|
||||
on a region with the mouse, the specified function is called. The
|
||||
same syntax can also be used in 'tabline'.
|
||||
same syntax can also be used in 'tabline' and 'tabpanel'.
|
||||
|
||||
%[FuncName] Start of a clickable region. "FuncName" is the name
|
||||
of a Vim function to call when the region is clicked.
|
||||
@@ -8708,16 +8708,16 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
"mods" Modifier keys: combination of "s" (shift), "c" (ctrl),
|
||||
"a" (alt). Empty string if no modifiers.
|
||||
"winid" |window-ID| of the window whose statusline was clicked,
|
||||
or 0 when the click was in 'tabline'.
|
||||
"area" "statusline" or "tabline". Indicates which option the
|
||||
clicked region belongs to. Useful when a single
|
||||
callback is shared between 'statusline' and 'tabline'.
|
||||
or 0 when the click was in 'tabline' or 'tabpanel'.
|
||||
"area" "statusline", "tabline", or "tabpanel". Indicates
|
||||
which option the clicked region belongs to.
|
||||
"tabnr" (tabpanel only) Tab page number of the clicked label.
|
||||
|
||||
If the function returns non-zero, the statusline is redrawn.
|
||||
Dragging the statusline to resize the window still works even when
|
||||
click handlers are defined. When used in 'tabline', clicks in
|
||||
%[FuncName] regions are dispatched to the callback instead of the
|
||||
default tab page selection behavior.
|
||||
click handlers are defined. When used in 'tabline' or 'tabpanel',
|
||||
clicks in %[FuncName] regions are dispatched to the callback
|
||||
instead of the default tab-selection behavior.
|
||||
|
||||
Example: >
|
||||
func! ClickFile(info)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*version9.txt* For Vim version 9.2. Last change: 2026 Apr 15
|
||||
*version9.txt* For Vim version 9.2. Last change: 2026 Apr 16
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -52613,8 +52613,8 @@ Other ~
|
||||
pairs individually (e.g. 'listchars', 'fillchars', 'diffopt').
|
||||
- |system()| and |systemlist()| functions accept a list as first argument,
|
||||
bypassing the shell completely.
|
||||
- Allow mouse clickable regions in the |status-line| using the
|
||||
|stl-%[FuncName]| atom.
|
||||
- Allow mouse clickable regions in the 'statusline', 'tabline' and the
|
||||
'tabpanel' using the |stl-%[FuncName]| atom.
|
||||
- Enable reflow support in the |:terminal|.
|
||||
|
||||
Platform specific ~
|
||||
|
||||
@@ -108,6 +108,10 @@ EXTERN short *TabPageIdxs INIT(= NULL);
|
||||
EXTERN stl_click_region_T *tabline_stl_click INIT(= NULL);
|
||||
EXTERN int tabline_stl_click_count INIT(= 0);
|
||||
|
||||
// Click regions for 'tabpanel' (%[FuncName]).
|
||||
EXTERN stl_click_region_T *tabpanel_stl_click INIT(= NULL);
|
||||
EXTERN int tabpanel_stl_click_count INIT(= 0);
|
||||
|
||||
#ifdef FEAT_PROP_POPUP
|
||||
// Array with size Rows x Columns containing zindex of popups.
|
||||
EXTERN short *popup_mask INIT(= NULL);
|
||||
|
||||
+43
-14
@@ -20,9 +20,11 @@
|
||||
static long mouse_hor_step = 6;
|
||||
static long mouse_vert_step = 3;
|
||||
static win_T *dragwin = NULL; // window being dragged
|
||||
static int stl_click_handler(win_T *wp, int mcol, int which_button, int mods);
|
||||
static int stl_click_handler(win_T *wp, int mrow, int mcol, int which_button,
|
||||
int mods);
|
||||
static int stl_click_handler_regions(stl_click_region_T *regions,
|
||||
int region_count, int winid, int mcol,
|
||||
int region_count, int winid,
|
||||
char_u *area_name, int mrow, int mcol,
|
||||
int which_button, int mods);
|
||||
|
||||
void
|
||||
@@ -492,6 +494,17 @@ do_mouse(
|
||||
if (mouse_col < firstwin->w_wincol
|
||||
|| mouse_col >= firstwin->w_wincol + topframe->fr_width)
|
||||
{
|
||||
// Dispatch 'tabpanel' %[FuncName] click regions before falling through
|
||||
// to tab-page selection. On drag events fall through to the normal
|
||||
// tab-drag handling.
|
||||
if (is_click && !is_drag
|
||||
&& stl_click_handler_regions(tabpanel_stl_click,
|
||||
tabpanel_stl_click_count,
|
||||
0, (char_u *)"tabpanel",
|
||||
mouse_row, mouse_col,
|
||||
which_button, mod_mask))
|
||||
return FALSE;
|
||||
|
||||
tp_label.is_panel = true;
|
||||
tp_label.just_in = true;
|
||||
tp_label.nr = get_tabpagenr_on_tabpanel();
|
||||
@@ -511,8 +524,9 @@ do_mouse(
|
||||
if (is_click && !is_drag
|
||||
&& stl_click_handler_regions(tabline_stl_click,
|
||||
tabline_stl_click_count,
|
||||
0, mouse_col, which_button,
|
||||
mod_mask))
|
||||
0, (char_u *)"tabline",
|
||||
mouse_row, mouse_col,
|
||||
which_button, mod_mask))
|
||||
return FALSE;
|
||||
|
||||
tp_label.just_in = true;
|
||||
@@ -778,7 +792,7 @@ do_mouse(
|
||||
// Check for statusline click handler early, before visual mode or
|
||||
// other button-specific handling can interfere.
|
||||
if (in_status_line && is_click && !is_drag
|
||||
&& stl_click_handler(dragwin, mouse_col,
|
||||
&& stl_click_handler(dragwin, mouse_row, mouse_col,
|
||||
which_button, mod_mask))
|
||||
{
|
||||
#ifdef FEAT_MOUSESHAPE
|
||||
@@ -1663,6 +1677,8 @@ stl_click_handler_regions(
|
||||
stl_click_region_T *regions,
|
||||
int region_count,
|
||||
int winid,
|
||||
char_u *area_name,
|
||||
int mrow,
|
||||
int mcol,
|
||||
int which_button,
|
||||
int mods)
|
||||
@@ -1682,10 +1698,12 @@ stl_click_handler_regions(
|
||||
if (regions == NULL || region_count == 0)
|
||||
return FALSE;
|
||||
|
||||
// Find the click region at the given column.
|
||||
// Find the click region at the given row and column.
|
||||
for (n = 0; n < region_count; n++)
|
||||
{
|
||||
if (col >= regions[n].col_start && col < regions[n].col_end)
|
||||
if (regions[n].row == mrow
|
||||
&& col >= regions[n].col_start
|
||||
&& col < regions[n].col_end)
|
||||
break;
|
||||
}
|
||||
if (n >= region_count || regions[n].funcname == NULL)
|
||||
@@ -1728,10 +1746,13 @@ stl_click_handler_regions(
|
||||
dict_add_number(info, "winid", winid);
|
||||
|
||||
// "area": which option the clicked region belongs to. Lets a shared
|
||||
// dispatcher distinguish 'statusline' from 'tabline' (and future areas)
|
||||
// without having to overload winid == 0.
|
||||
dict_add_string(info, "area",
|
||||
winid == 0 ? (char_u *)"tabline" : (char_u *)"statusline");
|
||||
// dispatcher distinguish 'statusline', 'tabline' and 'tabpanel' without
|
||||
// having to overload winid == 0.
|
||||
dict_add_string(info, "area", area_name);
|
||||
|
||||
// Expose tab page number for 'tabpanel' regions.
|
||||
if (regions[n].tabnr > 0)
|
||||
dict_add_number(info, "tabnr", regions[n].tabnr);
|
||||
|
||||
// Call the function with the info dict as argument.
|
||||
argvars[0].v_type = VAR_DICT;
|
||||
@@ -1755,9 +1776,14 @@ stl_click_handler_regions(
|
||||
{
|
||||
// Make sure the tabline gets redrawn too when the callback asks for
|
||||
// a redraw (redraw_statuslines() only redraws the tabline when
|
||||
// redraw_tabline is set).
|
||||
// redraw_tabline is set). For tabpanel the whole screen needs to be
|
||||
// refreshed.
|
||||
if (winid == 0)
|
||||
redraw_tabline = TRUE;
|
||||
# ifdef FEAT_TABPANEL
|
||||
if (STRCMP(area_name, "tabpanel") == 0)
|
||||
redraw_all_later(UPD_NOT_VALID);
|
||||
# endif
|
||||
redraw_statuslines();
|
||||
}
|
||||
|
||||
@@ -1766,6 +1792,8 @@ stl_click_handler_regions(
|
||||
(void)regions;
|
||||
(void)region_count;
|
||||
(void)winid;
|
||||
(void)area_name;
|
||||
(void)mrow;
|
||||
(void)mcol;
|
||||
(void)which_button;
|
||||
(void)mods;
|
||||
@@ -1778,12 +1806,13 @@ stl_click_handler_regions(
|
||||
* Returns TRUE if the function was called and handled the click.
|
||||
*/
|
||||
static int
|
||||
stl_click_handler(win_T *wp, int mcol, int which_button, int mods)
|
||||
stl_click_handler(win_T *wp, int mrow, int mcol, int which_button, int mods)
|
||||
{
|
||||
if (wp == NULL)
|
||||
return FALSE;
|
||||
return stl_click_handler_regions(wp->w_stl_click, wp->w_stl_click_count,
|
||||
wp->w_id, mcol, which_button, mods);
|
||||
wp->w_id, (char_u *)"statusline",
|
||||
mrow, mcol, which_button, mods);
|
||||
}
|
||||
|
||||
// dragwin is declared near the top of the file
|
||||
|
||||
@@ -1492,8 +1492,13 @@ win_redr_custom(
|
||||
stl_click_region_T **out_regions;
|
||||
int *out_count;
|
||||
int base_col;
|
||||
int base_row;
|
||||
int click_count = 0;
|
||||
|
||||
// clicktab reflects the last iteration of the draw loop above, so
|
||||
// the regions belong to the last drawn row.
|
||||
base_row = row + stlh_cnt - 1;
|
||||
|
||||
if (wp != NULL)
|
||||
{
|
||||
out_regions = &wp->w_stl_click;
|
||||
@@ -1547,11 +1552,13 @@ win_redr_custom(
|
||||
// Close previous region if there was one.
|
||||
if (cur_funcname != NULL)
|
||||
{
|
||||
regions[rcount].row = base_row;
|
||||
regions[rcount].col_start = region_start;
|
||||
regions[rcount].col_end = base_col + len;
|
||||
regions[rcount].funcname =
|
||||
vim_strsave(cur_funcname);
|
||||
regions[rcount].minwid = cur_minwid;
|
||||
regions[rcount].tabnr = 0;
|
||||
rcount++;
|
||||
}
|
||||
|
||||
@@ -1563,11 +1570,13 @@ win_redr_custom(
|
||||
// Close final region if it extends to the end.
|
||||
if (cur_funcname != NULL)
|
||||
{
|
||||
regions[rcount].row = base_row;
|
||||
regions[rcount].col_start = region_start;
|
||||
regions[rcount].col_end = base_col + maxwidth;
|
||||
regions[rcount].funcname =
|
||||
vim_strsave(cur_funcname);
|
||||
regions[rcount].minwid = cur_minwid;
|
||||
regions[rcount].tabnr = 0;
|
||||
rcount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1451,10 +1451,12 @@ typedef struct {
|
||||
* Per-window resolved click regions (screen column based).
|
||||
*/
|
||||
typedef struct {
|
||||
int row; // screen row where region lives
|
||||
int col_start; // screen column where region starts
|
||||
int col_end; // screen column where region ends
|
||||
char_u *funcname; // function name (allocated copy)
|
||||
int minwid; // minwid value
|
||||
int tabnr; // tab page number (tabpanel only, 0 otherwise)
|
||||
} stl_click_region_T;
|
||||
|
||||
|
||||
|
||||
+131
-1
@@ -17,6 +17,9 @@
|
||||
|
||||
static void do_by_tplmode(int tplmode, int col_start, int col_end,
|
||||
int *pcurtab_row, int *ptabpagenr);
|
||||
static void tabpanel_free_click_regions(void);
|
||||
static void tabpanel_append_click_regions(stl_clickrec_T *clicktab,
|
||||
char_u *buf, int row, int col_start, int col_end, int tabnr);
|
||||
|
||||
// set pcurtab_row. don't redraw tabpanel.
|
||||
#define TPLMODE_GET_CURTAB_ROW 0
|
||||
@@ -135,6 +138,108 @@ tabpanel_leftcol(void)
|
||||
return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
|
||||
}
|
||||
|
||||
/*
|
||||
* Free previously resolved 'tabpanel' click regions.
|
||||
*/
|
||||
static void
|
||||
tabpanel_free_click_regions(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (tabpanel_stl_click != NULL)
|
||||
{
|
||||
for (n = 0; n < tabpanel_stl_click_count; n++)
|
||||
vim_free(tabpanel_stl_click[n].funcname);
|
||||
VIM_CLEAR(tabpanel_stl_click);
|
||||
}
|
||||
tabpanel_stl_click_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert click records produced by build_stl_str_hl() for one line of
|
||||
* 'tabpanel' into screen-column based regions and append them to the global
|
||||
* tabpanel_stl_click array. The caller keeps ownership of the funcname
|
||||
* strings inside "clicktab" — this function makes its own copies.
|
||||
*/
|
||||
static void
|
||||
tabpanel_append_click_regions(
|
||||
stl_clickrec_T *clicktab,
|
||||
char_u *buf,
|
||||
int row,
|
||||
int col_start,
|
||||
int col_end,
|
||||
int tabnr)
|
||||
{
|
||||
int count = 0;
|
||||
int n;
|
||||
int base_col;
|
||||
int acc_width = 0;
|
||||
int max_w = col_end - col_start;
|
||||
char_u *p;
|
||||
char_u *cur_funcname = NULL;
|
||||
int cur_minwid = 0;
|
||||
int region_start_col;
|
||||
stl_click_region_T *new_arr;
|
||||
int limit;
|
||||
|
||||
if (clicktab == NULL)
|
||||
return;
|
||||
|
||||
for (n = 0; clicktab[n].start != NULL; n++)
|
||||
count++;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
base_col = (tpl_align == ALIGN_RIGHT ? topframe->fr_width : 0) + col_start;
|
||||
region_start_col = base_col;
|
||||
|
||||
// Grow the global array to make room for up to "count" more regions
|
||||
// (one close for each record plus a possible trailing region).
|
||||
new_arr = vim_realloc(tabpanel_stl_click,
|
||||
sizeof(stl_click_region_T) * (tabpanel_stl_click_count + count + 1));
|
||||
if (new_arr == NULL)
|
||||
return;
|
||||
tabpanel_stl_click = new_arr;
|
||||
|
||||
p = buf;
|
||||
for (n = 0; clicktab[n].start != NULL; n++)
|
||||
{
|
||||
acc_width += vim_strnsize(p, (int)(clicktab[n].start - p));
|
||||
p = clicktab[n].start;
|
||||
limit = acc_width < max_w ? acc_width : max_w;
|
||||
|
||||
if (cur_funcname != NULL)
|
||||
{
|
||||
stl_click_region_T *r =
|
||||
&tabpanel_stl_click[tabpanel_stl_click_count];
|
||||
r->row = row;
|
||||
r->col_start = region_start_col;
|
||||
r->col_end = base_col + limit;
|
||||
r->funcname = vim_strsave(cur_funcname);
|
||||
r->minwid = cur_minwid;
|
||||
r->tabnr = tabnr;
|
||||
tabpanel_stl_click_count++;
|
||||
}
|
||||
|
||||
cur_funcname = clicktab[n].funcname;
|
||||
cur_minwid = clicktab[n].minwid;
|
||||
region_start_col = base_col + limit;
|
||||
}
|
||||
|
||||
// Close the final region if it extends to the end.
|
||||
if (cur_funcname != NULL)
|
||||
{
|
||||
stl_click_region_T *r = &tabpanel_stl_click[tabpanel_stl_click_count];
|
||||
r->row = row;
|
||||
r->col_start = region_start_col;
|
||||
r->col_end = base_col + max_w;
|
||||
r->funcname = vim_strsave(cur_funcname);
|
||||
r->minwid = cur_minwid;
|
||||
r->tabnr = tabnr;
|
||||
tabpanel_stl_click_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* draw the tabpanel.
|
||||
*/
|
||||
@@ -150,7 +255,13 @@ draw_tabpanel(void)
|
||||
int is_right = tpl_align == ALIGN_RIGHT;
|
||||
|
||||
if (maxwidth == 0)
|
||||
{
|
||||
tabpanel_free_click_regions();
|
||||
return;
|
||||
}
|
||||
|
||||
// Discard old click regions — they'll be rebuilt during redraw below.
|
||||
tabpanel_free_click_regions();
|
||||
|
||||
// Reset got_int to avoid build_stl_str_hl() isn't evaluated.
|
||||
got_int = FALSE;
|
||||
@@ -495,6 +606,7 @@ do_by_tplmode(
|
||||
char_u buf[IOSIZE];
|
||||
stl_hlrec_T *hltab;
|
||||
stl_hlrec_T *tabtab;
|
||||
stl_clickrec_T *clicktab = NULL;
|
||||
|
||||
if (args.maxrow <= row - args.offsetrow)
|
||||
break;
|
||||
@@ -508,13 +620,31 @@ do_by_tplmode(
|
||||
(args.cwp, buf, sizeof(buf),
|
||||
&usefmt, opt_name, opt_scope, TPL_FILLCHAR,
|
||||
args.col_end - args.col_start, &hltab, &tabtab,
|
||||
NULL);
|
||||
tplmode == TPLMODE_REDRAW ? &clicktab : NULL);
|
||||
|
||||
args.prow = &row;
|
||||
args.pcol = &col;
|
||||
|
||||
draw_tabpanel_with_highlight(tplmode, buf, hltab, &args);
|
||||
|
||||
// Record any %[FuncName] click regions for this line once
|
||||
// the text has been drawn. Only visible rows participate.
|
||||
if (tplmode == TPLMODE_REDRAW && clicktab != NULL)
|
||||
{
|
||||
int screen_row = row - args.offsetrow;
|
||||
int m;
|
||||
|
||||
if (screen_row >= 0 && screen_row < args.maxrow)
|
||||
tabpanel_append_click_regions(clicktab, buf,
|
||||
screen_row, args.col_start, args.col_end,
|
||||
(int)v.vval.v_number);
|
||||
// We took ownership of the click records — free the
|
||||
// function names (matches the non-NULL clicktab path in
|
||||
// build_stl_str_hl()).
|
||||
for (m = 0; clicktab[m].start != NULL; m++)
|
||||
vim_free(clicktab[m].funcname);
|
||||
}
|
||||
|
||||
// Move to next line for %@
|
||||
if (*usefmt != NUL)
|
||||
{
|
||||
|
||||
@@ -249,6 +249,76 @@ function Test_tabpanel_mouse()
|
||||
let &showtabline = save_showtabline
|
||||
endfunc
|
||||
|
||||
func g:TplClickTestFunc(info)
|
||||
let g:tpl_click_info = a:info
|
||||
return 0
|
||||
endfunc
|
||||
|
||||
function Test_tabpanel_click_handler()
|
||||
let save_mouse = &mouse
|
||||
let save_stal = &showtabline
|
||||
let save_stpl = &showtabpanel
|
||||
let save_tpl = &tabpanel
|
||||
let save_tplo = &tabpanelopt
|
||||
set mouse=a
|
||||
set showtabline=0
|
||||
set showtabpanel=2
|
||||
set tabpanelopt=columns:16
|
||||
tabnew
|
||||
tabnew
|
||||
|
||||
" Place two adjacent %[FuncName] regions on every tab label.
|
||||
set tabpanel=%1[TplClickTestFunc][A]%[]%2[TplClickTestFunc][B]%[]
|
||||
redraw!
|
||||
|
||||
" Click on [A] region in the first tab label (row 1).
|
||||
call test_setmouse(1, 2)
|
||||
call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt')
|
||||
call assert_true(exists('g:tpl_click_info'))
|
||||
call assert_equal('l', g:tpl_click_info.button)
|
||||
call assert_equal(1, g:tpl_click_info.nclicks)
|
||||
call assert_equal(1, g:tpl_click_info.minwid)
|
||||
call assert_equal(0, g:tpl_click_info.winid)
|
||||
call assert_equal('tabpanel', g:tpl_click_info.area)
|
||||
call assert_equal(1, g:tpl_click_info.tabnr)
|
||||
unlet! g:tpl_click_info
|
||||
|
||||
" Click on [B] region in the second tab label (row 2).
|
||||
call test_setmouse(2, 5)
|
||||
call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt')
|
||||
call assert_true(exists('g:tpl_click_info'))
|
||||
call assert_equal(2, g:tpl_click_info.minwid)
|
||||
call assert_equal(2, g:tpl_click_info.tabnr)
|
||||
unlet! g:tpl_click_info
|
||||
|
||||
" Middle click on [A] in tab 3.
|
||||
call test_setmouse(3, 2)
|
||||
call feedkeys("\<MiddleMouse>\<MiddleRelease>", 'xt')
|
||||
call assert_true(exists('g:tpl_click_info'))
|
||||
call assert_equal('m', g:tpl_click_info.button)
|
||||
call assert_equal(1, g:tpl_click_info.minwid)
|
||||
call assert_equal(3, g:tpl_click_info.tabnr)
|
||||
unlet! g:tpl_click_info
|
||||
|
||||
" A click outside any region (but still in the panel) must not fire the
|
||||
" callback, and should fall through to the normal tab selection.
|
||||
set tabpanel=xxx%1[TplClickTestFunc][Y]%[]
|
||||
redraw!
|
||||
tabfirst
|
||||
call test_setmouse(2, 1)
|
||||
call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt')
|
||||
call assert_false(exists('g:tpl_click_info'))
|
||||
call assert_equal(2, tabpagenr())
|
||||
|
||||
tabonly!
|
||||
call s:reset()
|
||||
let &tabpanel = save_tpl
|
||||
let &tabpanelopt = save_tplo
|
||||
let &showtabpanel = save_stpl
|
||||
let &showtabline = save_stal
|
||||
let &mouse = save_mouse
|
||||
endfunc
|
||||
|
||||
function Test_tabpanel_drawing()
|
||||
CheckScreendump
|
||||
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
360,
|
||||
/**/
|
||||
359,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user