001package org.gwtbootstrap3.extras.summernote.client.ui.base; 002 003/* 004 * #%L 005 * GwtBootstrap3 006 * %% 007 * Copyright (C) 2016 GwtBootstrap3 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 org.gwtbootstrap3.client.ui.html.Div; 024import org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers; 025import org.gwtbootstrap3.extras.summernote.client.event.SummernoteBlurEvent; 026import org.gwtbootstrap3.extras.summernote.client.event.SummernoteBlurHandler; 027import org.gwtbootstrap3.extras.summernote.client.event.SummernoteChangeEvent; 028import org.gwtbootstrap3.extras.summernote.client.event.SummernoteChangeHandler; 029import org.gwtbootstrap3.extras.summernote.client.event.SummernoteEnterEvent; 030import org.gwtbootstrap3.extras.summernote.client.event.SummernoteEnterHandler; 031import org.gwtbootstrap3.extras.summernote.client.event.SummernoteFocusEvent; 032import org.gwtbootstrap3.extras.summernote.client.event.SummernoteFocusHandler; 033import org.gwtbootstrap3.extras.summernote.client.event.SummernoteImageUploadEvent; 034import org.gwtbootstrap3.extras.summernote.client.event.SummernoteImageUploadEvent.ImageFile; 035import org.gwtbootstrap3.extras.summernote.client.event.SummernoteImageUploadHandler; 036import org.gwtbootstrap3.extras.summernote.client.event.SummernoteInitEvent; 037import org.gwtbootstrap3.extras.summernote.client.event.SummernoteInitHandler; 038import org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyDownEvent; 039import org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyDownHandler; 040import org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyUpEvent; 041import org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyUpHandler; 042import org.gwtbootstrap3.extras.summernote.client.event.SummernotePasteEvent; 043import org.gwtbootstrap3.extras.summernote.client.event.SummernotePasteHandler; 044 045import com.google.gwt.core.client.JavaScriptObject; 046import com.google.gwt.core.client.JsArray; 047import com.google.gwt.core.client.JsArrayString; 048import com.google.gwt.core.client.ScriptInjector; 049import com.google.gwt.dom.client.Element; 050import com.google.gwt.event.shared.HandlerRegistration; 051import com.google.gwt.user.client.ui.HasEnabled; 052import com.google.gwt.user.client.ui.UIObject; 053 054/** 055 * Wrapper for the Summernote WYSIWYG Editor 056 * <p/> 057 * See: http://summernote.org/ 058 * 059 * @author Xiaodong Sun 060 */ 061public class SummernoteBase extends Div implements HasAllSummernoteHandlers, HasEnabled { 062 063 /** 064 * Language; defaults to {@link SummernoteLanguage#EN_US} 065 */ 066 private SummernoteLanguage language = SummernoteLanguage.EN_US; 067 068 /** 069 * Initialize options 070 */ 071 private SummernoteOptions options = SummernoteOptions.newOptions(); 072 073 /** 074 * Enabled/Disabled state 075 */ 076 private boolean enabled = true; 077 078 private boolean hasInitHandler = false; 079 private boolean hasEnterHandler = false; 080 private boolean hasFocusHandler = false; 081 private boolean hasBlurHandler = false; 082 private boolean hasKeyUpHandler = false; 083 private boolean hasKeyDownHandler = false; 084 private boolean hasPasteHandler = false; 085 private boolean hasUploadImageHandler = false; 086 private boolean hasChangeHandler = false; 087 088 /** 089 * 090 */ 091 public SummernoteBase() {} 092 093 /** 094 * Sets the default height of the editor (in pixel).<br> 095 * <br> 096 * <b>Note</b>: DO NOT renamed this method to <em>setHeight</em> 097 * to avoid UiBinder name clash with {@link UIObject#setHeight(String)}. 098 * 099 * @param height 100 */ 101 public void setDefaultHeight(final int height) { 102 options.setHeight(height); 103 } 104 105 /** 106 * Sets the maximum height of the editor (in pixel). 107 * 108 * @param maxHeight 109 */ 110 public void setMaxHeight(final int maxHeight) { 111 options.setMaxHeight(maxHeight); 112 } 113 114 /** 115 * Sets the minimum height of the editor (in pixel). 116 * 117 * @param minHeight 118 */ 119 public void setMinHeight(final int minHeight) { 120 options.setMinHeight(minHeight); 121 } 122 123 /** 124 * If <code>false</code> the toolbar will be hidden.<br> 125 * <br> 126 * Defaults to <code>true</code>. 127 * 128 * @param showToolbar 129 */ 130 public void setShowToolbar(final boolean showToolbar) { 131 options.setShowToolbar(showToolbar); 132 } 133 134 /** 135 * Customizes the toolbar.<br> 136 * <br> 137 * Example: 138 * <pre> 139 * summernote.setToolbar(new Toolbar() 140 * .addGroup(ToolbarButton.OL, ToolbarButton.BOLD) 141 * .addGroup(ToolbarButton.HELP)); 142 * </pre> 143 * 144 * @param toolbar 145 */ 146 public void setToolbar(final Toolbar toolbar) { 147 options.setToolbar(toolbar); 148 } 149 150 /** 151 * Set the focus of the editor. 152 * 153 * @param focus if <code>true</code>, focus on the editor 154 */ 155 public void setHasFocus(final boolean focus) { 156 options.setFocus(focus); 157 } 158 159 /** 160 * Set placeholder of the editor. 161 * 162 * @param placeholder placeholder of the editor 163 */ 164 public void setPlaceholder(final String placeholder) { 165 options.setPlaceholder(placeholder); 166 } 167 168 /** 169 * Set customized font names. 170 * 171 * @param fontNames customized font names 172 * @see SummernoteFontName 173 */ 174 public void setFontNames(final SummernoteFontName... fontNames) { 175 JsArrayString array = JavaScriptObject.createArray().cast(); 176 for (SummernoteFontName fontName : fontNames) { 177 array.push(fontName.getName()); 178 } 179 options.setFontNames(array); 180 } 181 182 /** 183 * Set a list for Web fonts to be ignored. <br> 184 * <br> 185 * Summernote tests font in fontNames before adding them to drop-down. 186 * This is problem while using Web fonts. It’s not easy picking up 187 * nice time to check availabilities of Web fonts. 188 * 189 * @param fontNames 190 */ 191 public void setFontNamesIgnoreCheck(final SummernoteFontName... fontNames) { 192 JsArrayString array = JavaScriptObject.createArray().cast(); 193 for (SummernoteFontName fontName : fontNames) { 194 array.push(fontName.getName()); 195 } 196 options.setFontNamesIgnoreCheck(array); 197 } 198 199 /** 200 * Set the air mode of the editor. Air-mode gives clearer interface with 201 * hidden toolbar. To reveal toolbar, select a text where you want to 202 * shape up.<br> 203 * <br> 204 * Defaults to <code>false</code>. 205 * 206 * @param airMode if <code>true</code>, the air mode is turn on 207 */ 208 public void setAirMode(final boolean airMode) { 209 options.setAirMode(airMode); 210 } 211 212 /** 213 * Set <code>false</code> to disable custom shortcuts.<br> 214 * <br> 215 * Defaults to <code>true</code>. 216 * 217 * @param shortcuts if <code>false</code>, disable custom shortcuts 218 */ 219 public void setShortcuts(final boolean shortcuts) { 220 options.setShortcuts(shortcuts); 221 } 222 223 /** 224 * Set <code>true</code> to place dialogs in <body> 225 * rather than in the editor.<br> 226 * <br> 227 * Defaults to <code>false</code>. 228 * 229 * @param dialogsInBody if <code>true</code>, place dialogs in <body> 230 */ 231 public void setDialogsInBody(final boolean dialogsInBody) { 232 options.setDialogsInBody(dialogsInBody); 233 } 234 235 /** 236 * Set <code>true</code> to turn on dialogs fading effect 237 * when showing or hiding.<br> 238 * <br> 239 * Defaults to <code>false</code>. 240 * 241 * @param dialogsFade if <code>true</code>, turn on dialogs fading effect 242 */ 243 public void setDialogsFade(final boolean dialogsFade) { 244 options.setDialogsFade(dialogsFade); 245 } 246 247 /** 248 * Set <code>true</code> to disable drag and drop.<br> 249 * <br> 250 * Defaults to <code>false</code>. 251 * 252 * @param disableDragAndDrop if <code>true</code>, disable drag and drop 253 */ 254 public void setDisableDragAndDrop(final boolean disableDragAndDrop) { 255 options.setDisableDragAndDrop(disableDragAndDrop); 256 } 257 258 /** 259 * Summernote support hint (autocomplete) feature. You can define custom hint 260 * with options. 261 * 262 * @param matchRegexp 263 * @param hintHandler 264 */ 265 public void setHint(String matchRegexp, HintHandler hintHandler) { 266 options.setHint(matchRegexp, hintHandler); 267 } 268 269 /** 270 * Set the editor language. 271 * 272 * @param language supported editor language 273 */ 274 public void setLanguage(final SummernoteLanguage language) { 275 options.setLanguage(language); 276 this.language = language; 277 } 278 279 /** 280 * Returns the editor language. 281 * 282 * @return 283 */ 284 public SummernoteLanguage getLanguage() { 285 return language; 286 } 287 288 @Override 289 public HandlerRegistration addSummernoteInitHandler(final SummernoteInitHandler handler) { 290 hasInitHandler = true; 291 return addHandler(handler, SummernoteInitEvent.getType()); 292 } 293 294 @Override 295 public HandlerRegistration addSummernoteEnterHandler(final SummernoteEnterHandler handler) { 296 hasEnterHandler = true; 297 return addHandler(handler, SummernoteEnterEvent.getType()); 298 } 299 300 @Override 301 public HandlerRegistration addSummernoteFocusHandler(final SummernoteFocusHandler handler) { 302 hasFocusHandler = true; 303 return addHandler(handler, SummernoteFocusEvent.getType()); 304 } 305 306 @Override 307 public HandlerRegistration addSummernoteBlurHandler(final SummernoteBlurHandler handler) { 308 hasBlurHandler = true; 309 return addHandler(handler, SummernoteBlurEvent.getType()); 310 } 311 312 @Override 313 public HandlerRegistration addSummernoteKeyUpHandler(final SummernoteKeyUpHandler handler) { 314 hasKeyUpHandler = true; 315 return addHandler(handler, SummernoteKeyUpEvent.getType()); 316 } 317 318 @Override 319 public HandlerRegistration addSummernoteKeyDownHandler(final SummernoteKeyDownHandler handler) { 320 hasKeyDownHandler = true; 321 return addHandler(handler, SummernoteKeyDownEvent.getType()); 322 } 323 324 @Override 325 public HandlerRegistration addSummernotePasteHandler(final SummernotePasteHandler handler) { 326 hasPasteHandler = true; 327 return addHandler(handler, SummernotePasteEvent.getType()); 328 } 329 330 @Override 331 public HandlerRegistration addSummernoteImageUploadHandler(final SummernoteImageUploadHandler handler) { 332 hasUploadImageHandler = true; 333 return addHandler(handler, SummernoteImageUploadEvent.getType()); 334 } 335 336 @Override 337 public HandlerRegistration addSummernoteChangeHandler(final SummernoteChangeHandler handler) { 338 hasChangeHandler = true; 339 return addHandler(handler, SummernoteChangeEvent.getType()); 340 } 341 342 /** 343 * Gets the HTML code generated from the editor 344 * 345 * @return generated code 346 */ 347 public String getCode() { 348 if (isAttached()) { 349 return getCode(getElement()); 350 } 351 return getElement().getInnerHTML(); 352 } 353 354 /** 355 * Sets the given HTML code to the editor. 356 * 357 * @param code 358 */ 359 public void setCode(final String code) { 360 if (isAttached()) { 361 setCode(getElement(), code); 362 } else { 363 getElement().setInnerHTML(code); 364 } 365 } 366 367 /** 368 * Returns <code>true</code> if the content is empty.<br> 369 * <br> 370 * Editing area needs <code><p><br></p></code></code> 371 * for focus, even if contents is empty. So summernote supports this method 372 * for helping to check contents is empty. 373 * 374 * @return <code>true</code> if the editor is empty 375 */ 376 public boolean isEmpty() { 377 if (isAttached()) { 378 return isEmpty(getElement()); 379 } 380 return getElement().getInnerHTML().isEmpty(); 381 } 382 383 /** 384 * Removes all contents and restores the editable instance 385 * to an <code>_emptyPara_</code>: <p><br></p> 386 */ 387 @Override 388 public void clear() { 389 if (isAttached()) { 390 command(getElement(), "empty"); 391 } else { 392 super.clear(); 393 getElement().removeAllChildren(); 394 } 395 } 396 397 @Override 398 public void setEnabled(boolean enabled) { 399 this.enabled = enabled; 400 if (isAttached()) { 401 command(getElement(), enabled ? "enable" : "disable"); 402 } 403 } 404 405 @Override 406 public boolean isEnabled() { 407 return enabled; 408 } 409 410 /** 411 * Clear editor contents and remove all stored history. 412 */ 413 public void reset() { 414 if (isAttached()) { 415 command(getElement(), "reset"); 416 } else { 417 clear(); 418 } 419 } 420 421 /** 422 * Call this when updating options to ensure everything is up to date 423 */ 424 public void reconfigure() { 425 destroy(getElement()); 426 initialize(); 427 } 428 429 private void initialize() { 430 // Inject the language JS is necessary 431 if (language.getJs() != null) { 432 ScriptInjector.fromString(language.getJs().getText()) 433 .setWindow(ScriptInjector.TOP_WINDOW).inject(); 434 } 435 // Initialize 436 initialize(getElement(), options); 437 // Enable/Disable editor 438 setEnabled(enabled); 439 } 440 441 @Override 442 protected void onLoad() { 443 super.onLoad(); 444 445 // Initialize 446 initialize(); 447 } 448 449 @Override 450 protected void onUnload() { 451 super.onUnload(); 452 453 // Destroy 454 destroy(getElement()); 455 } 456 457 /** 458 * Inserts the given images to the editor.<br> 459 * <br> 460 * This method should be used only when you customize 461 * the image upload handler. 462 * 463 * @param images 464 */ 465 public void insertImages(JsArray<ImageFile> images) { 466 insertImages(getElement(), images); 467 } 468 469 private native void initialize(Element e, SummernoteOptions options) /*-{ 470 var target = this; 471 options.callbacks = {}; 472 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasInitHandler) { 473 options.callbacks.onInit = function() { 474 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteInitEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteInitHandlers;)(target); 475 }; 476 } 477 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasEnterHandler) { 478 options.callbacks.onEnter = function () { 479 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteEnterEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteEnterHandlers;)(target); 480 }; 481 } 482 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasFocusHandler) { 483 options.callbacks.onFocus = function() { 484 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteFocusEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteFocusHandlers;)(target); 485 }; 486 } 487 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasBlurHandler) { 488 options.callbacks.onBlur = function() { 489 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteBlurEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteBlurHandlers;)(target); 490 }; 491 } 492 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasKeyUpHandler) { 493 options.callbacks.onKeyup = function(e) { 494 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyUpEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteKeyUpHandlers;Lcom/google/gwt/dom/client/NativeEvent;)(target, e.originalEvent); 495 }; 496 } 497 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasKeyDownHandler) { 498 options.callbacks.onKeydown = function(e) { 499 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteKeyDownEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteKeyDownHandlers;Lcom/google/gwt/dom/client/NativeEvent;)(target, e.originalEvent); 500 }; 501 } 502 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasUploadImageHandler) { 503 options.callbacks.onImageUpload = function(files) { 504 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteImageUploadEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteImageUploadHandlers;Lcom/google/gwt/core/client/JsArray;)(target, files); 505 }; 506 } 507 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasPasteHandler) { 508 options.callbacks.onPaste = function() { 509 @org.gwtbootstrap3.extras.summernote.client.event.SummernotePasteEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernotePasteHandlers;)(target); 510 }; 511 } 512 if (this.@org.gwtbootstrap3.extras.summernote.client.ui.base.SummernoteBase::hasChangeHandler) { 513 options.callbacks.onChange = function() { 514 @org.gwtbootstrap3.extras.summernote.client.event.SummernoteChangeEvent::fire(Lorg/gwtbootstrap3/extras/summernote/client/event/HasSummernoteChangeHandlers;)(target); 515 }; 516 } 517 $wnd.jQuery(e).summernote(options); 518 }-*/; 519 520 private native void destroy(Element e) /*-{ 521 $wnd.jQuery(e).summernote('destroy'); 522 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_INIT_EVENT); 523 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_ENTER_EVENT); 524 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_FOCUS_EVENT); 525 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_BLUR_EVENT); 526 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_KEYUP_EVENT); 527 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_KEYDOWN_EVENT); 528 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_PASTE_EVENT); 529 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_IMAGE_UPLOAD_EVENT); 530 $wnd.jQuery(e).off(@org.gwtbootstrap3.extras.summernote.client.event.HasAllSummernoteHandlers::SUMMERNOTE_CHANGE_EVENT); 531 }-*/; 532 533 private native void setCode(Element e, String code) /*-{ 534 $wnd.jQuery(e).summernote('code', code); 535 }-*/; 536 537 private native String getCode(Element e)/*-{ 538 return $wnd.jQuery(e).summernote('code'); 539 }-*/; 540 541 private native boolean isEmpty(Element e)/*-{ 542 return $wnd.jQuery(e).summernote('isEmpty'); 543 }-*/; 544 545 private native void command(Element e, String command)/*-{ 546 $wnd.jQuery(e).summernote(command); 547 }-*/; 548 549 private native void insertImages(Element e, JsArray<ImageFile> images) /*-{ 550 $wnd.jQuery(e).summernote('insertImages', images); 551 }-*/; 552}