card-widget.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /**
  2. * --------------------------------------------
  3. * AdminLTE card-widget.ts
  4. * License MIT
  5. * --------------------------------------------
  6. */
  7. import {
  8. domReady,
  9. slideUp,
  10. slideDown
  11. } from './util/index'
  12. /**
  13. * Constants
  14. * ====================================================
  15. */
  16. const DATA_KEY = 'lte.card-widget'
  17. const EVENT_KEY = `.${DATA_KEY}`
  18. const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
  19. const EVENT_EXPANDED = `expanded${EVENT_KEY}`
  20. const EVENT_REMOVE = `remove${EVENT_KEY}`
  21. const EVENT_MAXIMIZED = `maximized${EVENT_KEY}`
  22. const EVENT_MINIMIZED = `minimized${EVENT_KEY}`
  23. const CLASS_NAME_CARD = 'card'
  24. const CLASS_NAME_COLLAPSED = 'collapsed-card'
  25. const CLASS_NAME_COLLAPSING = 'collapsing-card'
  26. const CLASS_NAME_EXPANDING = 'expanding-card'
  27. const CLASS_NAME_WAS_COLLAPSED = 'was-collapsed'
  28. const CLASS_NAME_MAXIMIZED = 'maximized-card'
  29. const SELECTOR_DATA_REMOVE = '[data-lte-dismiss="card-remove"]'
  30. const SELECTOR_DATA_COLLAPSE = '[data-lte-toggle="card-collapse"]'
  31. const SELECTOR_DATA_MAXIMIZE = '[data-lte-toggle="card-maximize"]'
  32. const SELECTOR_CARD = `.${CLASS_NAME_CARD}`
  33. const SELECTOR_CARD_HEADER = '.card-header'
  34. const SELECTOR_CARD_BODY = '.card-body'
  35. const SELECTOR_CARD_FOOTER = '.card-footer'
  36. const Default = {
  37. animationSpeed: 500,
  38. collapseTrigger: SELECTOR_DATA_COLLAPSE,
  39. removeTrigger: SELECTOR_DATA_REMOVE,
  40. maximizeTrigger: SELECTOR_DATA_MAXIMIZE,
  41. collapseIcon: 'fa-minus',
  42. expandIcon: 'fa-plus',
  43. maximizeIcon: 'fa-expand',
  44. minimizeIcon: 'fa-compress'
  45. }
  46. type Config = {
  47. animationSpeed: number;
  48. collapseTrigger: string;
  49. removeTrigger: string;
  50. maximizeTrigger: string;
  51. collapseIcon: string;
  52. expandIcon: string;
  53. maximizeIcon: string;
  54. minimizeIcon: string;
  55. }
  56. class CardWidget {
  57. _element: HTMLElement
  58. _parent: HTMLElement | undefined
  59. _config: Config
  60. constructor(element: HTMLElement, config: Config) {
  61. this._element = element
  62. this._parent = element.closest(SELECTOR_CARD) as HTMLElement | undefined
  63. if (element.classList.contains(CLASS_NAME_CARD)) {
  64. this._parent = element
  65. }
  66. this._config = { ...Default, ...config }
  67. }
  68. collapse() {
  69. const event = new Event(EVENT_COLLAPSED)
  70. if (this._parent) {
  71. this._parent.classList.add(CLASS_NAME_COLLAPSING)
  72. const elm = this._parent?.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`)
  73. elm.forEach(el => {
  74. if (el instanceof HTMLElement) {
  75. slideUp(el, this._config.animationSpeed)
  76. }
  77. })
  78. setTimeout(() => {
  79. if (this._parent) {
  80. this._parent.classList.add(CLASS_NAME_COLLAPSED)
  81. this._parent.classList.remove(CLASS_NAME_COLLAPSING)
  82. }
  83. }, this._config.animationSpeed)
  84. }
  85. const icon = this._parent?.querySelector(`${SELECTOR_CARD_HEADER} ${this._config.collapseTrigger} .${this._config.collapseIcon}`)
  86. if (icon) {
  87. icon.classList.remove(this._config.collapseIcon)
  88. icon.classList.add(this._config.expandIcon)
  89. }
  90. this._element?.dispatchEvent(event)
  91. }
  92. expand() {
  93. const event = new Event(EVENT_EXPANDED)
  94. if (this._parent) {
  95. this._parent.classList.add(CLASS_NAME_EXPANDING)
  96. const elm = this._parent?.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`)
  97. elm.forEach(el => {
  98. if (el instanceof HTMLElement) {
  99. slideDown(el, this._config.animationSpeed)
  100. }
  101. })
  102. setTimeout(() => {
  103. if (this._parent) {
  104. this._parent.classList.remove(CLASS_NAME_COLLAPSED)
  105. this._parent.classList.remove(CLASS_NAME_EXPANDING)
  106. }
  107. }, this._config.animationSpeed)
  108. }
  109. const icon = this._parent?.querySelector(`${SELECTOR_CARD_HEADER} ${this._config.collapseTrigger} .${this._config.expandIcon}`)
  110. if (icon) {
  111. icon.classList.add(this._config.collapseIcon)
  112. icon.classList.remove(this._config.expandIcon)
  113. }
  114. this._element?.dispatchEvent(event)
  115. }
  116. remove() {
  117. const event = new Event(EVENT_REMOVE)
  118. if (this._parent) {
  119. slideUp(this._parent, this._config.animationSpeed)
  120. }
  121. this._element?.dispatchEvent(event)
  122. }
  123. toggle() {
  124. if (this._parent?.classList.contains(CLASS_NAME_COLLAPSED)) {
  125. this.expand()
  126. return
  127. }
  128. this.collapse()
  129. }
  130. maximize() {
  131. const event = new Event(EVENT_MAXIMIZED)
  132. if (this._parent) {
  133. const maxElm = this._parent.querySelector(`${this._config.maximizeTrigger} .${this._config.maximizeIcon}`)
  134. if (maxElm) {
  135. maxElm.classList.add(this._config.minimizeIcon)
  136. maxElm.classList.remove(this._config.maximizeIcon)
  137. }
  138. this._parent.style.height = `${this._parent.scrollHeight}px`
  139. this._parent.style.width = `${this._parent.scrollWidth}px`
  140. this._parent.style.transition = 'all .15s'
  141. setTimeout(() => {
  142. const htmlTag = document.querySelector('html')
  143. if (htmlTag) {
  144. htmlTag.classList.add(CLASS_NAME_MAXIMIZED)
  145. }
  146. if (this._parent) {
  147. this._parent.classList.add(CLASS_NAME_MAXIMIZED)
  148. if (this._parent.classList.contains(CLASS_NAME_COLLAPSED)) {
  149. this._parent.classList.add(CLASS_NAME_WAS_COLLAPSED)
  150. }
  151. }
  152. }, 150)
  153. }
  154. this._element?.dispatchEvent(event)
  155. }
  156. minimize() {
  157. const event = new Event(EVENT_MINIMIZED)
  158. if (this._parent) {
  159. const minElm = this._parent.querySelector(`${this._config.maximizeTrigger} .${this._config.minimizeIcon}`)
  160. if (minElm) {
  161. minElm.classList.add(this._config.maximizeIcon)
  162. minElm.classList.remove(this._config.minimizeIcon)
  163. }
  164. this._parent.style.cssText = `height: ${this._parent.style.height} !important; width: ${this._parent.style.width} !important; transition: all .15s;`
  165. setTimeout(() => {
  166. const htmlTag = document.querySelector('html')
  167. if (htmlTag) {
  168. htmlTag.classList.remove(CLASS_NAME_MAXIMIZED)
  169. }
  170. if (this._parent) {
  171. this._parent.classList.remove(CLASS_NAME_MAXIMIZED)
  172. if (this._parent?.classList.contains(CLASS_NAME_WAS_COLLAPSED)) {
  173. this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED)
  174. }
  175. }
  176. }, 10)
  177. }
  178. this._element?.dispatchEvent(event)
  179. }
  180. toggleMaximize() {
  181. if (this._parent?.classList.contains(CLASS_NAME_MAXIMIZED)) {
  182. this.minimize()
  183. return
  184. }
  185. this.maximize()
  186. }
  187. }
  188. /**
  189. *
  190. * Data Api implementation
  191. * ====================================================
  192. */
  193. domReady(() => {
  194. const collapseBtn = document.querySelectorAll(SELECTOR_DATA_COLLAPSE)
  195. collapseBtn.forEach(btn => {
  196. btn.addEventListener('click', event => {
  197. event.preventDefault()
  198. const target = event.target as HTMLElement
  199. const data = new CardWidget(target, Default)
  200. data.toggle()
  201. })
  202. })
  203. const removeBtn = document.querySelectorAll(SELECTOR_DATA_REMOVE)
  204. removeBtn.forEach(btn => {
  205. btn.addEventListener('click', event => {
  206. event.preventDefault()
  207. const target = event.target as HTMLElement
  208. const data = new CardWidget(target, Default)
  209. data.remove()
  210. })
  211. })
  212. const maxBtn = document.querySelectorAll(SELECTOR_DATA_MAXIMIZE)
  213. maxBtn.forEach(btn => {
  214. btn.addEventListener('click', event => {
  215. event.preventDefault()
  216. const target = event.target as HTMLElement
  217. const data = new CardWidget(target, Default)
  218. data.toggleMaximize()
  219. })
  220. })
  221. })
  222. export default CardWidget