001/**
002 * Copyright 2005-2018 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.uif.layout;
017
018import org.kuali.rice.krad.datadictionary.parse.BeanTag;
019import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
020import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBeanBase;
021import org.kuali.rice.krad.uif.CssConstants;
022
023/**
024 * CssGridSizes are used by CssGridLayoutManagers to determine how much "column/cell" width an item will take up in a
025 * css grid layout.  It is important to note that sizes set will affect that screen size AND all screen sizes
026 * larger than that size unless those screen sizes also have a size explicitly set.  Each "row" is 12 across, so no
027 * sizes in this object are allowed to exceed this value.
028 *
029 * @author Kuali Rice Team (rice.collab@kuali.org)
030 */
031@BeanTag(name = "cssGridSizes-bean", parent = "Uif-CssGridSizes")
032public class CssGridSizes extends UifDictionaryBeanBase {
033    private static final long serialVersionUID = 4390107040745451681L;
034
035    private String cssClassString;
036
037    private int xsSize;
038    private int smSize;
039    private int mdSize;
040    private int lgSize;
041
042    private int smOffset = -1;
043    private int mdOffset = -1;
044    private int lgOffset = -1;
045
046    public CssGridSizes() {}
047
048    public CssGridSizes(int xsSize, int smSize, int mdSize, int lgSize) {
049        this.xsSize = xsSize;
050        this.smSize = smSize;
051        this.mdSize = mdSize;
052        this.lgSize = lgSize;
053    }
054
055    /**
056     * Gets the css class string to use on the cell div of this item, by concatnating the appropriate css
057     * classes based on the size values set on this object
058     *
059     * @return the css class string that represents the size of the "cell" div for this item at different screen sizes
060     */
061    public String getCssClassString() {
062        if (cssClassString != null) {
063            return cssClassString;
064        }
065
066        cssClassString = "";
067
068        concatenateSizeStyle(xsSize, CssConstants.CssGrid.XS_COL_PREFIX, 1);
069
070        concatenateSizeStyle(smSize, CssConstants.CssGrid.SM_COL_PREFIX, 1);
071        concatenateSizeStyle(smOffset, CssConstants.CssGrid.SM_OFFSET_PREFIX, 0);
072
073        concatenateSizeStyle(mdSize, CssConstants.CssGrid.MD_COL_PREFIX, 1);
074        concatenateSizeStyle(mdOffset, CssConstants.CssGrid.MD_OFFSET_PREFIX, 0);
075
076        concatenateSizeStyle(lgSize, CssConstants.CssGrid.LG_COL_PREFIX, 1);
077        concatenateSizeStyle(lgOffset, CssConstants.CssGrid.LG_OFFSET_PREFIX, 0);
078
079        cssClassString = cssClassString.trim();
080
081        return cssClassString;
082    }
083
084    /**
085     * Concatenates the styleClassPrefix with the size passed in, if the size is of minSize or greater
086     *
087     * @param size the size to use
088     * @param cssClassPrefix the css class prefix to use before size
089     * @param minSize the minimum size
090     */
091    private void concatenateSizeStyle(int size, String cssClassPrefix, int minSize) {
092        if (size >= minSize) {
093            cssClassString += " " + cssClassPrefix + size;
094        }
095
096        if (size > CssGridLayoutManager.NUMBER_OF_COLUMNS) {
097            throw new RuntimeException("Sizes in CssGridSizes cannot exceed " +
098                    CssGridLayoutManager.NUMBER_OF_COLUMNS);
099        }
100    }
101
102    /**
103     * The size this Component's "cell" div will take up at an extra small screen size (phone).
104     *
105     * <p>
106     *  If 0 this setting will be ignored (default).  This setting CANNOT exceed 12.
107     * </p>
108     *
109     * @return the extra small size
110     */
111    @BeanTagAttribute(name = "xsSize")
112    public int getXsSize() {
113        return xsSize;
114    }
115
116    /**
117     * @see CssGridSizes#getXsSize()
118     */
119    public void setXsSize(int xsSize) {
120        this.xsSize = xsSize;
121    }
122
123    /**
124     * The size this Component's "cell" div will take up at a small screen size (tablet).
125     *
126     * <p>
127     *  If 0 this setting will be ignored (default).  This setting CANNOT exceed 12.
128     * </p>
129     *
130     * @return the small size
131     */
132    @BeanTagAttribute(name = "smSize")
133    public int getSmSize() {
134        return smSize;
135    }
136
137    /**
138     * @see CssGridSizes#getSmSize()
139     */
140    public void setSmSize(int smSize) {
141        this.smSize = smSize;
142    }
143
144    /**
145     * The size this Component's "cell" div will take up at a medium screen size (desktop).
146     *
147     * <p>
148     *  If 0 this setting will be ignored (default).  This setting CANNOT exceed 12.
149     * </p>
150     *
151     * @return the medium size
152     */
153    @BeanTagAttribute(name = "mdSize")
154    public int getMdSize() {
155        return mdSize;
156    }
157
158    /**
159     * @see CssGridSizes#getMdSize()
160     */
161    public void setMdSize(int mdSize) {
162        this.mdSize = mdSize;
163    }
164
165    /**
166     * The size this Component's "cell" div will take up at a large screen size (large desktop).
167     *
168     * <p>
169     *  If 0 this setting will be ignored (default).  This setting CANNOT exceed 12.
170     * </p>
171     *
172     * @return the large size
173     */
174    @BeanTagAttribute(name = "lgSize")
175    public int getLgSize() {
176        return lgSize;
177    }
178
179    /**
180     * @see CssGridSizes#getLgSize()
181     */
182    public void setLgSize(int lgSize) {
183        this.lgSize = lgSize;
184    }
185
186    /**
187     * The offset (amount "pushed over") the div will have before the Component content at a small screen
188     * size (tablet).
189     *
190     * <p>
191     *  If -1 this setting will be ignored (default).  This setting CANNOT exceed 12 AND should not be
192     *  set to 12 as it will cause unintended behaviors (maximum should be 11 in most cases).  When using offset
193     *  it is recommended that the size of content in the "row" PLUS the offset and size of this "cell" at each screen
194     *  size DOES NOT exceed 12 or unintended layouts WILL result.  There is no extra small (xs) offset.
195     * </p>
196     *
197     * @return the small size offset
198     */
199    @BeanTagAttribute(name = "smOffset")
200    public int getSmOffset() {
201        return smOffset;
202    }
203
204    /**
205     * @see CssGridSizes#getSmOffset()
206     */
207    public void setSmOffset(int smOffset) {
208        this.smOffset = smOffset;
209    }
210
211    /**
212     * The offset (amount "pushed over") the div will have before the Component content at a medium screen
213     * size (desktop), this can be set to 0 to override previous screen size offsets.
214     *
215     * <p>
216     *  If -1 this setting will be ignored (default).  This setting CANNOT exceed 12 AND should not be
217     *  set to 12 as it will cause unintended behaviors (maximum should be 11 in most cases).  When using offset
218     *  it is recommended that the size of content in the "row" PLUS the offset and size of this "cell" at each screen
219     *  size DOES NOT exceed 12 or unintended layouts WILL result.  There is no extra small (xs) offset.
220     * </p>
221     *
222     * @return the medium size offset
223     */
224    @BeanTagAttribute(name = "mdOffset")
225    public int getMdOffset() {
226        return mdOffset;
227    }
228
229    /**
230     * @see CssGridSizes#getMdOffset()
231     */
232    public void setMdOffset(int mdOffset) {
233        this.mdOffset = mdOffset;
234    }
235
236    /**
237     * The offset (amount "pushed over") the div will have before the Component content at a large screen
238     * size (large desktop); this can be set to 0 to override previous screen size offsets.
239     *
240     * <p>
241     *  If -1 this setting will be ignored (default).  This setting CANNOT exceed 12 AND should not be
242     *  set to 12 as it will cause unintended behaviors (maximum should be 11 in most cases).  When using offset
243     *  it is recommended that the size of content in the "row" PLUS the offset and size of this "cell" at each screen
244     *  size DOES NOT exceed 12 or unintended layouts WILL result.  There is no extra small (xs) offset.
245     * </p>
246     *
247     * @return the large size offset
248     */
249    @BeanTagAttribute(name = "lgOffset")
250    public int getLgOffset() {
251        return lgOffset;
252    }
253
254    /**
255     * @see CssGridSizes#getLgOffset()
256     */
257    public void setLgOffset(int lgOffset) {
258        this.lgOffset = lgOffset;
259    }
260
261    /**
262     * Convenience setter for sizes which takes in 4 integers in this order: xsSize, smSize, mdSize, lgSize
263     *
264     * <p>
265     *     The length of this array MUST be 4.  Any values 0 or less will have the same affect as not setting that size.
266     * </p>
267     *
268     * @param sizes the sizes in order of xs, sm, md, lg
269     */
270    @BeanTagAttribute(name = "sizes", type = BeanTagAttribute.AttributeType.LISTVALUE)
271    public void setSizes(int[] sizes) {
272        if (sizes == null || sizes.length != 4) {
273            throw new RuntimeException("Sizes on CssGridSizes requires 4 and only 4 values.  Values that are not used "
274                    + "can be set to 0 or less.");
275        }
276
277        xsSize = sizes[0];
278        smSize = sizes[1];
279        mdSize = sizes[2];
280        lgSize = sizes[3];
281    }
282
283    /**
284     * Convenience setter for offsets which takes in 3 integers in this order: smOffset, mdOffset, lgOffset
285     *
286     * <p>
287     *     The length of this array MUST be 3.  Any values -1 or less will have the same affect as not setting that size
288     *     because (unlike sizes) 0 is a valid value for offsets.
289     * </p>
290     *
291     * @param offsets the sizes in order of sm, md, lg
292     */
293    @BeanTagAttribute(name = "offsets", type = BeanTagAttribute.AttributeType.LISTVALUE)
294    public void setOffsets(int[] offsets) {
295        if (offsets == null || offsets.length != 3) {
296            throw new RuntimeException("Offset on CssGridSizes requires 3 and only 3 values.  Values that are not used "
297                    + "can be set to -1 or less.");
298        }
299
300        smOffset = offsets[0];
301        mdOffset = offsets[1];
302        lgOffset = offsets[2];
303    }
304
305    /**
306     * Helper method to get the total space this div will take up at a small screen size, taking size, offset, and
307     * other size settings into account
308     *
309     * @return the total small size
310     */
311    public int getTotalSmSize() {
312        int totalSmSize = this.smSize;
313        if (totalSmSize == 0 && this.xsSize != 0) {
314            totalSmSize = this.xsSize;
315        }
316
317        if (smOffset > -1) {
318            return totalSmSize + smOffset;
319        } else {
320            return totalSmSize;
321        }
322    }
323
324    /**
325     * Helper method to get the total space this div will take up at a medium screen size, taking size, offset, and
326     * other size settings into account
327     *
328     * @return the total medium size
329     */
330    public int getTotalMdSize() {
331        int totalMdSize = this.mdSize;
332        if (totalMdSize == 0) {
333            if (this.smSize != 0) {
334                totalMdSize = this.smSize;
335            } else if (this.xsSize != 0) {
336                totalMdSize = this.xsSize;
337            }
338        }
339
340        if (mdOffset > -1) {
341            return totalMdSize + mdOffset;
342        } else if (smOffset > -1) {
343            return totalMdSize + smOffset;
344        } else {
345            return totalMdSize;
346        }
347    }
348
349    /**
350     * Helper method to get the total space this div will take up at a large screen size, taking size, offset, and
351     * other size settings into account
352     *
353     * @return the total large size
354     */
355    public int getTotalLgSize() {
356        int totalLgSize = this.lgSize;
357        if (totalLgSize == 0) {
358            if (this.mdSize != 0) {
359                totalLgSize = this.mdSize;
360            } else if (this.smSize != 0) {
361                totalLgSize = this.smSize;
362            } else if (this.xsSize != 0) {
363                totalLgSize = this.xsSize;
364            }
365        }
366
367        if (lgOffset > -1) {
368            return totalLgSize + lgOffset;
369        } else if (mdOffset > -1) {
370            return totalLgSize + mdOffset;
371        } else if (smOffset > -1) {
372            return totalLgSize + smOffset;
373        } else {
374            return totalLgSize;
375        }
376    }
377}