PageSourceSearch

https://www.doxisafe.com/webjars/common-frontend/layout/layout.js

js doxisafe.com collected 2026-10-09 04:45:10 UTC 17,137 bytes, 449 lines download raw bytes

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.