IFrame.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /**
  2. * --------------------------------------------
  3. * AdminLTE IFrame.js
  4. * License MIT
  5. * --------------------------------------------
  6. */
  7. import $ from 'jquery'
  8. /**
  9. * Constants
  10. * ====================================================
  11. */
  12. const NAME = 'IFrame'
  13. const DATA_KEY = 'lte.iframe'
  14. const JQUERY_NO_CONFLICT = $.fn[NAME]
  15. const SELECTOR_DATA_TOGGLE = '[data-widget="iframe"]'
  16. const SELECTOR_DATA_TOGGLE_CLOSE = '[data-widget="iframe-close"]'
  17. const SELECTOR_DATA_TOGGLE_SCROLL_LEFT = '[data-widget="iframe-scrollleft"]'
  18. const SELECTOR_DATA_TOGGLE_SCROLL_RIGHT = '[data-widget="iframe-scrollright"]'
  19. const SELECTOR_CONTENT_WRAPPER = '.content-wrapper'
  20. const SELECTOR_CONTENT_IFRAME = `${SELECTOR_CONTENT_WRAPPER} iframe`
  21. const SELECTOR_TAB_NAV = `${SELECTOR_DATA_TOGGLE}.iframe-mode .nav`
  22. const SELECTOR_TAB_NAVBAR_NAV = `${SELECTOR_DATA_TOGGLE}.iframe-mode .navbar-nav`
  23. const SELECTOR_TAB_NAVBAR_NAV_ITEM = `${SELECTOR_TAB_NAVBAR_NAV} .nav-item`
  24. const SELECTOR_TAB_CONTENT = `${SELECTOR_DATA_TOGGLE}.iframe-mode .tab-content`
  25. const SELECTOR_TAB_EMPTY = `${SELECTOR_TAB_CONTENT} .tab-empty`
  26. const SELECTOR_TAB_LOADING = `${SELECTOR_TAB_CONTENT} .tab-loading`
  27. const SELECTOR_SIDEBAR_MENU_ITEM = '.main-sidebar .nav-item > a.nav-link'
  28. const SELECTOR_HEADER_MENU_ITEM = '.main-header .nav-item a.nav-link'
  29. const SELECTOR_HEADER_DROPDOWN_ITEM = '.main-header a.dropdown-item'
  30. const CLASS_NAME_IFRAME_MODE = 'iframe-mode'
  31. const Default = {
  32. onTabClick(item) {
  33. return item
  34. },
  35. onTabChanged(item) {
  36. return item
  37. },
  38. onTabCreated(item) {
  39. return item
  40. },
  41. autoIframeMode: true,
  42. autoItemActive: true,
  43. autoShowNewTab: true,
  44. loadingScreen: true,
  45. useNavbarItems: true,
  46. scrollOffset: 40,
  47. scrollBehaviorSwap: false
  48. }
  49. /**
  50. * Class Definition
  51. * ====================================================
  52. */
  53. class IFrame {
  54. constructor(element, config) {
  55. this._config = config
  56. this._element = element
  57. this._init()
  58. }
  59. // Public
  60. onTabClick(item) {
  61. this._config.onTabClick(item)
  62. }
  63. onTabChanged(item) {
  64. this._config.onTabChanged(item)
  65. }
  66. onTabCreated(item) {
  67. this._config.onTabCreated(item)
  68. }
  69. createTab(title, link, uniqueName, autoOpen) {
  70. const tabId = `panel-${uniqueName}-${Math.floor(Math.random() * 1000)}`
  71. const navId = `tab-${uniqueName}-${Math.floor(Math.random() * 1000)}`
  72. const newNavItem = `<li class="nav-item" role="presentation"><a class="nav-link" data-toggle="row" id="${navId}" href="#${tabId}" role="tab" aria-controls="${tabId}" aria-selected="false">${title}</a></li>`
  73. $(SELECTOR_TAB_NAVBAR_NAV).append(newNavItem)
  74. const newTabItem = `<div class="tab-pane fade" id="${tabId}" role="tabpanel" aria-labelledby="${navId}"><iframe src="${link}"></iframe></div>`
  75. $(SELECTOR_TAB_CONTENT).append(newTabItem)
  76. if (autoOpen) {
  77. if (this._config.loadingScreen) {
  78. const $loadingScreen = $(SELECTOR_TAB_LOADING)
  79. $loadingScreen.fadeIn()
  80. $(`${tabId} iframe`).ready(() => {
  81. if (typeof this._config.loadingScreen === 'number') {
  82. this.switchTab(`#${navId}`, this._config.loadingScreen)
  83. setTimeout(() => {
  84. $loadingScreen.fadeOut()
  85. }, this._config.loadingScreen)
  86. } else {
  87. this.switchTab(`#${navId}`, this._config.loadingScreen)
  88. $loadingScreen.fadeOut()
  89. }
  90. })
  91. } else {
  92. this.switchTab(`#${navId}`)
  93. }
  94. }
  95. this.onTabCreated($(`#${navId}`))
  96. }
  97. openTabSidebar(item, autoOpen = this._config.autoShowNewTab) {
  98. let $item = $(item).clone()
  99. if ($item.attr('href') === undefined) {
  100. $item = $(item).parent('a').clone()
  101. }
  102. $item.find('.right').remove()
  103. let title = $item.find('p').text()
  104. if (title === '') {
  105. title = $item.text()
  106. }
  107. const link = $item.attr('href')
  108. if (link === '#' || link === '' || link === undefined) {
  109. return
  110. }
  111. this.createTab(title, link, link.replace('.html', '').replace('./', '').replaceAll('/', '-'), autoOpen)
  112. }
  113. switchTab(item) {
  114. const $item = $(item)
  115. const tabId = $item.attr('href')
  116. $(SELECTOR_TAB_EMPTY).hide()
  117. $(`${SELECTOR_TAB_NAVBAR_NAV} .active`).tab('dispose').removeClass('active')
  118. this._fixHeight()
  119. $item.tab('show')
  120. $item.parents('li').addClass('active')
  121. this.onTabChanged($item)
  122. if (this._config.autoItemActive) {
  123. this._setItemActive($(`${tabId} iframe`).attr('src'))
  124. }
  125. }
  126. removeActiveTab() {
  127. const $navItem = $(`${SELECTOR_TAB_NAVBAR_NAV_ITEM}.active`)
  128. const $navItemParent = $navItem.parent()
  129. const navItemIndex = $navItem.index()
  130. $navItem.remove()
  131. $('.tab-pane.active').remove()
  132. if ($(SELECTOR_TAB_CONTENT).children().length == $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).length) {
  133. $(SELECTOR_TAB_EMPTY).show()
  134. } else {
  135. const prevNavItemIndex = navItemIndex - 1
  136. this.switchTab($navItemParent.children().eq(prevNavItemIndex).find('a'))
  137. }
  138. }
  139. // Private
  140. _init() {
  141. if (window.frameElement && this._config.autoIframeMode) {
  142. $('body').addClass(CLASS_NAME_IFRAME_MODE)
  143. } else if ($(SELECTOR_CONTENT_WRAPPER).hasClass(CLASS_NAME_IFRAME_MODE)) {
  144. this._setupListeners()
  145. this._fixHeight(true)
  146. }
  147. }
  148. _navScroll(offset) {
  149. const leftPos = $(SELECTOR_TAB_NAVBAR_NAV).scrollLeft()
  150. $(SELECTOR_TAB_NAVBAR_NAV).animate({ scrollLeft: (leftPos + offset) }, 250, 'linear')
  151. }
  152. _setupListeners() {
  153. $(window).on('resize', () => {
  154. setTimeout(() => {
  155. this._fixHeight()
  156. }, 1)
  157. })
  158. $(document).on('click', SELECTOR_SIDEBAR_MENU_ITEM, e => {
  159. e.preventDefault()
  160. this.openTabSidebar(e.target)
  161. })
  162. if (this._config.useNavbarItems) {
  163. $(document).on('click', `${SELECTOR_HEADER_MENU_ITEM}, ${SELECTOR_HEADER_DROPDOWN_ITEM}`, e => {
  164. e.preventDefault()
  165. this.openTabSidebar(e.target)
  166. })
  167. }
  168. $(document).on('click', SELECTOR_TAB_NAVBAR_NAV_ITEM, e => {
  169. e.preventDefault()
  170. this.onTabClick(e.target)
  171. this.switchTab(e.target)
  172. })
  173. $(document).on('click', SELECTOR_DATA_TOGGLE_CLOSE, e => {
  174. e.preventDefault()
  175. this.removeActiveTab()
  176. })
  177. let mousedown = false
  178. let mousedownInterval = null
  179. $(document).on('mousedown', SELECTOR_DATA_TOGGLE_SCROLL_LEFT, e => {
  180. e.preventDefault()
  181. clearInterval(mousedownInterval)
  182. let { scrollOffset } = this._config
  183. if (!this._config.scrollBehaviorSwap) {
  184. scrollOffset = -scrollOffset
  185. }
  186. mousedown = true
  187. this._navScroll(scrollOffset)
  188. mousedownInterval = setInterval(() => {
  189. this._navScroll(scrollOffset)
  190. }, 250)
  191. })
  192. $(document).on('mousedown', SELECTOR_DATA_TOGGLE_SCROLL_RIGHT, e => {
  193. e.preventDefault()
  194. clearInterval(mousedownInterval)
  195. let { scrollOffset } = this._config
  196. if (this._config.scrollBehaviorSwap) {
  197. scrollOffset = -scrollOffset
  198. }
  199. mousedown = true
  200. this._navScroll(scrollOffset)
  201. mousedownInterval = setInterval(() => {
  202. this._navScroll(scrollOffset)
  203. }, 250)
  204. })
  205. $(document).on('mouseup', () => {
  206. if (mousedown) {
  207. mousedown = false
  208. clearInterval(mousedownInterval)
  209. mousedownInterval = null
  210. }
  211. })
  212. }
  213. _setItemActive(href) {
  214. $(`${SELECTOR_SIDEBAR_MENU_ITEM}, ${SELECTOR_HEADER_DROPDOWN_ITEM}`).removeClass('active')
  215. $(SELECTOR_HEADER_MENU_ITEM).parent().removeClass('active')
  216. const $headerMenuItem = $(`${SELECTOR_HEADER_MENU_ITEM}[href$="${href}"]`)
  217. const $headerDropdownItem = $(`${SELECTOR_HEADER_DROPDOWN_ITEM}[href$="${href}"]`)
  218. const $sidebarMenuItem = $(`${SELECTOR_SIDEBAR_MENU_ITEM}[href$="${href}"]`)
  219. $headerMenuItem.each((i, e) => {
  220. $(e).parent().addClass('active')
  221. })
  222. $headerDropdownItem.each((i, e) => {
  223. $(e).addClass('active')
  224. })
  225. $sidebarMenuItem.each((i, e) => {
  226. $(e).addClass('active')
  227. $(e).parents('.nav-treeview').prevAll('.nav-link').addClass('active')
  228. })
  229. }
  230. _fixHeight(tabEmpty = false) {
  231. const contentWrapperHeight = parseFloat($(SELECTOR_CONTENT_WRAPPER).css('min-height'))
  232. const navbarHeight = $(SELECTOR_TAB_NAV).outerHeight()
  233. if (tabEmpty == true) {
  234. setTimeout(() => {
  235. $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).height(contentWrapperHeight - navbarHeight)
  236. }, 50)
  237. } else {
  238. $(SELECTOR_CONTENT_IFRAME).height(contentWrapperHeight - navbarHeight)
  239. }
  240. }
  241. // Static
  242. static _jQueryInterface(operation, ...args) {
  243. let data = $(this).data(DATA_KEY)
  244. const _options = $.extend({}, Default, $(this).data())
  245. if (!data) {
  246. data = new IFrame(this, _options)
  247. $(this).data(DATA_KEY, data)
  248. }
  249. if (typeof operation === 'string' && operation.match(/createTab|openTabSidebar|switchTab|removeActiveTab/)) {
  250. data[operation](...args)
  251. }
  252. }
  253. }
  254. /**
  255. * Data API
  256. * ====================================================
  257. */
  258. $(window).on('load', () => {
  259. IFrame._jQueryInterface.call($(SELECTOR_DATA_TOGGLE))
  260. })
  261. /**
  262. * jQuery API
  263. * ====================================================
  264. */
  265. $.fn[NAME] = IFrame._jQueryInterface
  266. $.fn[NAME].Constructor = IFrame
  267. $.fn[NAME].noConflict = function () {
  268. $.fn[NAME] = JQUERY_NO_CONFLICT
  269. return IFrame._jQueryInterface
  270. }
  271. export default IFrame