Subsite-Administration in Applications-Tab unter /ccm/admin integriert
git-svn-id: https://svn.libreccm.org/ccm/trunk@2300 8810af33-2d31-482b-a856-94f89814c4dfmaster
parent
2a89454821
commit
183d95a836
|
|
@ -152,10 +152,12 @@ public class PublicPersonalProfileNavItemsTable
|
|||
numberOfKeys = keys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return table.getColumnModel().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
if (!navItems.isBeforeFirst()) {
|
||||
lastOrder = navItems.getNavItem().getOrder();
|
||||
|
|
@ -163,6 +165,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
return navItems.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
|
|
@ -200,6 +203,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(int columnIndex) {
|
||||
return navItems.getNavItem().getId();
|
||||
}
|
||||
|
|
@ -209,6 +213,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
extends LockableImpl
|
||||
implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
|
|
@ -226,6 +231,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
extends LockableImpl
|
||||
implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
|
|
@ -235,9 +241,8 @@ public class PublicPersonalProfileNavItemsTable
|
|||
final int column) {
|
||||
|
||||
final ControlLink link = new ControlLink(value.toString());
|
||||
link.setConfirmation((String) PublicPersonalProfileGlobalizationUtil.
|
||||
globalize("publicpersonalprofile.ui.navitems.delete.confirm").
|
||||
localize());
|
||||
link.setConfirmation(PublicPersonalProfileGlobalizationUtil.
|
||||
globalize("publicpersonalprofile.ui.navitems.delete.confirm"));
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
|
@ -246,6 +251,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
extends LockableImpl
|
||||
implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
|
|
@ -276,6 +282,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
private final PublicPersonalProfileNavItemCollection navItems =
|
||||
new PublicPersonalProfileNavItemCollection();
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
|
|
@ -299,6 +306,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cellSelected(final TableActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
|
|
@ -323,6 +331,7 @@ public class PublicPersonalProfileNavItemsTable
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void headSelected(final TableActionEvent event) {
|
||||
//Nothing to do
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.arsdigita.london.terms.ui.admin;
|
||||
|
||||
import java.net.URL;
|
||||
|
|
@ -46,20 +45,17 @@ import com.arsdigita.util.UncheckedWrapperException;
|
|||
public class DomainForm extends Form {
|
||||
|
||||
private DomainObjectParameter m_domain;
|
||||
|
||||
private TextField m_key;
|
||||
private TextField m_url;
|
||||
private TextField m_title;
|
||||
private TextArea m_desc;
|
||||
private TextField m_version;
|
||||
private Date m_released;
|
||||
|
||||
private SaveCancelSection m_buttons;
|
||||
|
||||
public DomainForm(String name,
|
||||
DomainObjectParameter domain) {
|
||||
super(name, new SimpleContainer(Terms.XML_PREFIX +
|
||||
":domainForm",
|
||||
super(name, new SimpleContainer(Terms.XML_PREFIX + ":domainForm",
|
||||
Terms.XML_NS));
|
||||
setRedirecting(true);
|
||||
|
||||
|
|
@ -86,13 +82,14 @@ public class DomainForm extends Form {
|
|||
|
||||
try {
|
||||
m_key.addPrintListener(new PrintListener() {
|
||||
public void prepare(PrintEvent e) {
|
||||
TextField f = (TextField)e.getTarget();
|
||||
if (e.getPageState().getValue(m_domain) != null) {
|
||||
f.setReadOnly();
|
||||
}
|
||||
public void prepare(PrintEvent e) {
|
||||
TextField f = (TextField) e.getTarget();
|
||||
if (e.getPageState().getValue(m_domain) != null) {
|
||||
f.setReadOnly();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
} catch (TooManyListenersException ex) {
|
||||
throw new UncheckedWrapperException("cannot happen", ex);
|
||||
}
|
||||
|
|
@ -137,10 +134,11 @@ public class DomainForm extends Form {
|
|||
}
|
||||
|
||||
private class DomainInitListener implements FormInitListener {
|
||||
|
||||
public void init(FormSectionEvent ev)
|
||||
throws FormProcessException {
|
||||
throws FormProcessException {
|
||||
PageState state = ev.getPageState();
|
||||
Domain domain = (Domain)state.getValue(m_domain);
|
||||
Domain domain = (Domain) state.getValue(m_domain);
|
||||
|
||||
//m_key.setVisible(state, domain == null);
|
||||
|
||||
|
|
@ -158,13 +156,15 @@ public class DomainForm extends Form {
|
|||
m_desc.setValue(state, domain.getDescription());
|
||||
m_version.setValue(state, domain.getVersion());
|
||||
m_released.setValue(state, domain.getReleased());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DomainSubmissionListener implements FormSubmissionListener {
|
||||
|
||||
public void submitted(FormSectionEvent ev)
|
||||
throws FormProcessException {
|
||||
throws FormProcessException {
|
||||
PageState state = ev.getPageState();
|
||||
|
||||
if (m_buttons.getCancelButton().isSelected(state)) {
|
||||
|
|
@ -172,33 +172,35 @@ public class DomainForm extends Form {
|
|||
throw new FormProcessException("cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DomainProcessListener implements FormProcessListener {
|
||||
|
||||
public void process(FormSectionEvent ev)
|
||||
throws FormProcessException {
|
||||
throws FormProcessException {
|
||||
PageState state = ev.getPageState();
|
||||
Domain domain = (Domain)state.getValue(m_domain);
|
||||
Domain domain = (Domain) state.getValue(m_domain);
|
||||
|
||||
if (domain == null) {
|
||||
domain = Domain.create((String)m_key.getValue(state),
|
||||
(URL)m_url.getValue(state),
|
||||
(String)m_title.getValue(state),
|
||||
(String)m_desc.getValue(state),
|
||||
(String)m_version.getValue(state),
|
||||
(java.util.Date)m_released.getValue(state));
|
||||
domain = Domain.create((String) m_key.getValue(state),
|
||||
(URL) m_url.getValue(state),
|
||||
(String) m_title.getValue(state),
|
||||
(String) m_desc.getValue(state),
|
||||
(String) m_version.getValue(state),
|
||||
(java.util.Date) m_released.getValue(state));
|
||||
state.setValue(m_domain, domain);
|
||||
} else {
|
||||
//domain.setKey((String)m_key.getValue(state));
|
||||
domain.setURL((URL)m_url.getValue(state));
|
||||
domain.setTitle((String)m_title.getValue(state));
|
||||
domain.setDescription((String)m_desc.getValue(state));
|
||||
domain.setVersion((String)m_version.getValue(state));
|
||||
domain.setReleased((java.util.Date)m_released.getValue(state));
|
||||
domain.setURL((URL) m_url.getValue(state));
|
||||
domain.setTitle((String) m_title.getValue(state));
|
||||
domain.setDescription((String) m_desc.getValue(state));
|
||||
domain.setVersion((String) m_version.getValue(state));
|
||||
domain.setReleased((java.util.Date) m_released.getValue(state));
|
||||
}
|
||||
|
||||
fireCompletionEvent(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package com.arsdigita.subsite;
|
|||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.subsite.ui.AppManagerPanel;
|
||||
import com.arsdigita.ui.admin.GlobalizationUtil;
|
||||
import com.arsdigita.ui.admin.applications.AbstractSingletonApplicationManager;
|
||||
import com.arsdigita.ui.admin.applications.ApplicationInstanceAwareContainer;
|
||||
|
|
@ -32,19 +33,24 @@ import com.arsdigita.ui.admin.applications.ApplicationInstanceAwareContainer;
|
|||
*/
|
||||
public class SubsiteAppManager extends AbstractSingletonApplicationManager<Subsite>{
|
||||
|
||||
@Override
|
||||
public Class<Subsite> getApplication() {
|
||||
return Subsite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationInstanceAwareContainer getApplicationAdminForm() {
|
||||
final ApplicationInstanceAwareContainer container = new ApplicationInstanceAwareContainer();
|
||||
|
||||
final BoxPanel panel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
final Label warnLabel = new Label(GlobalizationUtil.globalize("ui.admin.applications.form_not_compatible_now"));
|
||||
warnLabel.setClassAttr("warning");
|
||||
panel.add(warnLabel);
|
||||
panel.add(new Link("Subsite Admin", "/admin/subsite"));
|
||||
// final BoxPanel panel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
// final Label warnLabel = new Label(GlobalizationUtil.globalize("ui.admin.applications.form_not_compatible_now"));
|
||||
// warnLabel.setClassAttr("warning");
|
||||
// panel.add(warnLabel);
|
||||
// panel.add(new Link("Subsite Admin", "/admin/subsite"));
|
||||
//
|
||||
// container.add(panel);
|
||||
|
||||
final AppManagerPanel panel = new AppManagerPanel();
|
||||
container.add(panel);
|
||||
|
||||
return container;
|
||||
|
|
|
|||
|
|
@ -19,12 +19,10 @@
|
|||
package com.arsdigita.subsite.ui;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import com.arsdigita.subsite.Subsite;
|
||||
import com.arsdigita.ui.admin.GlobalizationUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -33,28 +31,29 @@ import com.arsdigita.ui.admin.GlobalizationUtil;
|
|||
*/
|
||||
public class AppManagerPanel extends SimpleContainer {
|
||||
|
||||
// private final SiteSelectionModel selectionModel = new SiteSelectionModel(new BigDecimalParameter("site"));
|
||||
private final SiteSelectionModel selectionModel = new SiteSelectionModel(new BigDecimalParameter("site"));
|
||||
|
||||
public AppManagerPanel() {
|
||||
super(Subsite.SUBSITE_XML_PREFIX + "controlCenter",
|
||||
Subsite.SUBSITE_XML_NS);
|
||||
// super(Subsite.SUBSITE_XML_PREFIX + "controlCenter",
|
||||
// Subsite.SUBSITE_XML_NS);
|
||||
|
||||
final BoxPanel panel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
final Label warnLabel = new Label(GlobalizationUtil.globalize("ui.admin.applications.form_not_compatible_now"));
|
||||
warnLabel.setClassAttr("warning");
|
||||
add(warnLabel);
|
||||
panel.add(warnLabel);
|
||||
panel.add(new Link("", "/ccm/admin/subsite"));
|
||||
// add(new SiteListing(selectionModel));
|
||||
// add(new SiteForm("site", selectionModel));
|
||||
// final BoxPanel panel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
// final Label warnLabel = new Label(GlobalizationUtil.globalize("ui.admin.applications.form_not_compatible_now"));
|
||||
// warnLabel.setClassAttr("warning");
|
||||
// add(warnLabel);
|
||||
// panel.add(warnLabel);
|
||||
// panel.add(new Link("", "/ccm/admin/subsite"));
|
||||
//add(new SiteListing(selectionModel));
|
||||
add(new SiteTable(selectionModel));
|
||||
add(new SiteForm("site", selectionModel));
|
||||
|
||||
add(panel);
|
||||
// add(panel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
super.register(page);
|
||||
// page.addGlobalStateParam(selectionModel.getStateParameter());
|
||||
page.addGlobalStateParam(selectionModel.getStateParameter());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jens Pelzetter
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.subsite.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.table.TableColumnModel;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.bebop.table.TableModelBuilder;
|
||||
import com.arsdigita.domain.DomainCollection;
|
||||
import com.arsdigita.domain.DomainObjectFactory;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.persistence.OID;
|
||||
import com.arsdigita.persistence.SessionManager;
|
||||
import com.arsdigita.subsite.Site;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
|
||||
/**
|
||||
* A table showing all subsites in the system.
|
||||
*
|
||||
* @author Jens Pelzetter <jens@jp-digital.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SiteTable extends Table implements TableActionListener {
|
||||
|
||||
private static final String TABLE_COL_EDIT = "table_col_edit";
|
||||
private static final String TABLE_COL_DEL = "table_col_del";
|
||||
//private final ParameterSingleSelectionModel siteSelect;
|
||||
private final SiteSelectionModel siteSelect;
|
||||
|
||||
public SiteTable(final SiteSelectionModel siteSelect) {
|
||||
|
||||
this.siteSelect = siteSelect;
|
||||
|
||||
setEmptyView(new Label(SubsiteGlobalizationUtil.globalize("subsite.ui.no_subsites")));
|
||||
|
||||
final TableColumnModel columnModel = getColumnModel();
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
0, SubsiteGlobalizationUtil.globalize("subsite.ui.title.label")));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
1, SubsiteGlobalizationUtil.globalize("subsite.ui.hostname.label")));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
2, SubsiteGlobalizationUtil.globalize("subsite.ui.customfrontpage.label")));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
3, SubsiteGlobalizationUtil.globalize("subsite.ui.theme.label")));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
4, SubsiteGlobalizationUtil.globalize("subsite.ui.root_category.label")));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
5, SubsiteGlobalizationUtil.globalize("subsite.ui.edit"),
|
||||
TABLE_COL_EDIT));
|
||||
|
||||
columnModel.add(new TableColumn(
|
||||
6, SubsiteGlobalizationUtil.globalize("subsite.ui.delete"),
|
||||
TABLE_COL_DEL));
|
||||
|
||||
setModelBuilder(new SiteTableModelBuilder());
|
||||
|
||||
columnModel.get(5).setCellRenderer(new EditCellRenderer());
|
||||
columnModel.get(6).setCellRenderer(new DeleteCellRenderer());
|
||||
|
||||
addTableActionListener(this);
|
||||
}
|
||||
|
||||
private class SiteTableModelBuilder extends LockableImpl implements TableModelBuilder {
|
||||
|
||||
@Override
|
||||
public TableModel makeModel(final Table table, final PageState state) {
|
||||
table.getRowSelectionModel().clearSelection(state);
|
||||
|
||||
return new SiteTableModel(table, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SiteTableModel implements TableModel {
|
||||
|
||||
private final Table table;
|
||||
private final DomainCollection sites;
|
||||
|
||||
public SiteTableModel(final Table table, final PageState state) {
|
||||
this.table = table;
|
||||
sites = new DomainCollection(SessionManager.getSession().retrieve(
|
||||
Site.BASE_DATA_OBJECT_TYPE));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return table.getColumnModel().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
return sites.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(final int columnIndex) {
|
||||
final Site site = (Site) sites.getDomainObject();
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return site.getTitle();
|
||||
case 1:
|
||||
return site.getHostname();
|
||||
case 2:
|
||||
return site.getFrontPage().getTitle();
|
||||
case 3:
|
||||
return site.getStyleDirectory();
|
||||
case 4:
|
||||
return site.getRootCategory().getDisplayName();
|
||||
case 5:
|
||||
return SubsiteGlobalizationUtil.globalize("subsite.ui.edit");
|
||||
case 6:
|
||||
return SubsiteGlobalizationUtil.globalize("subsite.ui.delete");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(final int columnIndex) {
|
||||
return sites.getDomainObject().getOID().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class EditCellRenderer extends LockableImpl implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final boolean isSelected,
|
||||
final Object key,
|
||||
final int row,
|
||||
final int column) {
|
||||
final ControlLink link = new ControlLink(new Label((GlobalizedMessage) value));
|
||||
return link;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DeleteCellRenderer extends LockableImpl implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state, final Object value,
|
||||
final boolean isSelected,
|
||||
final Object key,
|
||||
final int row,
|
||||
final int column) {
|
||||
final ControlLink link = new ControlLink(new Label((GlobalizedMessage) value));
|
||||
link.setConfirmation(SubsiteGlobalizationUtil.globalize("subsite.ui.delete.confirm"));
|
||||
return link;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cellSelected(final TableActionEvent event) {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
final Site site = (Site) DomainObjectFactory.newInstance(OID.valueOf(event.getRowKey().
|
||||
toString()));
|
||||
|
||||
final TableColumn column = getColumnModel().get(event.getColumn().intValue());
|
||||
|
||||
if (TABLE_COL_EDIT.equals(column.getHeaderKey().toString())) {
|
||||
siteSelect.setSelectedObject(state, site);
|
||||
} else if (TABLE_COL_DEL.equals(column.getHeaderKey().toString())) {
|
||||
site.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void headSelected(final TableActionEvent event) {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,3 +21,5 @@ subsite.ui.other_style_missing=If you choose {0} for the theme you need to provi
|
|||
subsite.ui.other_style_invalid=To set custom XSL directory select {0} in for the theme
|
||||
subsite.ui.root_category_missing=No root category selected
|
||||
subsite.ui.hostname_already_in\ use=The hostname {0} is already used by another subsite
|
||||
subsite.ui.edit=Edit
|
||||
subsite.ui.delete=Delete
|
||||
|
|
|
|||
|
|
@ -21,3 +21,5 @@ subsite.ui.other_style_missing=Wenn Sie {0} f\u00fcr das Theme w\u00e4hlen, m\u0
|
|||
subsite.ui.other_style_invalid=Um ein eigenes Verzeichnis mit XSL-Styles anzugeben, w\u00e4hlen Sie {0} f\u00fcr das Theme
|
||||
subsite.ui.root_category_missing=Kein Kategoriensystem ausgew\u00e4hlt
|
||||
subsite.ui.hostname_already_in\ use=Der Hostname {0} wird bereits von einer anderen Subsite verwendet
|
||||
subsite.ui.edit=Bearbeiten
|
||||
subsite.ui.delete=L\u00f6schen
|
||||
|
|
|
|||
Loading…
Reference in New Issue