Closure Library のダイアログを特定要素配下に生成する
TL;DR
デフォルトの機能では goog.ui.Dialog を特定要素配下に生成することはできない
goog.ui.Dialog とそれを使ういくつかのクラスを継承して挙動を変更すれば実現はできる
Closure Library 側の挙動が変われば簡単に壊れるので進んで採用したくない
何がしたかったか
goog.ui.Dialog から派生したダイアログはデフォルトで body 直下に div タグを生成する
body 直下では別途読み込まれているCSSと本来指定していスタイルが競合してしまうケースがあったので、ダイアログを body 直下ではなく 特定要素配下に生成するようにしたかった
問題点
goog.ui.Dialog は goog.ui.ModalPopup を継承し、 goog.ui.ModalPopup は goog.ui.Component を継承している
goog.ui.Component の render 関数は引数として opt_parentElement を受け付けていて、これを指定してあげれば特定要素配下に Component を生成してくれる
だたし goog.ui.Dialog では render を常に引数なしで呼び出してしまっている
renderIfNoDom_
setVisible
やったこと
goog.ui.Dialog を継承して renderIfNoDom_ と setVisible の挙動を変更する
以下は LinkDialogPlugin の例
code:foo/core.cljs
(ns foo.core
(:import goog.editor.plugins.LinkDialogPlugin
goog.ui.Dialog
goog.ui.editor.LinkDialog
goog.ui.editor.AbstractDialog.Builder))
;; Dialog の継承
(this-as this (.call Dialog this opt-class opt-use-iframe-mask opt-dom-helper)))
(goog/inherits WrappedDialog Dialog)
(set! (.. WrappedDialog -prototype -renderIfNoDom_)
(fn []
(this-as this
(when-not (.getElement this)
(.render this (js/document.querySelector "#この配下に置きたい"))))))
(set! (.. WrappedDialog -prototype -setVisible)
(this-as this
(when-not (= visible (.isVisible this))
(when-not (.isInDocument this)
(.render this (js/document.querySelector "#この配下に置きたい")))
(.base Dialog this "setVisible" visible)))))
;; AbstractDialog.Builder の継承
(this-as this
(.call Builder this editor-dialog)
;; 継承した Dialog を使うよう変更
(set! (.-wrappedDialog_ this) (WrappedDialog. "" true (.-dom editor-dialog)))
(.addClassName this "tr-dialog")
this))
(goog/inherits WrappedAbstractDialogBuilder Builder)
;; LinkDialog の継承
(this-as this (.call LinkDialog this dom-helper link)))
(goog/inherits WrappedLinkDialog LinkDialog)
(set! (.. WrappedLinkDialog -prototype -createDialogControl)
(fn []
(this-as this
;; 継承した AbstractDialog.Builder を使うよう変更
(doto builder
(.setTitle goog.ui.editor.messages.MSG_EDIT_LINK)
(.setContent (.createDialogContent_ this)))
(.build builder)))))
;; LinkDialogPlugin
(defn WrappedLinkDialogPlugin []
(this-as this (.call LinkDialogPlugin this)))
(goog/inherits WrappedLinkDialogPlugin LinkDialogPlugin)
(set! (.. WrappedLinkDialogPlugin -prototype -getTrogClassId)
(fn [] "MyWrappedLinkDialog"))
(set! (.. WrappedLinkDialogPlugin -prototype -createDialog)
(this-as this
;; ダイアログとして上記の WrappedLinkDialog を使うよう変更
(when (.-emailWarning_ this)
(.setEmailWarning dialog (.-emailWarning_ this)))
(when (.-showOpenLinkInNewWindow_ this)
(.showOpenLinkInNewWindow dialog (.-isOpenLinkInNewWindowChecked_ this)))
(when (.-showRelNoFollow_ this)
(.showRelNoFollow dialog))
(.setStopReferrerLeaks dialog (.-stopReferrerLeaks_ this))
(doto (.-eventHandler_ this)
(.listen dialog goog.ui.editor.AbstractDialog.EventType.OK (.-handleOk this))
(.listen dialog goog.ui.editor.AbstractDialog.EventType.CANCEL (.-handleCancel_ this))
(.listen dialog goog.ui.editor.LinkDialog.EventType.BEFORE_TEST_LINK (.-handleBeforeTestLink this)))
dialog))))