1/* globals sessionStorage, localStorage, window, moment, getComputedStyle, document */ 2 3 Vue.filter('size', function(bytes) { 4 if (bytes < 0) return '' 5 var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] 6 for (var i = 0; bytes > 1024; i++) bytes /= 1024 7 return Number.parseFloat(bytes).toFixed(bytes < 10 ? 1 : 0) + ' ' + units[i] 8 }) 9 10 var breakpoints = ['', 'sm-', 'md-', 'lg-', 'xl-'] 11 const Sidebars = function(resolve) { 12 axios.get('webjars/common-frontend/layout/sidebars.html').then(function(html) { 13 resolve({ 14 template: html, 15 props: { leftOpen: Boolean, rightOpen: Boolean, leftCaption: String, rightCaption: String, 16 leftSize: { type: Array, default: function() { return [12, 6, 4, 3, 3] } }, 17 rightSize: { type: Array, default: function() { return [12, 6, 4, 3, 3] } } 18 }, 19 computed: { 20 middleClasses: function() { 21 if (this.leftOpen) { 22 var middleSize = this.leftSize.map(function(val, i) { return 12 - val - (this.rightOpen ? this.rightSize[i] : 0) }.bind(this)) 23 var offset = this.leftSize.map(function(size, i) { return 'offset-' + breakpoints[i] + size }).join(' ') 24 return this.colClasses(middleSize) + ' ' + offset 25 } else if (this.rightOpen) return this.colClasses(this.rightSize.map(function(val) { return 12 - val })) 26 else return 'col-12' 27 } 28 }, 29 methods: { // https://help.optimizely.com/Build_Campaigns_and_Experiments/Use_screen_measurements_to_design_for_responsive_breakpoints 30 showMain: function(keepRight) { 31 if (window.innerWidth < 576) { // sm breakpoint 32 this.$emit('update:leftOpen', false) 33 this.$emit('update:rightOpen', false) 34 } else if (window.innerWidth < 768) { // md breakpoint 35 if (this.rightOpen && keepRight) this.$emit('update:leftOpen', false) 36 else if (this.leftOpen && !keepRight) this.$emit('update:rightOpen', false) 37 } 38 }, 39 showRight: function() { 40 this.$emit('update:rightOpen', true) 41 if (window.innerWidth < 768) this.$emit('update:leftOpen', false) 42 }, 43 colClasses: function(sizes) { 44 return sizes.map(function(size, i) { 45 if (!size) return 'd-none' 46 else if (size && i > 0 && !sizes[i-1]) return 'd-' + breakpoints[i] + 'block col-' + breakpoints[i] + size 47 else return 'col-' + breakpoints[i] + size 48 }).join(' ') 49 } 50 } 51 }) 52 }) 53 } 54 55 const Sidebar = { // https://getbootstrap.com/docs/5.2/examples/sidebars/# 56 template: '<div class="d-flex flex-nowrap">\ 57 <div class="d-flex flex-column border border-top-0"> <slot name="left"></slot> </div>\ 58 <div class="h-100" style="width: calc(100% - 48px)"> <slot></slot> </div>\ 59 </div>' 60 } 61 62 const SidebarItem = { 63 template: '<b-list-group-item class="border-0 py-1 text-center" action :to="to" @click="$emit(\'click\', $event)"\ 64 style="padding-left: 12px; padding-right: 12px">\ 65 <div :class="iconClass" :title="tooltip" v-b-popover.hover.right></div>\ 66 </b-list-group-item>', 67 props: { iconClass: String, tooltip: String, to: String } 68 } 69 70 const SidebarDropright = { 71 template: '<b-dropdown dropright variant="light" toggle-class="border-0 shadow-none" no-caret>\ 72 <template #button-content> <span :class="iconClass"></span> </template>\ 73 <slot></slot>\ 74 </b-dropdown>', 75 props: { iconClass: String } 76 } 77 78 const CibHeader = function(resolve) { 79 axios.get('webjars/common-frontend/layout/cib-header.html').then(function(html) { 80 resolve({ 81 template: html, 82 inject: ['currentLanguage'], 83 props: { languages: Array, user: Object }, 84 methods: { 85 logout: function() { 86 sessionStorage.getItem('token') ? sessionStorage.removeItem('token') : localStorage.removeItem('token') 87 this.$emit('logout') 88 } 89 } 90 }) 91 }) 92 } 93 94 const CibTable = function(resolve) { 95 axios.get('webjars/common-frontend/layout/cib-table.html').then(function(html) { 96 resolve({ 97 template: html, 98 props: { rows: Array, columns: Array, sizes: Array, prefix: String, keyMember: String, start: Number, limit: Number, tooltips: Array },
99 data: function() { return { sortBy: null, desc: 1, selected: null } }, 100 computed: { 101 sorted: function() { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort 102 var vm = this 103 var res = !this.sortBy ? this.rows : this.rows.slice(0).sort(function(one, two) { // https://davidwalsh.name/javascript-clone-array 104 var val1 = vm.access(one, vm.sortBy) 105 var val2 = vm.access(two, vm.sortBy) 106 return vm.desc * specialCompare(val1, val2) 107 }) 108 return res.slice(this.start || 0, this.limit ? (this.start || 0) + this.limit : undefined) 109 } 110 }, 111 methods: { 112 access: function(row, col) { 113 var val = row 114 col.split('.').forEach(function(field) { val = val[field] }) 115 return val 116 }, 117 isMoment: function(row, col) { 118 var res = this.access(row, col) 119 return res && res.fromNow 120 }, 121 isDate: function(row, col) { return this.access(row, col) instanceof Date } 122 } 123 }) 124 }) 125 } 126 127 const CibTable2 = { 128 functional: true, 129 render: function(create, vm) { 130 var scopedSlots = vm.scopedSlots 131 var props = vm.props
132 var $t = vm.parent.$t.bind(vm.parent) 133 134 props.fields = props.fields.map(function(col) { 135 if (typeof col === 'string') col = { key: col } 136 col.label = col.label != null ? col.label : col.key 137 col.class = col.class || 'flex-fill' 138 col.tdAttr = col.tdAttr || { style: 'display: flex' } 139 col.tdClass = (col.tdClass || 'py-1') + ' align-items-center' 140 col.thClass = (col.thClass || '') + ' text-secondary align-items-center', 141 col.thStyle = { display: 'flex' } 142 col.sortable = col.sortable != null ? col.sortable : true 143 if (typeof col.formatter === 'string') { 144 var prefix = col.formatter 145 col.formatter = function(value) { return $t(prefix + value) } 146 } 147 if (col.sortable && col.formatter && col.sortByFormatted == null) col.sortByFormatted = true 148 return col 149 }) 150 props['sort-direction'] = 'desc' 151 props.selectable = (props.selectable != null ? props.selectable : true) 152 props['select-mode'] = (props['select-mode'] != null ? props['select-mode'] : 'single') 153 props.hover = (props.hover != null ? props.hover : true) 154 props['sort-icon-left'] = true 155 props.fixed= true 156 props.striped = true 157 props.hover = true 158 props['tbody-tr-class'] = 'row' 159 props['thead-tr-class'] = 'row' 160 props['details-td-class'] = 'bg-white' 161 props['sort-compare'] = props['sort-compare'] || function(one, two, key, desc, formatter) { 162 var val1 = formatter ? formatter(one[key], key, one) : one[key] 163 var val2 = formatter ? formatter(two[key], key, two) : two[key] 164 return specialCompare(val1, val2) 165 } 166 167 scopedSlots['cell()'] = scopedSlots['cell()'] || function(row) { 168 var value = row.value instanceof moment ? row.value.fromNow() : row.value 169 var title = row.value instanceof moment ? row.value.format('L LTS') : row.value 170 return create('div', { 171 class: 'text-truncate', 172 attrs: { 173 title: title 174 } 175 }, value) 176 } 177 178 scopedSlots['head()'] = scopedSlots['head()'] || function(row) { if (row.label) return $t(props.prefix + row.label) } 179 return create('b-table', { 180 props: props, 181 class: 'container-fluid', 182 on: { 183 'row-hovered': vm.listeners.mouseenter || emptyFunction, 184 'row-unhovered': vm.listeners.mouseleave || emptyFunction, 185 'row-clicked': vm.listeners.click || emptyFunction, 186 'row-contextmenu': vm.listeners.contextmenu || emptyFunction, 187 'row-selected': vm.listeners.select || emptyFunction 188 }, 189 slots: vm.slots, 190 scopedSlots: scopedSlots 191 }) 192 193 function emptyFunction() {} 194 } 195 } 196 197 const CibTable2Filter = { 198 functional: true, 199 props: { table: Object, filterKeys: Array, placeholder: String, tableFilters: Object }, 200 render: function(create, vm) { 201 var elements = [] 202 var inputs = [] 203 vm.props.filterKeys.forEach(function(key) { 204 var defaultInput = [create('b-form-input', { 205 props: { 206 value: vm.props.tableFilters[key], 207 debounce: 300, 208 placeholder: vm.props.placeholder 209 }, 210 on: { 211 update: function(e) { 212 vm.props.tableFilters[key] = e 213 } 214 }, 215 class: 'form-control', 216 style: 'max-width: 300px' 217 })] 218 var inputElement = vm.scopedSlots[key] ? 219 vm.scopedSlots[key]() : defaultInput 220 inputs.push({ input: inputElement, key: key }) 221 }) 222 vm.props.table.fields.forEach(function(field) { 223 var dataInput = inputs.find(function(input) { 224 return input.key === field.key 225 }) 226 elements.push(create('b-td', { 227 class: field.class + ' ' + field.tdClass, 228 style: { display: 'flex' } 229 }, dataInput ? dataInput.input : undefined)) 230 }) 231 return elements 232 } 233 } 234 235 const ResizeHead = { 236 template: '<thead ref="head"> <slot></slot> </thead>', 237 props: { fixedTable: Boolean, sticky: Boolean }, 238 data: function() { 239 return { 240 moving: false, 241 movingIndex: 0, 242 ths: null, 243 bars: null 244 } 245 }, 246 mounted: function() { 247 this.setResizing() 248 }, 249 methods: { 250 setResizing: function() { 251 //TODO Resize columns on table resize (e.g. window smaller/bigger, sidebar close) if not fixed 252 var table = this.$refs.head.parentElement 253 var thead = this.$refs.head 254 this.ths = thead.querySelectorAll('th') 255 var barHeight = thead.offsetHeight 256 var resizeContainer = this.getResizeContainer() 257 if (!resizeContainer) { 258 resizeContainer = document.createElement('div') 259 // table.style.position = 'relative' //TODO ? use unclear 260 resizeContainer.style.width = '0px' 261 if (this.sticky) { 262 resizeContainer.style.zIndex = 1021 //sticky-top from thead tr has 1020 263 resizeContainer.className = 'vue-columns-resizable sticky-top' 264 } else resizeContainer.className = 'vue-columns-resizable position-relative' 265 table.parentElement.insertBefore(resizeContainer, table) 266 } else resizeContainer.innerHTML = '' 267 268 this.ths.forEach((th, index) => { 269 var nextTh = this.ths[index + 1] 270 th.style.width = th.offsetWidth + 'px' 271 if (index + 1 >= this.ths.length && !this.fixedTable) return 272 var bar = createBar(nextTh, th) 273 bar.addEventListener('mousedown', startMoving.bind(this, index)); 274 bar.addEventListener('dblclick', resetColumn.bind(this, index)) 275 276 resizeContainer.appendChild(bar) 277 }) 278 279 this.bars = resizeContainer.querySelectorAll('.columns-resize-bar') 280 281 282 document.addEventListener('mouseup', this.endResizing) 283 //With a fixed table you would not be able to make the last column bigger as you would always leave the table with the mouse 284 document.addEventListener('mousemove', this.handleResize) 285 286 //Create a div between the table headers to drag 287 function createBar(nextTh, currentTh) { 288 var bar = document.createElement('div') 289 bar.style.position = 'absolute' 290 setBarPosition(currentTh, bar, nextTh) 291 bar.style.top = 0 292 bar.style.height = barHeight + 'px' 293 bar.style.width = '8px' 294 bar.style.zIndex = 1 295 bar.style.cursor = 'col-resize' 296 bar.className = 'columns-resize-bar' 297 return bar 298 } 299 var vm = this 300 //Reset to needed space 301 function resetColumn(index) { 302 var th = vm.ths[index] 303 var nextTh = vm.ths[index + 1] 304 var bar = vm.bars[index] 305 th.style.width = 'min-content' 306 th.style.width = th.offsetWidth + 'px' 307 bar.style.left = th.offsetLeft 308 setBarPosition(th, bar, nextTh) 309 vm.sendCurrentSizes() 310 } 311 //Resize columns on dragging 312 function startMoving(index) { 313 vm.moving = true 314 vm.movingIndex = index 315 // document.body.style.cursor = 'col-resize' //TODO ? with this the cursor changes even after dragging vertically (mouse leaves the bar div) 316 // document.body.style.userSelect = 'none' 317 } 318 }, 319 endResizing: function() { 320 if (!this.moving) return 321 this.moving = false 322 document.body.style.cursor = '' //TODO ? 323// document.body.style.userSelect = ''
324 this.bars.forEach((bar, index) => { 325 var th = this.ths[index] 326 var nextTh = this.ths[index + 1] 327 th.style.width = th.offsetWidth + 'px' 328 setBarPosition(th, bar, nextTh) 329 }) 330 this.sendCurrentSizes() 331 }, 332 sendCurrentSizes: function() { 333 this.$emit('resize', Array.prototype.map.call(this.ths, function(th) { return th.style.width })) 334 }, 335 handleResize: function(e) { 336 if (this.moving) { 337 var th = this.ths[this.movingIndex] 338 var nextTh = this.ths[this.movingIndex + 1] 339 var bar = this.bars[this.movingIndex] 340 th.style.width = cutPx(th.style.width) + e.movementX + 'px' 341 if (nextTh) { 342 if (!this.fixedTable) 343 nextTh.style.width = cutPx(nextTh.style.width) - e.movementX + 'px' 344 bar.style.left = nextTh.offsetLeft - 4 + 'px' 345 } else bar.style.left = th.offsetLeft + th.offsetWidth - 8 + 'px' 346 } 347 function cutPx(str) { return +str.replace('px', '') } 348 }, 349 getResizeContainer: function() { 350 return this.$refs.head.parentElement.parentElement.querySelector('.vue-columns-resizable') 351 }, 352 }, 353 beforeDestroy: function() { 354 var resize = this.getResizeContainer() 355 resize.parentElement.remove(resize) 356 document.removeEventListener('mousemove', this.handleResize) 357 document.removeEventListener('mouseup', this.endResizing) 358 } 359 } 360 function setBarPosition(currentTh, bar, nextTh) { 361 if (nextTh) 362 bar.style.left = nextTh.offsetLeft - 4 + 'px' 363 else bar.style.left = currentTh.offsetLeft + currentTh.offsetWidth - 8 + 'px' 364 } 365 366 const Tree = function(resolve) { 367 axios.get('webjars/common-frontend/layout/tree.html').then(function(html) { 368 resolve({ 369 template: html, 370 components: { TransitionCollapse }, 371 props: { nodes: Array, isLeaf: Function, path: { type: String, default: '' }, nodeKey: String, 372 parent: { type: Object, default: function() { 373 var vm = this 374 var obj = { get children() { return vm.nodes } } 375 obj[this.nodeKey] = 'ROOT' 376 return obj 377 } } }, 378 data: function() { 379 return { 380 state: { 381 open: this.parent[this.nodeKey] === 'ROOT' 382 }, 383 render: false 384 } 385 }, 386 methods: { 387 childsState: function(node) { 388 if(this.$refs['childFrom' + node[this.nodeKey]] && this.$refs['childFrom' + node[this.nodeKey]][0]) { 389 return this.$refs['childFrom' + node[this.nodeKey]][0].state 390 } 391 return { open: false } 392 }, 393 toggleFolder: function(node, newState) { 394 if(this.$refs['childFrom' + node[this.nodeKey]] && this.$refs['childFrom' + node[this.nodeKey]][0]) { 395 newState = newState != null ? newState : !this.$refs['childFrom' + node[this.nodeKey]][0].state.open 396 this.$refs['childFrom' + node[this.nodeKey]][0].state.open = newState 397 return this.$refs['childFrom' + node[this.nodeKey]][0] 398 } 399 return null 400 } 401 } 402 }) 403 }) 404 } 405 406 const TransitionCollapse = { 407 template: '<transition name="expand-custom" @enter="enter" @after-enter="afterEnter" @leave="leave"\ 408 enter-active-class="collapsing" leave-active-class="collapsing">\ 409 <slot></slot>\ 410 </transition>', 411 methods: { 412 afterEnter: function(element) { 413 element.style.height = 'auto' 414 }, 415 enter: function(element) { 416 var width = getComputedStyle(element).width 417 element.style.width = width; 418 element.style.position = 'absolute' 419 element.style.visibility = 'hidden' 420 element.style.height = 'auto' 421 var height = getComputedStyle(element).height 422 element.style.width = null 423 element.style.position = null 424 element.style.visibility = null 425 element.style.height = 0 426 // Force repaint to make sure the animation is triggered correctly. 427 getComputedStyle(element).height 428 element.style.height = height 429 }, 430 leave: function(element) { 431 //Set the height from 'auto' to pixel height and after to '0' to make the transition 432 var height = getComputedStyle(element).height 433 element.style.height = height 434 // Force repaint to make sure the animation is triggered correctly. 435 getComputedStyle(element).height 436 element.style.height = 0 437 } 438 } 439 } 440 441 function specialCompare(a, b) { 442 if (typeof a === 'string' && typeof b === 'string') { 443 a = a.toLowerCase().replace(/Ã/g, "s").replace(/ä/g, "a").replace(/ö/g, "o").replace(/ü/g, "u") 444 b = b.toLowerCase().replace(/Ã/g, "s").replace(/ä/g, "a").replace(/ö/g, "o").replace(/ü/g, "u") 445 } 446 return a < b ? -1 : a > b ? 1 : 0 447 } 448 449 export { Sidebars, Sidebar, SidebarItem, SidebarDropright, CibHeader, CibTable, CibTable2, CibTable2Filter, ResizeHead, Tree, TransitionCollapse }
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.