cvs remove.
2002-07-15 Not Zed <NotZed@Ximian.com> * filter-score.[ch]: cvs remove. * filter-element.c: Remove reference to filter-score.h * vfoldertypes.xml: Fix label vfolder rule as below, also add score and size rules from filtertypes.xml. * filtertypes.xml (score): Use (cast-int (user-tag "score")) to get the value directly, rather than (get-score). (label): Use (user-tag "label") to get the value directly, rather than (get-label). The label is now a string too. * filter-label.c (filter_label_get_type): Make filter-label inherit from filter-option. Which makes more sense doesn't it ... surely. (validate): Removed, optionlists are self-validating. (xml_create): Initialise the list of options from our configuration database. If it isn't working, ignore it and set it up anyway. (filter_label_init): Override the xml type. (filter_label_count): (filter_label_label): (filter_label_index): Some helper functions for external interfaces. All of the mail config/etc should use this. * filter-option.c (free_option): (xml_create): (clone): Made the "value" type in glib memory rather than xml memory space. (filter_option_add): Utility function to add a new option to the list. (clone): Use above function to simplify code. (xml_create): Same here. (xml_encode): Allow subclasses to override the type. svn path=/trunk/; revision=17472
This commit is contained in:
@ -1,3 +1,40 @@
|
||||
2002-07-15 Not Zed <NotZed@Ximian.com>
|
||||
|
||||
* filter-score.[ch]: cvs remove.
|
||||
|
||||
* filter-element.c: Remove reference to filter-score.h
|
||||
|
||||
* vfoldertypes.xml: Fix label vfolder rule as below, also add
|
||||
score and size rules from filtertypes.xml.
|
||||
|
||||
* filtertypes.xml (score): Use (cast-int (user-tag "score")) to
|
||||
get the value directly, rather than (get-score).
|
||||
(label): Use (user-tag "label") to get the value directly, rather
|
||||
than (get-label). The label is now a string too.
|
||||
|
||||
* filter-label.c (filter_label_get_type): Make filter-label
|
||||
inherit from filter-option. Which makes more sense doesn't it
|
||||
... surely.
|
||||
(validate): Removed, optionlists are self-validating.
|
||||
(xml_create): Initialise the list of options from our
|
||||
configuration database. If it isn't working, ignore it and set it
|
||||
up anyway.
|
||||
(filter_label_init): Override the xml type.
|
||||
(filter_label_count):
|
||||
(filter_label_label):
|
||||
(filter_label_index): Some helper functions for external
|
||||
interfaces. All of the mail config/etc should use this.
|
||||
|
||||
* filter-option.c (free_option):
|
||||
(xml_create):
|
||||
(clone): Made the "value" type in glib memory rather than xml
|
||||
memory space.
|
||||
(filter_option_add): Utility function to add a new option to the
|
||||
list.
|
||||
(clone): Use above function to simplify code.
|
||||
(xml_create): Same here.
|
||||
(xml_encode): Allow subclasses to override the type.
|
||||
|
||||
2002-07-10 Not Zed <NotZed@Ximian.com>
|
||||
|
||||
** fixes for #10781
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
/*
|
||||
* Authors: Jeffrey Stedfast <fejj@ximian.com>
|
||||
* Michael Zucchi <notzed@ximian.com>
|
||||
*
|
||||
* Copyright 2002 Ximian, Inc. (www.ximian.com)
|
||||
*
|
||||
@ -48,15 +49,12 @@
|
||||
|
||||
#define d(x)
|
||||
|
||||
static gboolean validate (FilterElement *fe);
|
||||
static void xml_create (FilterElement *fe, xmlNodePtr node);
|
||||
static GtkWidget *get_widget (FilterElement *fe);
|
||||
|
||||
static void filter_label_class_init (FilterLabelClass *klass);
|
||||
static void filter_label_init (FilterLabel *label);
|
||||
static void filter_label_finalise (GtkObject *obj);
|
||||
|
||||
|
||||
static FilterElementClass *parent_class;
|
||||
|
||||
enum {
|
||||
@ -65,7 +63,6 @@ enum {
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
GtkType
|
||||
filter_label_get_type (void)
|
||||
{
|
||||
@ -82,7 +79,7 @@ filter_label_get_type (void)
|
||||
(GtkArgGetFunc) NULL
|
||||
};
|
||||
|
||||
type = gtk_type_unique (filter_int_get_type (), &type_info);
|
||||
type = gtk_type_unique (filter_option_get_type (), &type_info);
|
||||
}
|
||||
|
||||
return type;
|
||||
@ -94,24 +91,21 @@ filter_label_class_init (FilterLabelClass *klass)
|
||||
GtkObjectClass *object_class = (GtkObjectClass *) klass;
|
||||
FilterElementClass *filter_element = (FilterElementClass *) klass;
|
||||
|
||||
parent_class = gtk_type_class (filter_int_get_type ());
|
||||
parent_class = gtk_type_class (filter_option_get_type ());
|
||||
|
||||
object_class->finalize = filter_label_finalise;
|
||||
|
||||
/* override methods */
|
||||
filter_element->validate = validate;
|
||||
filter_element->xml_create = xml_create;
|
||||
filter_element->get_widget = get_widget;
|
||||
|
||||
/* signals */
|
||||
|
||||
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
|
||||
}
|
||||
|
||||
static void
|
||||
filter_label_init (FilterLabel *o)
|
||||
{
|
||||
|
||||
((FilterOption *)o)->type = "label";
|
||||
}
|
||||
|
||||
static void
|
||||
@ -133,94 +127,71 @@ filter_label_new (void)
|
||||
return (FilterLabel *) gtk_type_new (filter_label_get_type ());
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate (FilterElement *fe)
|
||||
static struct {
|
||||
char *path;
|
||||
char *title;
|
||||
char *value;
|
||||
} labels[] = {
|
||||
{ "/Mail/Labels/label_0", N_("Important"), "important" },
|
||||
{ "/Mail/Labels/label_1", N_("Work"), "work" },
|
||||
{ "/Mail/Labels/label_2", N_("Personal"), "personal" },
|
||||
{ "/Mail/Labels/label_3", N_("To Do"), "todo" },
|
||||
{ "/Mail/Labels/label_4", N_("Later"), "later" },
|
||||
};
|
||||
|
||||
int filter_label_count(void)
|
||||
{
|
||||
FilterInt *label = (FilterInt *)fe;
|
||||
GtkWidget *dialog;
|
||||
|
||||
if (label->val < 0 || label->val > 4) {
|
||||
dialog = gnome_ok_dialog (_("You must specify a label name"));
|
||||
|
||||
gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
|
||||
return FALSE;
|
||||
return sizeof(labels)/sizeof(labels[0]);
|
||||
}
|
||||
|
||||
const char *filter_label_label(int i)
|
||||
{
|
||||
if (i<0 || i >= sizeof(labels)/sizeof(labels[0]))
|
||||
return NULL;
|
||||
else
|
||||
return labels[i].value;
|
||||
}
|
||||
|
||||
int filter_label_index(const char *label)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<sizeof(labels)/sizeof(labels[0]);i++) {
|
||||
if (strcmp(labels[i].value, label) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
xml_create (FilterElement *fe, xmlNodePtr node)
|
||||
{
|
||||
/* parent implementation */
|
||||
((FilterElementClass *)(parent_class))->xml_create (fe, node);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
label_selected (GtkWidget *item, gpointer user_data)
|
||||
{
|
||||
FilterInt *label = user_data;
|
||||
|
||||
label->val = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (item), "label"));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
get_widget (FilterElement *fe)
|
||||
{
|
||||
FilterInt *label = (FilterInt *) fe;
|
||||
GtkWidget *omenu, *menu, *item;
|
||||
FilterOption *fo = (FilterOption *)fe;
|
||||
Bonobo_ConfigDatabase db;
|
||||
CORBA_Environment ev;
|
||||
char *path, *num;
|
||||
int i;
|
||||
|
||||
omenu = gtk_option_menu_new ();
|
||||
menu = gtk_menu_new ();
|
||||
gtk_widget_show (menu);
|
||||
|
||||
/* sigh. This is a fucking nightmare... */
|
||||
|
||||
|
||||
((FilterElementClass *)(parent_class))->xml_create(fe, node);
|
||||
|
||||
CORBA_exception_init (&ev);
|
||||
db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev);
|
||||
|
||||
if (BONOBO_EX (&ev) || db == CORBA_OBJECT_NIL) {
|
||||
CORBA_exception_free (&ev);
|
||||
|
||||
/* I guess we'll have to return an empty menu? */
|
||||
gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
|
||||
return omenu;
|
||||
}
|
||||
if (BONOBO_EX (&ev) || db == CORBA_OBJECT_NIL)
|
||||
db = CORBA_OBJECT_NIL;
|
||||
|
||||
CORBA_exception_free (&ev);
|
||||
|
||||
path = g_strdup ("/Mail/Labels/label_#");
|
||||
num = path + strlen (path) - 1;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
char *utf8_label, *native_label;
|
||||
|
||||
for (i=0;i<sizeof(labels)/sizeof(labels[0]);i++) {
|
||||
char *title, *btitle;
|
||||
|
||||
sprintf (num, "%d", i);
|
||||
utf8_label = bonobo_config_get_string (db, path, NULL);
|
||||
|
||||
native_label = e_utf8_to_gtk_string (GTK_WIDGET (menu), utf8_label);
|
||||
g_free (utf8_label);
|
||||
|
||||
item = gtk_menu_item_new_with_label (native_label);
|
||||
g_free (native_label);
|
||||
|
||||
gtk_object_set_data (GTK_OBJECT (item), "label", GINT_TO_POINTER (i));
|
||||
gtk_signal_connect (GTK_OBJECT (item), "activate",
|
||||
label_selected, label);
|
||||
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_append (GTK_MENU (menu), item);
|
||||
if (db == CORBA_OBJECT_NIL
|
||||
|| (title = btitle = bonobo_config_get_string(db, labels[i].path, NULL)) == NULL) {
|
||||
btitle = NULL;
|
||||
title = labels[i].title;
|
||||
}
|
||||
|
||||
filter_option_add(fo, labels[i].value, title, NULL);
|
||||
g_free(btitle);
|
||||
}
|
||||
|
||||
g_free (path);
|
||||
|
||||
gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
|
||||
gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), label->val);
|
||||
|
||||
return omenu;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ extern "C" {
|
||||
#pragma }
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include "filter-int.h"
|
||||
#include "filter-option.h"
|
||||
|
||||
#define FILTER_LABEL(obj) GTK_CHECK_CAST (obj, filter_label_get_type (), FilterLabel)
|
||||
#define FILTER_LABEL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, filter_label_get_type (), FilterLabelClass)
|
||||
@ -39,11 +39,11 @@ typedef struct _FilterLabel FilterLabel;
|
||||
typedef struct _FilterLabelClass FilterLabelClass;
|
||||
|
||||
struct _FilterLabel {
|
||||
FilterInt parent;
|
||||
FilterOption parent;
|
||||
};
|
||||
|
||||
struct _FilterLabelClass {
|
||||
FilterIntClass parent_class;
|
||||
FilterOptionClass parent_class;
|
||||
|
||||
/* virtual methods */
|
||||
|
||||
@ -54,6 +54,11 @@ GtkType filter_label_get_type (void);
|
||||
|
||||
FilterLabel *filter_label_new (void);
|
||||
|
||||
/* Sigh, this is a mess, but its cleaner than the original mess */
|
||||
int filter_label_count(void);
|
||||
const char *filter_label_label(int i);
|
||||
int filter_label_index(const char *label);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -111,6 +111,8 @@ filter_option_class_init (FilterOptionClass *class)
|
||||
static void
|
||||
filter_option_init (FilterOption *o)
|
||||
{
|
||||
o->type = "option";
|
||||
|
||||
o->priv = g_malloc0 (sizeof (*o->priv));
|
||||
}
|
||||
|
||||
@ -118,7 +120,7 @@ static void
|
||||
free_option(struct _filter_option *o, void *data)
|
||||
{
|
||||
g_free(o->title);
|
||||
xmlFree (o->value);
|
||||
g_free(o->value);
|
||||
g_free(o->code);
|
||||
g_free(o);
|
||||
}
|
||||
@ -173,6 +175,25 @@ filter_option_set_current (FilterOption *option, const char *name)
|
||||
option->current = find_option (option, name);
|
||||
}
|
||||
|
||||
/* used by implementers to add additional options */
|
||||
void
|
||||
filter_option_add(FilterOption *fo, const char *value, const char *title, const char *code)
|
||||
{
|
||||
struct _filter_option *op;
|
||||
|
||||
g_assert(IS_FILTER_OPTION(fo));
|
||||
g_return_if_fail(find_option(fo, value) == NULL);
|
||||
|
||||
op = g_malloc(sizeof(*op));
|
||||
op->title = g_strdup(title);
|
||||
op->value = g_strdup(value);
|
||||
op->code = g_strdup(code);
|
||||
|
||||
fo->options = g_list_append(fo->options, op);
|
||||
if (fo->current == NULL)
|
||||
fo->current = op;
|
||||
}
|
||||
|
||||
static int
|
||||
option_eq(FilterElement *fe, FilterElement *cm)
|
||||
{
|
||||
@ -189,41 +210,39 @@ xml_create (FilterElement *fe, xmlNodePtr node)
|
||||
FilterOption *fo = (FilterOption *)fe;
|
||||
xmlNodePtr n, work;
|
||||
struct _filter_option *op;
|
||||
|
||||
|
||||
/* parent implementation */
|
||||
((FilterElementClass *)(parent_class))->xml_create(fe, node);
|
||||
|
||||
n = node->childs;
|
||||
while (n) {
|
||||
if (!strcmp (n->name, "option")) {
|
||||
op = g_malloc0 (sizeof (*op));
|
||||
op->value = xmlGetProp (n, "value");
|
||||
char *tmp, *value, *title = NULL, *code = NULL;
|
||||
|
||||
value = xmlGetProp (n, "value");
|
||||
work = n->childs;
|
||||
while (work) {
|
||||
if (!strcmp (work->name, "title")) {
|
||||
if (!op->title) {
|
||||
gchar *str, *decstr;
|
||||
str = xmlNodeGetContent (work);
|
||||
decstr = e_utf8_xml1_decode (str);
|
||||
if (str) xmlFree (str);
|
||||
op->title = decstr;
|
||||
if (!title) {
|
||||
tmp = xmlNodeGetContent(work);
|
||||
title = e_utf8_xml1_decode(tmp);
|
||||
if (tmp)
|
||||
xmlFree(tmp);
|
||||
}
|
||||
} else if (!strcmp (work->name, "code")) {
|
||||
if (!op->code) {
|
||||
gchar *str, *decstr;
|
||||
str = xmlNodeGetContent (work);
|
||||
decstr = e_utf8_xml1_decode (str);
|
||||
if (str) xmlFree (str);
|
||||
op->code = decstr;
|
||||
if (!code) {
|
||||
tmp = xmlNodeGetContent(work);
|
||||
code = e_utf8_xml1_decode(tmp);
|
||||
if (tmp)
|
||||
xmlFree(tmp);
|
||||
}
|
||||
}
|
||||
work = work->next;
|
||||
}
|
||||
d(printf ("creating new option:\n title %s\n value %s\n code %s\n",
|
||||
op->title, op->value, op->code ? op->code : "none"));
|
||||
fo->options = g_list_append (fo->options, op);
|
||||
if (fo->current == NULL)
|
||||
fo->current = op;
|
||||
filter_option_add(fo, value, title, code);
|
||||
xmlFree(value);
|
||||
g_free(title);
|
||||
g_free(code);
|
||||
} else {
|
||||
g_warning ("Unknown xml node within optionlist: %s\n", n->name);
|
||||
}
|
||||
@ -240,10 +259,9 @@ xml_encode (FilterElement *fe)
|
||||
d(printf ("Encoding option as xml\n"));
|
||||
value = xmlNewNode (NULL, "value");
|
||||
xmlSetProp (value, "name", fe->name);
|
||||
xmlSetProp (value, "type", "option");
|
||||
if (fo->current) {
|
||||
xmlSetProp (value, "type", fo->type);
|
||||
if (fo->current)
|
||||
xmlSetProp (value, "value", fo->current->value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@ -324,9 +342,8 @@ build_code (FilterElement *fe, GString *out, struct _FilterPart *ff)
|
||||
|
||||
d(printf ("building option code %p, current = %p\n", fo, fo->current));
|
||||
|
||||
if (fo->current && fo->current->code) {
|
||||
if (fo->current && fo->current->code)
|
||||
filter_part_expand_code (ff, fo->current->code, out);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -334,9 +351,8 @@ format_sexp (FilterElement *fe, GString *out)
|
||||
{
|
||||
FilterOption *fo = (FilterOption *)fe;
|
||||
|
||||
if (fo->current) {
|
||||
if (fo->current)
|
||||
e_sexp_encode_string (out, fo->current->value);
|
||||
}
|
||||
}
|
||||
|
||||
static FilterElement *
|
||||
@ -344,7 +360,7 @@ clone (FilterElement *fe)
|
||||
{
|
||||
FilterOption *fo = (FilterOption *)fe, *new;
|
||||
GList *l;
|
||||
struct _filter_option *fn, *op;
|
||||
struct _filter_option *op;
|
||||
|
||||
d(printf ("cloning option\n"));
|
||||
|
||||
@ -352,19 +368,8 @@ clone (FilterElement *fe)
|
||||
l = fo->options;
|
||||
while (l) {
|
||||
op = l->data;
|
||||
fn = g_malloc (sizeof (*fn));
|
||||
d(printf (" option %s\n", op->title));
|
||||
fn->title = g_strdup (op->title);
|
||||
fn->value = xmlStrdup (op->value);
|
||||
if (op->code)
|
||||
fn->code = g_strdup (op->code);
|
||||
else
|
||||
fn->code = NULL;
|
||||
new->options = g_list_append (new->options, fn);
|
||||
filter_option_add(new, op->value, op->title, op->code);
|
||||
l = g_list_next (l);
|
||||
|
||||
if (new->current == NULL)
|
||||
new->current = fn;
|
||||
}
|
||||
|
||||
d(printf ("cloning option code %p, current = %p\n", new, new->current));
|
||||
|
||||
@ -40,6 +40,8 @@ struct _FilterOption {
|
||||
FilterElement parent;
|
||||
struct _FilterOptionPrivate *priv;
|
||||
|
||||
const char *type; /* static memory, type name written to xml */
|
||||
|
||||
GList *options;
|
||||
struct _filter_option *current;
|
||||
};
|
||||
@ -57,6 +59,7 @@ FilterOption *filter_option_new (void);
|
||||
|
||||
/* methods */
|
||||
void filter_option_set_current(FilterOption *option, const char *name);
|
||||
void filter_option_add(FilterOption *fo, const char *name, const char *title, const char *code);
|
||||
|
||||
#endif /* ! _FILTER_OPTION_H */
|
||||
|
||||
|
||||
@ -389,13 +389,13 @@
|
||||
<option value="is">
|
||||
<title>is</title>
|
||||
<code>
|
||||
(match-all (= (get-label) ${versus}))
|
||||
(match-all (= (user-tag "label") ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="is-not">
|
||||
<title>is not</title>
|
||||
<code>
|
||||
(match-all (not (= (get-label) ${versus})))
|
||||
(match-all (not (= (user-tag "label") ${versus})))
|
||||
</code>
|
||||
</option>
|
||||
</input>
|
||||
@ -408,25 +408,25 @@
|
||||
<option value="is">
|
||||
<title>is</title>
|
||||
<code>
|
||||
(match-all (= (get-score) ${versus}))
|
||||
(match-all (= (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="is-not">
|
||||
<title>is not</title>
|
||||
<code>
|
||||
(match-all (not (= (get-score) ${versus})))
|
||||
(match-all (not (= (cast-int (user-tag "score")) ${versus})))
|
||||
</code>
|
||||
</option>
|
||||
<option value="greater-than">
|
||||
<title>is greater than</title>
|
||||
<code>
|
||||
(match-all (> (get-score) ${versus}))
|
||||
(match-all (> (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="less-than">
|
||||
<title>is less than</title>
|
||||
<code>
|
||||
(match-all (< (get-score) ${versus}))
|
||||
(match-all (< (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
</input>
|
||||
|
||||
@ -260,19 +260,69 @@
|
||||
<option value="is">
|
||||
<title>is</title>
|
||||
<code>
|
||||
(match-all (= (get-label) ${versus}))
|
||||
(match-all (= (user-tag "label") ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="is-not">
|
||||
<title>is not</title>
|
||||
<code>
|
||||
(match-all (not (= (get-label) ${versus})))
|
||||
(match-all (not (= (user-tag "label") ${versus})))
|
||||
</code>
|
||||
</option>
|
||||
</input>
|
||||
<input type="label" name="versus"/>
|
||||
</part>
|
||||
|
||||
<part name="score">
|
||||
<title>Score</title>
|
||||
<input type="optionlist" name="score-type">
|
||||
<option value="is">
|
||||
<title>is</title>
|
||||
<code>
|
||||
(match-all (= (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="is-not">
|
||||
<title>is not</title>
|
||||
<code>
|
||||
(match-all (not (= (cast-int (user-tag "score")) ${versus})))
|
||||
</code>
|
||||
</option>
|
||||
<option value="greater-than">
|
||||
<title>is greater than</title>
|
||||
<code>
|
||||
(match-all (> (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="less-than">
|
||||
<title>is less than</title>
|
||||
<code>
|
||||
(match-all (< (cast-int (user-tag "score")) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
</input>
|
||||
<input type="score" name="versus"/>
|
||||
</part>
|
||||
|
||||
<part name="size">
|
||||
<title>Size (kB)</title>
|
||||
<input type="optionlist" name="size-type">
|
||||
<option value="greater-than">
|
||||
<title>is greater than</title>
|
||||
<code>
|
||||
(match-all (> (get-size) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
<option value="less-than">
|
||||
<title>is less than</title>
|
||||
<code>
|
||||
(match-all (< (get-size) ${versus}))
|
||||
</code>
|
||||
</option>
|
||||
</input>
|
||||
<input type="integer" name="versus"/>
|
||||
</part>
|
||||
|
||||
<part name="status">
|
||||
<title>Status</title>
|
||||
<input type="optionlist" name="match-type">
|
||||
|
||||
Reference in New Issue
Block a user