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