001package gwt.material.design.client.ui; 002 003/* 004 * #%L 005 * GwtMaterial 006 * %% 007 * Copyright (C) 2015 GwtMaterialDesign 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import com.google.gwt.dom.client.Document; 024import com.google.gwt.dom.client.Element; 025import com.google.gwt.user.client.ui.Widget; 026import com.google.web.bindery.event.shared.HandlerRegistration; 027import gwt.material.design.client.base.HasSelectables; 028import gwt.material.design.client.base.MaterialWidget; 029import gwt.material.design.client.constants.CollapsibleType; 030import gwt.material.design.client.events.ClearActiveEvent; 031import gwt.material.design.client.events.ClearActiveEvent.ClearActiveHandler; 032 033//@formatter:off 034 035/** 036 * Collapsibles are accordion elements that expand when clicked on. 037 * They allow you to hide content that is not immediately relevant 038 * to the user. 039 * 040 * <h3>UiBinder Usage:</h3> 041 * 042 * <pre> 043 *{@code 044 * // Accordion 045 * <m:MaterialCollapsible type="ACCORDION" grid="s12 m6 l8"> 046 * <!-- ITEM 1 --> 047 * <m:MaterialCollapsibleItem> 048 * <m:MaterialCollapsibleHeader> 049 * <m:MaterialLink text="First" iconType="POLYMER" iconPosition="LEFT" textColor="black"/> 050 * </m:MaterialCollapsibleHeader> 051 * <m:MaterialCollapsibleBody> 052 * <m:MaterialLabel text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."/> 053 * </m:MaterialCollapsibleBody> 054 * </m:MaterialCollapsibleItem> 055 * </m:MaterialCollapsible> 056 * 057 * // Expandable 058 * <m:MaterialCollapsible type="EXPANDABLE" grid="s12 m6 l8"> 059 * <!-- ITEM 1 --> 060 * <m:MaterialCollapsibleItem> 061 * <m:MaterialCollapsibleHeader> 062 * <m:MaterialLink text="First" iconType="POLYMER" iconPosition="LEFT" textColor="black"/> 063 * </m:MaterialCollapsibleHeader> 064 * <m:MaterialCollapsibleBody> 065 * <m:MaterialLabel text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."/> 066 * </m:MaterialCollapsibleBody> 067 * </m:MaterialCollapsibleItem> 068 * </m:MaterialCollapsible> 069 * 070 * // Popout 071 * <m:MaterialCollapsible type="POPOUT" grid="s12 m6 l8"> 072 * <!-- ITEM 1 --> 073 * <m:MaterialCollapsibleItem> 074 * <m:MaterialCollapsibleHeader> 075 * <m:MaterialLink text="First" iconType="POLYMER" iconPosition="LEFT" textColor="black"/> 076 * </m:MaterialCollapsibleHeader> 077 * <m:MaterialCollapsibleBody> 078 * <m:MaterialLabel text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."/> 079 * </m:MaterialCollapsibleBody> 080 * </m:MaterialCollapsibleItem> 081 * </m:MaterialCollapsible> 082 * } 083 * </pre> 084 * 085 * @author kevzlou7979 086 * @author Ben Dol 087 * @see <a href="http://gwt-material-demo.herokuapp.com/#collapsibles">Material Collapsibles</a> 088 */ 089//@formatter:on 090public class MaterialCollapsible extends MaterialWidget implements HasSelectables { 091 092 protected interface HasCollapsibleParent { 093 void setParent(MaterialCollapsible parent); 094 } 095 096 private boolean initialized; 097 private boolean accordion = true; 098 099 private int activeIndex = -1; 100 private Widget activeWidget; 101 102 /** 103 * Creates an empty collapsible 104 */ 105 public MaterialCollapsible() { 106 super(Document.get().createULElement(), "collapsible"); 107 108 enableFeature(Feature.ONLOAD_ADD_QUEUE, true); 109 } 110 111 /** 112 * Creates a list and adds the given widgets. 113 */ 114 public MaterialCollapsible(final MaterialCollapsibleItem... widgets) { 115 this(); 116 117 for(final MaterialCollapsibleItem item : widgets) { 118 add(item); 119 } 120 } 121 122 @Override 123 protected void onLoad() { 124 super.onLoad(); 125 126 // Setup the expansion type 127 if (isAccordion()) { 128 getElement().setAttribute("data-collapsible", "accordion"); 129 } else { 130 getElement().setAttribute("data-collapsible", "expandable"); 131 } 132 133 // Activate preset activation index 134 if(activeIndex != -1 && activeWidget == null) { 135 setActive(activeIndex); 136 } 137 138 // Initialize collapsible after all elements 139 // are attached and marked as active, etc. 140 initCollapsible(getElement(), accordion); 141 } 142 143 @Override 144 public void add(final Widget child) { 145 if(child instanceof MaterialCollapsibleItem) { 146 ((MaterialCollapsibleItem) child).setParent(this); 147 } 148 super.add(child); 149 } 150 151 @Override 152 public boolean remove(Widget w) { 153 if(w instanceof MaterialCollapsibleItem) { 154 ((MaterialCollapsibleItem) w).setParent(null); 155 } 156 w.removeStyleName("active"); 157 158 return super.remove(w); 159 } 160 161 /** 162 * Initialize the collapsible material component. 163 */ 164 protected void initCollapsible() { 165 initCollapsible(getElement(), isAccordion()); 166 } 167 168 /** 169 * Initialize the collapsible material component. 170 */ 171 protected native void initCollapsible(final Element e, boolean accordion) /*-{ 172 $wnd.jQuery(document).ready(function() { 173 $wnd.jQuery(e).collapsible({ 174 accordion: accordion 175 }); 176 }); 177 this.@gwt.material.design.client.ui.MaterialCollapsible::initialized = true; 178 }-*/; 179 180 public void setType(CollapsibleType type) { 181 switch (type) { 182 case POPOUT: 183 addStyleName(type.getCssName()); 184 break; 185 default: 186 break; 187 } 188 } 189 190 /** 191 * Configure if you want this collapsible container to 192 * accordion its child elements or use expandable. 193 */ 194 public void setAccordion(boolean accordion) { 195 this.accordion = accordion; 196 197 if(initialized) { 198 // Since we have attached already reinitialize collapsible. 199 initCollapsible(); 200 } 201 } 202 203 public boolean isAccordion() { 204 return accordion; 205 } 206 207 /** 208 * Providing the one-based index of the 209 * {@link MaterialCollapsibleItem} to mark as active. 210 */ 211 public void setActive(int index) { 212 clearActive(); 213 activeIndex = index; 214 if(isAttached()) { 215 if(index <= getWidgetCount()) { 216 activeWidget = getWidget(index - 1); 217 if (activeWidget != null && activeWidget instanceof MaterialCollapsibleItem) { 218 ((MaterialCollapsibleItem) activeWidget).setActive(true); 219 if(initialized) { 220 initCollapsible(); 221 } 222 } 223 } 224 } 225 } 226 227 public HandlerRegistration addClearActiveHandler(final ClearActiveHandler handler) { 228 return addHandler(new ClearActiveHandler() { 229 @Override 230 public void onClearActive(ClearActiveEvent event) { 231 if(isEnabled()){ 232 handler.onClearActive(event); 233 } 234 } 235 }, ClearActiveEvent.TYPE); 236 } 237 238 @Override 239 public void clearActive() { 240 clearActiveClass(this); 241 ClearActiveEvent.fire(this); 242 } 243}