Guest User

Untitled

a guest
Dec 18th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.18 KB | None | 0 0
  1. <script>
  2. export default {
  3. props: {
  4. open: {
  5. type: Boolean,
  6. required: false,
  7. default: false
  8. },
  9. },
  10.  
  11. data() {
  12. return {
  13. identifier: null,
  14. level: null,
  15. title: null,
  16. content: [],
  17. expanded: this.open
  18. }
  19. },
  20.  
  21. watch: {
  22. expanded: function (value) {
  23.  
  24. // Update the hash if the collapsible section's
  25. // heading has an `id` and we are opening, not closing
  26. if (this.identifier && value) {
  27. history.pushState(null, null, '#' + this.identifier);
  28. }
  29.  
  30. this.$emit('expanded', value)
  31. }
  32. },
  33.  
  34. created() {
  35. let nodes = this.$slots.default
  36.  
  37. // The first element MUST a heading with appropriate level, otherwise warn the user.
  38. if (! this.checkHeading(nodes[0])) {
  39. this.warn()
  40. }
  41.  
  42. // Extract heading level.
  43. this.level = this.getHeadingLevel(nodes[0])
  44.  
  45. // Extract title
  46. this.title = this.getTitle(nodes[0])
  47.  
  48. // Extract the heading identifier
  49. this.identifier = this.getHeadingIdentifier(nodes[0])
  50.  
  51. // Get contents except heading
  52. for (let i = 1; i < nodes.length; i++) {
  53. if (! this.checkHeading(nodes[i]) && undefined !== nodes[i].tag) {
  54. this.content.push(nodes[i])
  55. }
  56. }
  57. },
  58.  
  59. mounted() {
  60.  
  61. // Defines if section MUST expanded and focused
  62. this.mustLoadExpanded()
  63. },
  64.  
  65. render: function (createElement) {
  66.  
  67. // Render template with data
  68. return createElement('div', {attrs: {role: 'region'}, class: 'toggle-section'}, [
  69. createElement('h2', {attrs: {id: this.identifier, 'aria-level': this.level}}, [
  70. createElement('button', {ref: this.identifier + '-button', attrs: {'aria-expanded': this.expanded.toString()}, on: {click: this.toggle}}, [
  71. this.title,
  72. createElement('svg', {attrs: {'aria-hidden': 'true', focusable: 'false', viewBox: '0 0 10 10'}}, [
  73. createElement('rect', {attrs: {height: 8, width: 1, y: 1, x: 4.5}, class: 'vert'}),
  74. createElement('rect', {attrs: {height: 1, width: 8, y: 4.5, x: 1}}),
  75. ])
  76. ])
  77. ]),
  78. createElement('div', {class: 'content ' + this.classExpanded}, this.content)
  79. ]);
  80. },
  81.  
  82. computed: {
  83.  
  84. // Defines the class to show or not the content block
  85. classExpanded: function () {
  86. return this.expanded ? '' : 'hidden'
  87. }
  88. },
  89.  
  90. methods: {
  91.  
  92. /**
  93. * @throws Exception
  94. */
  95. warn() {
  96. console.warn('The first element inside each <toggle-section> should be a heading of an appropriate level.')
  97. },
  98.  
  99. /**
  100. * @param node Vnode
  101. * @returns Boolean
  102. */
  103. checkHeading(node) {
  104. return /h[1-6]/i.test(node.tag)
  105. },
  106.  
  107. /**
  108. * @param node Vnode
  109. * @returns Number
  110. */
  111. getHeadingLevel(node) {
  112. return parseInt(node.tag.substr(1))
  113. },
  114.  
  115. /**
  116. * @param node Vnode
  117. * @returns String
  118. */
  119. getTitle(node) {
  120. return node.children[0].text
  121. },
  122.  
  123. /**
  124. * @param node Vnode
  125. * @returns String
  126. */
  127. getHeadingIdentifier(node) {
  128. return undefined !== node.data ? node.data.attrs.id : this.kebabCase(this.title)
  129. },
  130.  
  131. /**
  132. * @param string String
  133. * @returns String
  134. */
  135. kebabCase(string) {
  136. return string.toLowerCase().replace(/\W+/g, '-').replace(/(^-|-$)/g, '')
  137. },
  138.  
  139. /**
  140. * Expand or collapse the section
  141. */
  142. toggle() {
  143. this.expanded = !this.expanded
  144. },
  145.  
  146. /**
  147. * Defines if the section must expanded and focused
  148. */
  149. mustLoadExpanded() {
  150. if (window.location.hash.substr(1) === this.identifier) {
  151. this.expanded = true
  152. this.$refs[this.identifier + '-button'].focus()
  153. }
  154. }
  155. }
  156. }
  157. </script>
  158.  
  159. <style>
  160. .toggle-section {
  161. padding: 0.5rem 0;
  162. }
  163.  
  164. h2 button {
  165. all: inherit;
  166. box-sizing: border-box;
  167. display: flex;
  168. justify-content: space-between;
  169. align-items: center;
  170. width: 100%;
  171. padding: 0.25rem;
  172. }
  173.  
  174. button svg {
  175. height: 1rem;
  176. margin-left: 1rem;
  177. }
  178.  
  179. .hidden, [aria-expanded="true"] .vert {
  180. display: none;
  181. }
  182.  
  183. [aria-expanded] rect {
  184. fill: currentColor;
  185. }
  186. </style>
Add Comment
Please, Sign In to add comment