001package com.github.gwtbootstrap.client.ui;
002
003import com.github.gwtbootstrap.client.ui.base.HasVisibility;
004import com.github.gwtbootstrap.client.ui.base.HasVisibleHandlers;
005import com.github.gwtbootstrap.client.ui.base.MarkupWidget;
006import com.github.gwtbootstrap.client.ui.constants.Constants;
007import com.github.gwtbootstrap.client.ui.constants.VisibilityChange;
008import com.github.gwtbootstrap.client.ui.event.HiddenEvent;
009import com.github.gwtbootstrap.client.ui.event.HiddenHandler;
010import com.github.gwtbootstrap.client.ui.event.HideEvent;
011import com.github.gwtbootstrap.client.ui.event.HideHandler;
012import com.github.gwtbootstrap.client.ui.event.ShowEvent;
013import com.github.gwtbootstrap.client.ui.event.ShowHandler;
014import com.github.gwtbootstrap.client.ui.event.ShownEvent;
015import com.github.gwtbootstrap.client.ui.event.ShownHandler;
016import com.google.gwt.core.client.Scheduler;
017import com.google.gwt.core.client.Scheduler.ScheduledCommand;
018import com.google.gwt.dom.client.Element;
019import com.google.gwt.event.shared.HandlerRegistration;
020import com.google.gwt.user.client.Event;
021import com.google.gwt.user.client.ui.Widget;
022
023/**
024 * Markup widget of Collapse
025 * <p>
026 * It's a markup widget (decorator widget).
027 * it's can exchange child to Collapsible widget.
028 * 
029 * It's need trigger, You have 2 ways to create trigger.<br/>
030 * <ol>
031 *   <li> Using {@link CollapseTrigger}. </li>
032 *   <li> Calling {@link #toggle()}. </li>
033 * </ol>
034 * </p>
035 * 
036 * <p>
037 * <h3>UiBinder Usage:</h3>
038 * </p>
039 * <pre>
040 * {@code
041 * <b:Collapse b:id="toggle1" defaultOpen="true">
042 *   <!-- it can be added any widget, but accept one wdiget.
043 *   <b:Label>aaa</b:Label>
044 * </b:Collapse>
045 * }
046 * </pre>
047 * 
048 * @since 2.2.1.0
049 * @author ohashi keisuke
050 * @see Accordion
051 * @see Collapse
052 * @see CollapseTrigger
053 * @see <a href="http://twitter.github.com/bootstrap/javascript.html#collapse">Twitter Bootstrap document</a>
054 * 
055 *
056 */
057public class Collapse extends MarkupWidget implements HasVisibility, HasVisibleHandlers {
058
059    private String parent;
060    
061    private boolean toggle = false;
062    
063    private boolean existTrigger = false;
064
065    private boolean dafaultOpen;
066
067    /**
068     * Get parent selector
069     * @return parent parent selector
070     */
071    public String getParent() {
072        return parent;
073    }
074
075    /**
076     * Set parent selector.
077     * 
078     * it only work with {@link AccordionGroup},
079     * Please see <a href="https://github.com/twitter/bootstrap/issues/4988">this issue</a>.
080     * 
081     * @param parent parent selector
082     */
083    public void setParent(String parent) {
084        this.parent = parent;
085    }
086
087    /**
088     * is the collapsible element toggled on invocation
089     * @return toggle true:toggled , false: un-toggled
090     */
091    public boolean isToggle() {
092        return toggle;
093    }
094
095    /**
096     * Toggles the collapsible element on invocation
097     * @param toggle true: toggled on invocation , false : not-toggled
098     */
099    public void setToggle(boolean toggle) {
100        this.toggle = toggle;
101    }
102    
103    public void setDefaultOpen(boolean dafaultOpen) {
104        this.dafaultOpen = dafaultOpen;
105        
106        if(widget != null && !widget.isAttached()) {
107            widget.setStyleName(Constants.IN , dafaultOpen);
108        }
109        
110    }
111    
112    /**
113     * {@inheritDoc}
114     */
115    @Override
116    public Widget asWidget() {
117        
118        if(widget != null) {
119            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
120                
121                @Override
122                public void execute() {
123                    if(!isExistTrigger()){
124                        reconfigure();
125                    } else {
126                        setHandlerFunctions(widget.getElement());
127                    }
128                }
129            });
130        }
131        
132        return getWidget();
133    }
134    
135    /**
136     * {@inheritDoc}
137     */
138    @Override
139    public void setWidget(Widget w) {
140        super.setWidget(w);
141        
142        if(widget != null) {
143            widget.addStyleName(Constants.COLLAPSE);
144        }
145        
146    }
147    
148    /**
149     * {@inheritDoc}
150     */
151    @Override
152    public HandlerRegistration addHideHandler(HideHandler handler) {
153        return getWidget().addHandler(handler, HideEvent.getType());
154    }
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public HandlerRegistration addHiddenHandler(HiddenHandler handler) {
161        return getWidget().addHandler(handler, HiddenEvent.getType());
162    }
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public HandlerRegistration addShowHandler(ShowHandler handler) {
169        return getWidget().addHandler(handler, ShowEvent.getType());
170    }
171
172    /**
173     * {@inheritDoc}
174     */
175    @Override
176    public HandlerRegistration addShownHandler(ShownHandler handler) {
177        return getWidget().addHandler(handler, ShownEvent.getType());
178    }
179
180    /**
181     * {@inheritDoc}
182     */
183    @Override
184    public void show() {
185        changeVisibility(VisibilityChange.SHOW);
186    }
187
188    /**
189     * {@inheritDoc}
190     */
191    @Override
192    public void hide() {
193        changeVisibility(VisibilityChange.HIDE);
194    }
195
196    /**
197     * {@inheritDoc}
198     */
199    @Override
200    public void toggle() {
201        changeVisibility(VisibilityChange.TOGGLE);
202    }
203
204    /**
205     * Change visibility
206     * @param visibilityChange call method
207     */
208    protected void changeVisibility(VisibilityChange visibilityChange) {
209        
210        if(widget == null) return;
211        
212        changeVisibility(widget.getElement() , visibilityChange.get());
213    }
214    
215    /**
216     * Is exist Trigger?
217     * @return existTrigger
218     */
219    public boolean isExistTrigger() {
220        return existTrigger;
221    }
222
223    /**
224     * Is there the trigger(Collapse Trigger)
225     * @param existTrigger exists:true, none:false
226     */
227    public void setExistTrigger(boolean existTrigger) {
228        this.existTrigger = existTrigger;
229    }
230    
231    /**
232     * re configure setting
233     */
234    public void reconfigure() {
235        
236        if(widget == null) return;
237        
238        setDefaultOpen(dafaultOpen);
239        
240        removeDataIfExists(widget.getElement());
241        
242        setHandlerFunctions(widget.getElement());
243        
244        configure(widget.getElement(), parent, toggle);
245    }
246    
247    //@fomatter:off
248    /**
249     * Configure collapse settings.
250     * @param e element
251     * @param parent parent selector
252     * @param toggle is toggled on added document
253     */
254    public native void configure(Element e, String parent, boolean toggle) /*-{
255        $wnd.jQuery(e).collapse({
256            "parent" : parent || false,
257            "toggle" : toggle
258        });
259    }-*/;
260    
261    /**
262     * Configure collapse settings.
263     * @param selector selector
264     * @param parent parent selector
265     * @param toggle is toggled on added document
266     */
267    public static native void configure(String selector, String parent, boolean toggle) /*-{
268        $wnd.jQuery(selector).collapse({
269            "parent" : parent || false,
270            "toggle" : toggle
271        });
272        
273    }-*/;
274
275    /**
276     * Remove data api.
277     * @param e element
278     */
279    protected native void removeDataIfExists(Element e) /*-{
280        var $this = $wnd.jQuery(e);
281        if($this.data('collapse')) {
282            $this.removeData('parent').removeData('toggle').removeData('collapse');
283        }
284    }-*/;
285    
286    /**
287     * Links the Java functions that fire the events.
288     */
289    protected native void setHandlerFunctions(Element e) /*-{
290        var that = this;
291        var $this = $wnd.jQuery(e);
292
293        $this.off('show');
294        $this.off('shown');
295        $this.off('hide');
296        $this.off('hidden');
297
298        $this.on('hide', function(e) {
299            [email protected]::onHide(Lcom/google/gwt/user/client/Event;)(e);
300        });
301        $this.on('hidden', function(e) {
302            [email protected]::onHidden(Lcom/google/gwt/user/client/Event;)(e);
303        });
304        $this.on('show', function(e) {
305            [email protected]::onShow(Lcom/google/gwt/user/client/Event;)(e);
306        });
307        $this.on('shown', function(e) {
308            [email protected]::onShown(Lcom/google/gwt/user/client/Event;)(e);
309        });
310    }-*/;
311
312    protected native void changeVisibility(Element e , String c) /*-{
313        $wnd.jQuery(e).collapse(c);
314    }-*/;
315    
316    public static native void changeVisibility(String target , String c) /*-{
317        $wnd.jQuery(target).collapse(c);
318    }-*/;
319    //@fomatter:on
320
321
322    /**
323     * This method is called immediately when the widget's {@link #hide()}
324     * method is executed.
325     */
326    protected void onHide(Event e) {
327        widget.fireEvent(new HideEvent(e));
328    }
329
330    /**
331     * This method is called once the widget is completely hidden.
332     */
333    protected void onHidden(Event e) {
334        widget.fireEvent(new HiddenEvent(e));
335    }
336
337    /**
338     * This method is called immediately when the widget's {@link #show()}
339     * method is executed.
340     */
341    protected void onShow(Event e) {
342        widget.fireEvent(new ShowEvent(e));
343    }
344
345    /**
346     * This method is called once the widget is completely shown.
347     */
348    protected void onShown(Event e) {
349        widget.fireEvent(new ShownEvent(e));
350    }
351}