View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.console.panels;
20  
21  import java.io.Serializable;
22  import java.util.Optional;
23  import org.apache.commons.lang3.StringUtils;
24  import org.apache.syncope.client.console.policies.PolicyRuleWrapper;
25  import org.apache.syncope.client.console.wizards.WizardMgtPanel;
26  import org.apache.syncope.client.ui.commons.Constants;
27  import org.apache.syncope.client.ui.commons.status.StatusBean;
28  import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
29  import org.apache.syncope.common.keymaster.client.api.model.Domain;
30  import org.apache.syncope.common.lib.Attr;
31  import org.apache.syncope.common.lib.to.EntityTO;
32  import org.apache.syncope.common.lib.to.JobTO;
33  import org.apache.wicket.AttributeModifier;
34  import org.apache.wicket.Component;
35  import org.apache.wicket.PageReference;
36  import org.apache.wicket.ajax.AjaxEventBehavior;
37  import org.apache.wicket.ajax.AjaxRequestTarget;
38  import org.apache.wicket.ajax.markup.html.AjaxLink;
39  import org.apache.wicket.markup.html.WebMarkupContainer;
40  import org.apache.wicket.markup.html.basic.Label;
41  import org.apache.wicket.model.ResourceModel;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  /**
46   * Toggle panel.
47   *
48   * @param <T> model object type
49   */
50  public abstract class TogglePanel<T extends Serializable> extends WizardMgtPanel<T> {
51  
52      private static final long serialVersionUID = -2025535531121434056L;
53  
54      protected static final Logger LOG = LoggerFactory.getLogger(TogglePanel.class);
55  
56      protected static final int HEADER_FIRST_ABBREVIATION = 25;
57  
58      private enum Status {
59          INACTIVE,
60          ACTIVE
61  
62      }
63  
64      private static final String LABEL_DATA_VALUE = "data-value";
65  
66      private enum ToggleMenuCSS {
67          CLASS("toggle-menu"),
68          CLASS_ACTIVE("active-toggle-menu"),
69          CLASS_INACTIVE("active-toggle-menu");
70  
71          private final String value;
72  
73          ToggleMenuCSS(final String value) {
74              this.value = value;
75          }
76  
77          public String value() {
78              return value;
79          }
80  
81      }
82  
83      private final WebMarkupContainer container;
84  
85      private Status status = Status.INACTIVE;
86  
87      private final Label header;
88  
89      private final String activeId;
90  
91      public TogglePanel(final String id, final PageReference pageRef) {
92          this(id, id, pageRef);
93      }
94  
95      public TogglePanel(final String id, final String markupId, final PageReference pageRef) {
96          super(id, true);
97          this.activeId = markupId;
98          String containerID = StringUtils.isBlank(markupId) ? id : markupId;
99  
100         setRenderBodyOnly(true);
101         setOutputMarkupId(true);
102         disableContainerAutoRefresh();
103         setPageRef(pageRef);
104 
105         container = new WebMarkupContainer("togglePanelContainer");
106         super.addInnerObject(container.setMarkupId(containerID));
107 
108         header = new Label("label", StringUtils.EMPTY);
109         header.add(new AttributeModifier("title", new ResourceModel("copy_to_clipboard.title")));
110         header.setOutputMarkupId(true);
111         container.add(header);
112 
113         container.add(new AjaxLink<Void>("close") {
114 
115             private static final long serialVersionUID = 5538299138211283825L;
116 
117             @Override
118             public void onClick(final AjaxRequestTarget target) {
119                 toggle(target, false);
120             }
121 
122         }.add(new AjaxEventBehavior(Constants.ON_CLICK) {
123 
124             private static final long serialVersionUID = -9027652037484739586L;
125 
126             @Override
127             protected String findIndicatorId() {
128                 return StringUtils.EMPTY;
129             }
130 
131             @Override
132             protected void onEvent(final AjaxRequestTarget target) {
133                 // do nothing
134             }
135         }));
136     }
137 
138     /**
139      * Add object inside the main container.
140      *
141      * @param childs components to be added.
142      * @return the current panel instance.
143      */
144     @Override
145     public TogglePanel<T> addInnerObject(final Component... childs) {
146         container.addOrReplace(childs);
147         return this;
148     }
149 
150     protected void setHeader(final AjaxRequestTarget target, final String header) {
151         this.header.setDefaultModelObject(Optional.ofNullable(header).
152                 map(s -> StringUtils.abbreviate(s, HEADER_FIRST_ABBREVIATION)).orElse(StringUtils.EMPTY));
153         target.add(this.header);
154     }
155 
156     public void close(final AjaxRequestTarget target) {
157         toggle(target, false);
158     }
159 
160     @SuppressWarnings("cast")
161     protected String getTargetKey(final Serializable modelObject) {
162         final String key;
163         if (modelObject == null) {
164             key = new ResourceModel("actions", StringUtils.EMPTY).getObject();
165         } else if (modelObject instanceof EntityTO) {
166             key = ((EntityTO) modelObject).getKey();
167         } else if (modelObject instanceof AnyWrapper) {
168             key = ((AnyWrapper<?>) modelObject).getInnerObject().getKey();
169         } else if (modelObject instanceof Attr) {
170             key = ((Attr) modelObject).getSchema();
171         } else if (modelObject instanceof ConfParam) {
172             key = ((ConfParam) modelObject).getSchema();
173         } else if (modelObject instanceof StatusBean) {
174             key = StringUtils.isNotBlank(((StatusBean) modelObject).getResource())
175                     ? ((StatusBean) modelObject).getResource() : ((StatusBean) modelObject).getKey();
176         } else if (modelObject instanceof PolicyRuleWrapper) {
177             key = ((PolicyRuleWrapper) modelObject).getConf().getName();
178         } else if (modelObject instanceof JobTO) {
179             key = ((JobTO) modelObject).getRefKey() == null
180                     ? ((JobTO) modelObject).getRefDesc() : ((JobTO) modelObject).getRefKey();
181         } else if (modelObject instanceof ToggleableTarget) {
182             key = ((ToggleableTarget) modelObject).getKey();
183         } else if (modelObject instanceof Domain) {
184             key = ((Domain) modelObject).getKey();
185         } else {
186             key = new ResourceModel("actions", StringUtils.EMPTY).getObject();
187         }
188         return key;
189     }
190 
191     protected void updateLabelKeyValue(final Serializable modelObject) {
192         header.add(new AttributeModifier(LABEL_DATA_VALUE, getTargetKey(modelObject)));
193     }
194 
195     /**
196      * Force toggle via java. To be used when the onclick has been intercepted before.
197      * Also, set key value in label name for copy-to-clipboard feature.
198      *
199      * @param target ajax request target.
200      * @param modelObject model object
201      * @param toggle toggle action.
202      */
203     public void toggle(final AjaxRequestTarget target, final Serializable modelObject, final boolean toggle) {
204         updateLabelKeyValue(modelObject);
205 
206         toggle(target, toggle);
207     }
208 
209     /**
210      * Force toggle via java. To be used when the onclick has been intercepted before.
211      *
212      * @param target ajax request target.
213      * @param toggle toggle action.
214      */
215     public void toggle(final AjaxRequestTarget target, final boolean toggle) {
216         final String selector = String.format("$(\"div#%s\")", activeId);
217         if (toggle) {
218             if (status == Status.INACTIVE) {
219                 target.add(TogglePanel.this.container);
220                 target.appendJavaScript(
221                         selector + ".toggle(\"slow\");"
222                         + selector + ".attr(\"class\", \""
223                         + ToggleMenuCSS.CLASS.value() + ' ' + ToggleMenuCSS.CLASS_ACTIVE.value() + "\");");
224                 status = Status.ACTIVE;
225             } else if (status == Status.ACTIVE) {
226                 // useful when handling action menu after refreshing (ref. SYNCOPE-1134)
227                 target.appendJavaScript(
228                         selector + ".not(':visible')" + ".toggle(\"slow\")" + ".removeClass(\""
229                         + ToggleMenuCSS.CLASS_INACTIVE.value() + "\")"
230                         + ".addClass(\"" + ToggleMenuCSS.CLASS_ACTIVE.value() + "y\");");
231             }
232         } else if (status == Status.ACTIVE) {
233             target.appendJavaScript(
234                     selector + ".toggle(\"slow\");"
235                     + selector + ".attr(\"class\", \""
236                     + ToggleMenuCSS.CLASS.value() + ' ' + ToggleMenuCSS.CLASS_INACTIVE.value() + "\");");
237             status = Status.INACTIVE;
238         }
239     }
240 }