001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.dto.html5;
014
015import static org.apache.juneau.xml.annotation.XmlFormat.*;
016import static org.apache.juneau.html.annotation.HtmlFormat.*;
017
018import java.net.*;
019import java.net.URI;
020import java.util.*;
021import java.util.Map.*;
022
023import org.apache.juneau.*;
024import org.apache.juneau.annotation.*;
025import org.apache.juneau.html.*;
026import org.apache.juneau.internal.*;
027import org.apache.juneau.xml.annotation.*;
028
029/**
030 * Superclass for all HTML elements.
031 *
032 * <p>
033 * These are beans that when serialized using {@link HtmlSerializer} generate valid HTML5 elements.
034 *
035 * <ul class='seealso'>
036 *    <li class='link'>{@doc juneau-dto.HTML5}
037 * </ul>
038 */
039@org.apache.juneau.html.annotation.Html(format=XML)
040public abstract class HtmlElement {
041
042   private LinkedHashMap<String,Object> attrs;
043
044   /**
045    * The attributes of this element.
046    *
047    * @return The attributes of this element.
048    */
049   @Xml(format=ATTRS)
050   @Beanp("a")
051   public LinkedHashMap<String,Object> getAttrs() {
052      return attrs;
053   }
054
055   /**
056    * Sets the attributes for this element.
057    *
058    * @param attrs The new attributes for this element.
059    * @return This object (for method chaining).
060    */
061   @Beanp("a")
062   public HtmlElement setAttrs(LinkedHashMap<String,Object> attrs) {
063      for (Entry<String,Object> e : attrs.entrySet()) {
064         String key = e.getKey();
065         if ("url".equals(key) || "href".equals(key) || key.endsWith("action"))
066            e.setValue(StringUtils.toURI(e.getValue()));
067      }
068      this.attrs = attrs;
069      return this;
070   }
071
072   /**
073    * Adds an arbitrary attribute to this element.
074    *
075    * @param key The attribute name.
076    * @param val The attribute value.
077    * @return This object (for method chaining).
078    */
079   public HtmlElement attr(String key, Object val) {
080      if (this.attrs == null)
081         this.attrs = new LinkedHashMap<>();
082      if (val == null)
083         this.attrs.remove(key);
084      else {
085         if ("url".equals(key) || "href".equals(key) || key.endsWith("action"))
086            val = StringUtils.toURI(val);
087         this.attrs.put(key, val);
088      }
089      return this;
090   }
091
092   /**
093    * Adds an arbitrary URI attribute to this element.
094    *
095    * <p>
096    * Same as {@link #attr(String, Object)}, except if the value is a string that appears to be a URI
097    * (e.g. <js>"servlet:/xxx"</js>).
098    *
099    * <p>
100    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
101    * Strings must be valid URIs.
102    *
103    * <p>
104    * URIs defined by {@link UriResolver} can be used for values.
105    *
106    * @param key The attribute name.
107    * @param val The attribute value.
108    * @return This object (for method chaining).
109    */
110   public HtmlElement attrUri(String key, Object val) {
111      if (this.attrs == null)
112         this.attrs = new LinkedHashMap<>();
113      this.attrs.put(key, StringUtils.toURI(val));
114      return this;
115   }
116
117   /**
118    * Returns the attribute with the specified name.
119    *
120    * @param key The attribute name.
121    * @return The attribute value, or <jk>null</jk> if the named attribute does not exist.
122    */
123   public String getAttr(String key) {
124      return getAttr(String.class, key);
125   }
126
127   /**
128    * Returns the attribute with the specified name converted to the specified class type.
129    *
130    * @param type
131    *    The class type to convert this class to.
132    *    See {@link ObjectUtils} for a list of supported conversion types.
133    * @param key The attribute name.
134    * @return The attribute value, or <jk>null</jk> if the named attribute does not exist.
135    */
136   public <T> T getAttr(Class<T> type, String key) {
137      return attrs == null ? null : ObjectUtils.toType(attrs.get(key), type);
138   }
139
140   /**
141    * {@doc HTML5.editing#the-accesskey-attribute accesskey}
142    * attribute.
143    *
144    * @param accesskey The new value for this attribute.
145    * @return This object (for method chaining).
146    */
147   public HtmlElement accesskey(String accesskey) {
148      attr("accesskey", accesskey);
149      return this;
150   }
151
152   /**
153    * {@doc HTML5.dom#classes class} attribute.
154    *
155    * @param _class The new value for this attribute.
156    * @return This object (for method chaining).
157    */
158   public HtmlElement _class(String _class) {
159      attr("class", _class);
160      return this;
161   }
162
163   /**
164    * {@doc HTML5.editing#attr-contenteditable contenteditable}
165    * attribute.
166    *
167    * @param contenteditable The new value for this attribute.
168    * Typically a {@link Boolean} or {@link String}.
169    * @return This object (for method chaining).
170    */
171   public HtmlElement contenteditable(Object contenteditable) {
172      attr("contenteditable", contenteditable);
173      return this;
174   }
175
176   /**
177    * {@doc HTML5.dom#the-dir-attribute dir} attribute.
178    *
179    * @param dir The new value for this attribute.
180    * @return This object (for method chaining).
181    */
182   public HtmlElement dir(String dir) {
183      attr("dir", dir);
184      return this;
185   }
186
187   /**
188    * {@doc HTML5.editing#the-hidden-attribute hidden} attribute.
189    *
190    * @param hidden
191    *    The new value for this attribute.
192    *    Typically a {@link Boolean} or {@link String}.
193    * @return This object (for method chaining).
194    */
195   public HtmlElement hidden(Object hidden) {
196      attr("hidden", deminimize(hidden, "hidden"));
197      return this;
198   }
199
200   /**
201    * {@doc HTML5.dom#the-id-attribute id} attribute.
202    *
203    * @param id The new value for this attribute.
204    * @return This object (for method chaining).
205    */
206   public HtmlElement id(String id) {
207      attr("id", id);
208      return this;
209   }
210
211   /**
212    * {@doc HTML5.dom#attr-lang lang} attribute.
213    *
214    * @param lang The new value for this attribute.
215    * @return This object (for method chaining).
216    */
217   public HtmlElement lang(String lang) {
218      attr("lang", lang);
219      return this;
220   }
221
222   /**
223    * {@doc HTML5.webappapis#handler-onabort onabort} attribute.
224    *
225    * @param onabort The new value for this attribute.
226    * @return This object (for method chaining).
227    */
228   public HtmlElement onabort(String onabort) {
229      attr("onabort", onabort);
230      return this;
231   }
232
233   /**
234    * {@doc HTML5.webappapis#handler-onblur onblur} attribute.
235    *
236    * @param onblur The new value for this attribute.
237    * @return This object (for method chaining).
238    */
239   public HtmlElement onblur(String onblur) {
240      attr("onblur", onblur);
241      return this;
242   }
243
244   /**
245    * {@doc HTML5.webappapis#handler-oncancel oncancel} attribute.
246    *
247    * @param oncancel The new value for this attribute.
248    * @return This object (for method chaining).
249    */
250   public HtmlElement oncancel(String oncancel) {
251      attr("oncancel", oncancel);
252      return this;
253   }
254
255   /**
256    * {@doc HTML5.webappapis#handler-oncanplay oncanplay} attribute.
257    *
258    * @param oncanplay The new value for this attribute.
259    * @return This object (for method chaining).
260    */
261   public HtmlElement oncanplay(String oncanplay) {
262      attr("oncanplay", oncanplay);
263      return this;
264   }
265
266   /**
267    * {@doc HTML5.webappapis#handler-oncanplaythrough oncanplaythrough}
268    * attribute.
269    *
270    * @param oncanplaythrough The new value for this attribute.
271    * @return This object (for method chaining).
272    */
273   public HtmlElement oncanplaythrough(String oncanplaythrough) {
274      attr("oncanplaythrough", oncanplaythrough);
275      return this;
276   }
277
278   /**
279    * {@doc HTML5.webappapis#handler-onchange onchange} attribute.
280    *
281    * @param onchange The new value for this attribute.
282    * @return This object (for method chaining).
283    */
284   public HtmlElement onchange(String onchange) {
285      attr("onchange", onchange);
286      return this;
287   }
288
289   /**
290    * {@doc HTML5.webappapis#handler-onclick onclick} attribute.
291    *
292    * @param onclick The new value for this attribute.
293    * @return This object (for method chaining).
294    */
295   public HtmlElement onclick(String onclick) {
296      attr("onclick", onclick);
297      return this;
298   }
299
300   /**
301    * {@doc HTML5.webappapis#handler-oncuechange oncuechange}
302    * attribute.
303    *
304    * @param oncuechange The new value for this attribute.
305    * @return This object (for method chaining).
306    */
307   public HtmlElement oncuechange(String oncuechange) {
308      attr("oncuechange", oncuechange);
309      return this;
310   }
311
312   /**
313    * {@doc HTML5.webappapis#handler-ondblclick ondblclick} attribute.
314    *
315    * @param ondblclick The new value for this attribute.
316    * @return This object (for method chaining).
317    */
318   public HtmlElement ondblclick(String ondblclick) {
319      attr("ondblclick", ondblclick);
320      return this;
321   }
322
323   /**
324    * {@doc HTML5.webappapis#handler-ondurationchange ondurationchange}
325    * attribute.
326    *
327    * @param ondurationchange The new value for this attribute.
328    * @return This object (for method chaining).
329    */
330   public HtmlElement ondurationchange(String ondurationchange) {
331      attr("ondurationchange", ondurationchange);
332      return this;
333   }
334
335   /**
336    * {@doc HTML5.webappapis#handler-onemptied onemptied} attribute.
337    *
338    * @param onemptied The new value for this attribute.
339    * @return This object (for method chaining).
340    */
341   public HtmlElement onemptied(String onemptied) {
342      attr("onemptied", onemptied);
343      return this;
344   }
345
346   /**
347    * {@doc HTML5.webappapis#handler-onended onended} attribute.
348    *
349    * @param onended The new value for this attribute.
350    * @return This object (for method chaining).
351    */
352   public HtmlElement onended(String onended) {
353      attr("onended", onended);
354      return this;
355   }
356
357   /**
358    * {@doc HTML5.webappapis#handler-onerror onerror} attribute.
359    *
360    * @param onerror The new value for this attribute.
361    * @return This object (for method chaining).
362    */
363   public HtmlElement onerror(String onerror) {
364      attr("onerror", onerror);
365      return this;
366   }
367
368   /**
369    * {@doc HTML5.webappapis#handler-onfocus onfocus} attribute.
370    *
371    * @param onfocus The new value for this attribute.
372    * @return This object (for method chaining).
373    */
374   public HtmlElement onfocus(String onfocus) {
375      attr("onfocus", onfocus);
376      return this;
377   }
378
379   /**
380    * {@doc HTML5.webappapis#handler-oninput oninput} attribute.
381    *
382    * @param oninput The new value for this attribute.
383    * @return This object (for method chaining).
384    */
385   public HtmlElement oninput(String oninput) {
386      attr("oninput", oninput);
387      return this;
388   }
389
390   /**
391    * {@doc HTML5.webappapis#handler-oninvalid oninvalid} attribute.
392    *
393    * @param oninvalid The new value for this attribute.
394    * @return This object (for method chaining).
395    */
396   public HtmlElement oninvalid(String oninvalid) {
397      attr("oninvalid", oninvalid);
398      return this;
399   }
400
401   /**
402    * {@doc HTML5.webappapis#handler-onkeydown onkeydown} attribute.
403    *
404    * @param onkeydown The new value for this attribute.
405    * @return This object (for method chaining).
406    */
407   public HtmlElement onkeydown(String onkeydown) {
408      attr("onkeydown", onkeydown);
409      return this;
410   }
411
412   /**
413    * {@doc HTML5.webappapis#handler-onkeypress onkeypress} attribute.
414    *
415    * @param onkeypress The new value for this attribute.
416    * @return This object (for method chaining).
417    */
418   public HtmlElement onkeypress(String onkeypress) {
419      attr("onkeypress", onkeypress);
420      return this;
421   }
422
423   /**
424    * {@doc HTML5.webappapis#handler-onkeyup onkeyup} attribute.
425    *
426    * @param onkeyup The new value for this attribute.
427    * @return This object (for method chaining).
428    */
429   public HtmlElement onkeyup(String onkeyup) {
430      attr("onkeyup", onkeyup);
431      return this;
432   }
433
434   /**
435    * {@doc HTML5.webappapis#handler-onload onload} attribute.
436    *
437    * @param onload The new value for this attribute.
438    * @return This object (for method chaining).
439    */
440   public HtmlElement onload(String onload) {
441      attr("onload", onload);
442      return this;
443   }
444
445   /**
446    * {@doc HTML5.webappapis#handler-onloadeddata onloadeddata}
447    * attribute.
448    *
449    * @param onloadeddata The new value for this attribute.
450    * @return This object (for method chaining).
451    */
452   public HtmlElement onloadeddata(String onloadeddata) {
453      attr("onloadeddata", onloadeddata);
454      return this;
455   }
456
457   /**
458    * {@doc HTML5.webappapis#handler-onloadedmetadata onloadedmetadata}
459    * attribute.
460    *
461    * @param onloadedmetadata The new value for this attribute.
462    * @return This object (for method chaining).
463    */
464   public HtmlElement onloadedmetadata(String onloadedmetadata) {
465      attr("onloadedmetadata", onloadedmetadata);
466      return this;
467   }
468
469   /**
470    * {@doc HTML5.webappapis#handler-onloadstart onloadstart}
471    * attribute.
472    *
473    * @param onloadstart The new value for this attribute.
474    * @return This object (for method chaining).
475    */
476   public HtmlElement onloadstart(String onloadstart) {
477      attr("onloadstart", onloadstart);
478      return this;
479   }
480
481   /**
482    * {@doc HTML5.webappapis#handler-onmousedown onmousedown}
483    * attribute.
484    *
485    * @param onmousedown The new value for this attribute.
486    * @return This object (for method chaining).
487    */
488   public HtmlElement onmousedown(String onmousedown) {
489      attr("onmousedown", onmousedown);
490      return this;
491   }
492
493   /**
494    * {@doc HTML5.webappapis#handler-onmouseenter onmouseenter} attribute.
495    *
496    * @param onmouseenter The new value for this attribute.
497    * @return This object (for method chaining).
498    */
499   public HtmlElement onmouseenter(String onmouseenter) {
500      attr("onmouseenter", onmouseenter);
501      return this;
502   }
503
504   /**
505    * {@doc HTML5.webappapis#handler-onmouseleave onmouseleave}
506    * attribute.
507    *
508    * @param onmouseleave The new value for this attribute.
509    * @return This object (for method chaining).
510    */
511   public HtmlElement onmouseleave(String onmouseleave) {
512      attr("onmouseleave", onmouseleave);
513      return this;
514   }
515
516   /**
517    * {@doc HTML5.webappapis#handler-onmousemove onmousemove}
518    * attribute.
519    *
520    * @param onmousemove The new value for this attribute.
521    * @return This object (for method chaining).
522    */
523   public HtmlElement onmousemove(String onmousemove) {
524      attr("onmousemove", onmousemove);
525      return this;
526   }
527
528   /**
529    * {@doc HTML5.webappapis#handler-onmouseout onmouseout} attribute.
530    *
531    * @param onmouseout The new value for this attribute.
532    * @return This object (for method chaining).
533    */
534   public HtmlElement onmouseout(String onmouseout) {
535      attr("onmouseout", onmouseout);
536      return this;
537   }
538
539   /**
540    * {@doc HTML5.webappapis#handler-onmouseover onmouseover}
541    * attribute.
542    *
543    * @param onmouseover The new value for this attribute.
544    * @return This object (for method chaining).
545    */
546   public HtmlElement onmouseover(String onmouseover) {
547      attr("onmouseover", onmouseover);
548      return this;
549   }
550
551   /**
552    * {@doc HTML5.webappapis#handler-onmouseup onmouseup} attribute.
553    *
554    * @param onmouseup The new value for this attribute.
555    * @return This object (for method chaining).
556    */
557   public HtmlElement onmouseup(String onmouseup) {
558      attr("onmouseup", onmouseup);
559      return this;
560   }
561
562   /**
563    * {@doc HTML5.webappapis#handler-onmousewheel onmousewheel}
564    * attribute.
565    *
566    * @param onmousewheel The new value for this attribute.
567    * @return This object (for method chaining).
568    */
569   public HtmlElement onmousewheel(String onmousewheel) {
570      attr("onmousewheel", onmousewheel);
571      return this;
572   }
573
574   /**
575    * {@doc HTML5.webappapis#handler-onpause onpause} attribute.
576    *
577    * @param onpause The new value for this attribute.
578    * @return This object (for method chaining).
579    */
580   public HtmlElement onpause(String onpause) {
581      attr("onpause", onpause);
582      return this;
583   }
584
585   /**
586    * {@doc HTML5.webappapis#handler-onplay onplay} attribute.
587    *
588    * @param onplay The new value for this attribute.
589    * @return This object (for method chaining).
590    */
591   public HtmlElement onplay(String onplay) {
592      attr("onplay", onplay);
593      return this;
594   }
595
596   /**
597    * {@doc HTML5.webappapis#handler-onplaying onplaying} attribute.
598    *
599    * @param onplaying The new value for this attribute.
600    * @return This object (for method chaining).
601    */
602   public HtmlElement onplaying(String onplaying) {
603      attr("onplaying", onplaying);
604      return this;
605   }
606
607   /**
608    * {@doc HTML5.webappapis#handler-onprogress onprogress} attribute.
609    *
610    * @param onprogress The new value for this attribute.
611    * @return This object (for method chaining).
612    */
613   public HtmlElement onprogress(String onprogress) {
614      attr("onprogress", onprogress);
615      return this;
616   }
617
618   /**
619    * {@doc HTML5.webappapis#handler-onratechange onratechange}
620    * attribute.
621    *
622    * @param onratechange The new value for this attribute.
623    * @return This object (for method chaining).
624    */
625   public HtmlElement onratechange(String onratechange) {
626      attr("onratechange", onratechange);
627      return this;
628   }
629
630   /**
631    * {@doc HTML5.webappapis#handler-onreset onreset} attribute.
632    *
633    * @param onreset The new value for this attribute.
634    * @return This object (for method chaining).
635    */
636   public HtmlElement onreset(String onreset) {
637      attr("onreset", onreset);
638      return this;
639   }
640
641   /**
642    * {@doc HTML5.webappapis#handler-onresize onresize} attribute.
643    *
644    * @param onresize The new value for this attribute.
645    * @return This object (for method chaining).
646    */
647   public HtmlElement onresize(String onresize) {
648      attr("onresize", onresize);
649      return this;
650   }
651
652   /**
653    * {@doc HTML5.webappapis#handler-onscroll onscroll} attribute.
654    *
655    * @param onscroll The new value for this attribute.
656    * @return This object (for method chaining).
657    */
658   public HtmlElement onscroll(String onscroll) {
659      attr("onscroll", onscroll);
660      return this;
661   }
662
663   /**
664    * {@doc HTML5.webappapis#handler-onseeked onseeked} attribute.
665    *
666    * @param onseeked The new value for this attribute.
667    * @return This object (for method chaining).
668    */
669   public HtmlElement onseeked(String onseeked) {
670      attr("onseeked", onseeked);
671      return this;
672   }
673
674   /**
675    * {@doc HTML5.webappapis#handler-onseeking onseeking} attribute.
676    *
677    * @param onseeking The new value for this attribute.
678    * @return This object (for method chaining).
679    */
680   public HtmlElement onseeking(String onseeking) {
681      attr("onseeking", onseeking);
682      return this;
683   }
684
685   /**
686    * {@doc HTML5.webappapis#handler-onselect onselect} attribute.
687    *
688    * @param onselect The new value for this attribute.
689    * @return This object (for method chaining).
690    */
691   public HtmlElement onselect(String onselect) {
692      attr("onselect", onselect);
693      return this;
694   }
695
696   /**
697    * {@doc HTML5.webappapis#handler-onshow onshow} attribute.
698    *
699    * @param onshow The new value for this attribute.
700    * @return This object (for method chaining).
701    */
702   public HtmlElement onshow(String onshow) {
703      attr("onshow", onshow);
704      return this;
705   }
706
707   /**
708    * {@doc HTML5.webappapis#handler-onstalled onstalled} attribute.
709    *
710    * @param onstalled The new value for this attribute.
711    * @return This object (for method chaining).
712    */
713   public HtmlElement onstalled(String onstalled) {
714      attr("onstalled", onstalled);
715      return this;
716   }
717
718   /**
719    * {@doc HTML5.webappapis#handler-onsubmit onsubmit} attribute.
720    *
721    * @param onsubmit The new value for this attribute.
722    * @return This object (for method chaining).
723    */
724   public HtmlElement onsubmit(String onsubmit) {
725      attr("onsubmit", onsubmit);
726      return this;
727   }
728
729   /**
730    * {@doc HTML5.webappapis#handler-onsuspend onsuspend} attribute.
731    *
732    * @param onsuspend The new value for this attribute.
733    * @return This object (for method chaining).
734    */
735   public HtmlElement onsuspend(String onsuspend) {
736      attr("onsuspend", onsuspend);
737      return this;
738   }
739
740   /**
741    * {@doc HTML5.webappapis#handler-ontimeupdate ontimeupdate}
742    * attribute.
743    *
744    * @param ontimeupdate The new value for this attribute.
745    * @return This object (for method chaining).
746    */
747   public HtmlElement ontimeupdate(String ontimeupdate) {
748      attr("ontimeupdate", ontimeupdate);
749      return this;
750   }
751
752   /**
753    * {@doc HTML5.webappapis#handler-ontoggle ontoggle} attribute.
754    *
755    * @param ontoggle The new value for this attribute.
756    * @return This object (for method chaining).
757    */
758   public HtmlElement ontoggle(String ontoggle) {
759      attr("ontoggle", ontoggle);
760      return this;
761   }
762
763   /**
764    * {@doc HTML5.webappapis#handler-onvolumechange onvolumechange}
765    * attribute.
766    *
767    * @param onvolumechange The new value for this attribute.
768    * @return This object (for method chaining).
769    */
770   public HtmlElement onvolumechange(String onvolumechange) {
771      attr("onvolumechange", onvolumechange);
772      return this;
773   }
774
775   /**
776    * {@doc HTML5.webappapis#handler-onwaiting onwaiting} attribute.
777    *
778    * @param onwaiting The new value for this attribute.
779    * @return This object (for method chaining).
780    */
781   public HtmlElement onwaiting(String onwaiting) {
782      attr("onwaiting", onwaiting);
783      return this;
784   }
785
786   /**
787    * {@doc HTML5.editing#attr-spellcheck spellcheck} attribute.
788    *
789    * @param spellcheck
790    *    The new value for this attribute.
791    *    Typically a {@link Boolean} or {@link String}.
792    * @return This object (for method chaining).
793    */
794   public HtmlElement spellcheck(Object spellcheck) {
795      attr("spellcheck", spellcheck);
796      return this;
797   }
798
799   /**
800    * {@doc HTML5.dom#the-style-attribute style} attribute.
801    *
802    * @param style The new value for this attribute.
803    * @return This object (for method chaining).
804    */
805   public HtmlElement style(String style) {
806      attr("style", style);
807      return this;
808   }
809
810   /**
811    * {@doc HTML5.editing#attr-tabindex tabindex} attribute.
812    *
813    * @param tabindex
814    *    The new value for this attribute.
815    *    Typically a {@link Number} or {@link String}.
816    * @return This object (for method chaining).
817    */
818   public HtmlElement tabindex(Object tabindex) {
819      attr("tabindex", tabindex);
820      return this;
821   }
822
823   /**
824    * {@doc HTML5.dom#attr-title title} attribute.
825    *
826    * @param title The new value for this attribute.
827    * @return This object (for method chaining).
828    */
829   public HtmlElement title(String title) {
830      attr("title", title);
831      return this;
832   }
833
834   /**
835    * {@doc HTML5.dom#attr-translate translate} attribute.
836    *
837    * @param translate
838    *    The new value for this attribute.
839    *    Typically a {@link Number} or {@link String}.
840    * @return This object (for method chaining).
841    */
842   public HtmlElement translate(Object translate) {
843      attr("translate", translate);
844      return this;
845   }
846
847   /**
848    * If the specified attribute is a boolean, it gets converted to the attribute name if <jk>true</jk> or <jk>null</jk> if <jk>false</jk>.
849    *
850    * @param value The attribute value.
851    * @param attr The attribute name.
852    * @return The deminimized value, or the same value if the value wasn't a boolean.
853    */
854   protected Object deminimize(Object value, String attr) {
855      if (value instanceof Boolean) {
856         if ((Boolean)value)
857            return attr;
858         return null;
859      }
860      return value;
861   }
862
863   @Override /* Object */
864   public String toString() {
865      return HtmlSerializer.DEFAULT_SQ.toString(this);
866   }
867}