A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/bootstrap-vue/bootstrap-vue/commit/3f0d46a below:

delegate row event handlers to the tbody… · bootstrap-vue/bootstrap-vue@3f0d46a · GitHub

1 +

import KeyCodes from '../../../utils/key-codes'

2 +

import { arrayIncludes } from '../../../utils/array'

3 +

import { closest, isElement } from '../../../utils/dom'

1 4

import { props as tbodyProps, BTbody } from '../tbody'

5 +

import filterEvent from './filter-event'

6 +

import textSelectionActive from './text-selection-active'

2 7

import tbodyRowMixin from './mixin-tbody-row'

3 8 4 9

const props = {

10 +

...tbodyProps,

5 11

tbodyClass: {

6 12

type: [String, Array, Object]

7 13

// default: undefined

8 -

},

9 -

...tbodyProps

14 +

}

10 15

}

11 16 12 17

export default {

13 18

mixins: [tbodyRowMixin],

14 19

props,

15 20

methods: {

21 +

// Helper methods

22 +

getTbodyTrs() {

23 +

// Returns all the item TR elements (excludes detail and spacer rows)

24 +

// `this.$refs.itemRows` is an array of item TR components/elements

25 +

// Rows should all be B-TR components, but we map to TR elements

26 +

// TODO: This may take time for tables many rows, so we may want to cache

27 +

// the result of this during each render cycle on a non-reactive

28 +

// property. We clear out the cache as each render starts, and

29 +

// populate it on first access of this method if null

30 +

return (this.$refs.itemRows || []).map(tr => tr.$el || tr)

31 +

},

32 +

getTbodyTrIndex(el) {

33 +

// Returns index of a particular TBODY item TR

34 +

// We set `true` on closest to include self in result

35 +

/* istanbul ignore next: should not normally happen */

36 +

if (!isElement(el)) {

37 +

return -1

38 +

}

39 +

const tr = el.tagName === 'TR' ? el : closest('tr', el, true)

40 +

return tr ? this.getTbodyTrs().indexOf(tr) : -1

41 +

},

42 +

emitTbodyRowEvent(type, evt) {

43 +

// Emits a row event, with the item object, row index and original event

44 +

if (type && evt && evt.target) {

45 +

const rowIndex = this.getTbodyTrIndex(evt.target)

46 +

if (rowIndex > -1) {

47 +

// The array of TRs correlate to the `computedItems` array

48 +

const item = this.computedItems[rowIndex]

49 +

this.$emit(type, item, rowIndex, evt)

50 +

}

51 +

}

52 +

},

53 +

tbodyRowEvtStopped(evt) {

54 +

return this.stopIfBusy && this.stopIfBusy(evt)

55 +

},

56 +

// Delegated row event handlers

57 +

onTbodyRowKeydown(evt) {

58 +

// Keyboard navigation and row click emulation

59 +

const target = evt.target

60 +

if (

61 +

this.tbodyRowEvtStopped(evt) ||

62 +

target.tagName !== 'TR' ||

63 +

target !== document.activeElement ||

64 +

target.tabIndex !== 0

65 +

) {

66 +

// Early exit if not an item row TR

67 +

return

68 +

}

69 +

const keyCode = evt.keyCode

70 +

if (arrayIncludes([KeyCodes.ENTER, KeyCodes.SPACE], keyCode)) {

71 +

// Emulated click for keyboard users, transfer to click handler

72 +

evt.stopPropagation()

73 +

evt.preventDefault()

74 +

this.onTBodyRowClicked(evt)

75 +

} else if (

76 +

arrayIncludes([KeyCodes.UP, KeyCodes.DOWN, KeyCodes.HOME, KeyCodes.END], keyCode)

77 +

) {

78 +

// Keyboard navigation

79 +

const rowIndex = this.getTbodyTrIndex(target)

80 +

if (rowIndex > -1) {

81 +

evt.stopPropagation()

82 +

evt.preventDefault()

83 +

const trs = this.getTbodyTrs()

84 +

const shift = evt.shiftKey

85 +

if (keyCode === KeyCodes.HOME || (shift && keyCode === KeyCodes.UP)) {

86 +

// Focus first row

87 +

trs[0].focus()

88 +

} else if (keyCode === KeyCodes.END || (shift && keyCode === KeyCodes.DOWN)) {

89 +

// Focus last row

90 +

trs[trs.length - 1].focus()

91 +

} else if (keyCode === KeyCodes.UP && rowIndex > 0) {

92 +

// Focus previous row

93 +

trs[rowIndex - 1].focus()

94 +

} else if (keyCode === KeyCodes.DOWN && rowIndex < trs.length - 1) {

95 +

// Focus next row

96 +

trs[rowIndex + 1].focus()

97 +

}

98 +

}

99 +

}

100 +

},

101 +

onTBodyRowClicked(evt) {

102 +

if (this.tbodyRowEvtStopped(evt)) {

103 +

// If table is busy, then don't propagate

104 +

return

105 +

} else if (filterEvent(evt) || textSelectionActive(this.$el)) {

106 +

// Clicked on a non-disabled control so ignore

107 +

// Or user is selecting text, so ignore

108 +

return

109 +

}

110 +

this.emitTbodyRowEvent('row-clicked', evt)

111 +

},

112 +

onTbodyRowMiddleMouseRowClicked(evt) {

113 +

if (!this.tbodyRowEvtStopped(evt) && evt.which === 2) {

114 +

this.emitTbodyRowEvent('row-middle-clicked', evt)

115 +

}

116 +

},

117 +

onTbodyRowContextmenu(evt) {

118 +

if (!this.tbodyRowEvtStopped(evt)) {

119 +

this.emitTbodyRowEvent('row-contextmenu', evt)

120 +

}

121 +

},

122 +

onTbodyRowDblClicked(evt) {

123 +

if (!this.tbodyRowEvtStopped(evt) && !filterEvent(evt)) {

124 +

this.emitTbodyRowEvent('row-dblclicked', evt)

125 +

}

126 +

},

127 +

// Note: Row hover handlers are handled by the tbody-row mixin

128 +

// As mouseenter/mouseleave events do not bubble

129 +

//

130 +

// Render Helper

16 131

renderTbody() {

17 132

// Render the tbody element and children

18 133

const items = this.computedItems

19 134

// Shortcut to `createElement` (could use `this._c()` instead)

20 135

const h = this.$createElement

136 +

const hasRowClickHandler = this.$listeners['row-clicked'] || this.isSelectable

21 137 22 138

// Prepare the tbody rows

23 139

const $rows = []

@@ -30,10 +146,10 @@ export default {

30 146

} else {

31 147

// Table isn't busy, or we don't have a busy slot

32 148 33 -

// Create a slot cache for improved performace when looking up cell slot names.

34 -

// Values will be keyed by the field's `key` and will store the slot's name.

35 -

// Slots could be dynamic (i.e. `v-if`), so we must compute on each render.

36 -

// Used by tbodyRow mixin render helper.

149 +

// Create a slot cache for improved performance when looking up cell slot names

150 +

// Values will be keyed by the field's `key` and will store the slot's name

151 +

// Slots could be dynamic (i.e. `v-if`), so we must compute on each render

152 +

// Used by tbody-row mixin render helper

37 153

const cache = {}

38 154

const defaultSlotName = this.hasNormalizedSlot('cell()') ? 'cell()' : null

39 155

this.computedFields.forEach(field => {

@@ -46,35 +162,57 @@ export default {

46 162

? lowerName

47 163

: defaultSlotName

48 164

})

49 -

// Created as a non-reactive property so to not trigger component updates.

50 -

// Must be a fresh object each render.

165 +

// Created as a non-reactive property so to not trigger component updates

166 +

// Must be a fresh object each render

51 167

this.$_bodyFieldSlotNameCache = cache

52 168 53 -

// Add static Top Row slot (hidden in visibly stacked mode as we can't control data-label attr)

169 +

// Add static top row slot (hidden in visibly stacked mode

170 +

// as we can't control `data-label` attr)

54 171

$rows.push(this.renderTopRow ? this.renderTopRow() : h())

55 172 56 -

// render the rows

173 +

// Render the rows

57 174

items.forEach((item, rowIndex) => {

58 175

// Render the individual item row (rows if details slot)

59 176

$rows.push(this.renderTbodyRow(item, rowIndex))

60 177

})

61 178 62 -

// Empty Items / Empty Filtered Row slot (only shows if items.length < 1)

179 +

// Empty items / empty filtered row slot (only shows if `items.length < 1`)

63 180

$rows.push(this.renderEmpty ? this.renderEmpty() : h())

64 181 65 -

// Static bottom row slot (hidden in visibly stacked mode as we can't control data-label attr)

182 +

// Static bottom row slot (hidden in visibly stacked mode

183 +

// as we can't control `data-label` attr)

66 184

$rows.push(this.renderBottomRow ? this.renderBottomRow() : h())

67 185

}

68 186 187 +

const handlers = {

188 +

// TODO: We may want to to only instantiate these handlers

189 +

// if there is an event listener registered

190 +

auxclick: this.onTbodyRowMiddleMouseRowClicked,

191 +

// TODO: Perhaps we do want to automatically prevent the

192 +

// default context menu from showing if there is

193 +

// a `row-contextmenu` listener registered.

194 +

contextmenu: this.onTbodyRowContextmenu,

195 +

// The following event(s) is not considered A11Y friendly

196 +

dblclick: this.onTbodyRowDblClicked

197 +

// hover events (mouseenter/mouseleave) ad handled by tbody-row mixin

198 +

}

199 +

if (hasRowClickHandler) {

200 +

handlers.click = this.onTBodyRowClicked

201 +

handlers.keydown = this.onTbodyRowKeydown

202 +

}

69 203

// Assemble rows into the tbody

70 204

const $tbody = h(

71 205

BTbody,

72 206

{

207 +

ref: 'tbody',

73 208

class: this.tbodyClass || null,

74 209

props: {

75 210

tbodyTransitionProps: this.tbodyTransitionProps,

76 211

tbodyTransitionHandlers: this.tbodyTransitionHandlers

77 -

}

212 +

},

213 +

// BTbody transfers all native event listeners to the root element

214 +

// TODO: Only set the handlers if the table is not busy

215 +

on: handlers

78 216

},

79 217

$rows

80 218

)


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4