Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
EXSYS2021
da6
Hold Afstand
Commits
f39069af
Commit
f39069af
authored
May 06, 2021
by
Kent Nielsen
Browse files
Merge branch 'develop' into 'feature/mobile-layout'
# Conflicts: # website/studerende-dk/src/views/Home.vue
parents
d4030c31
848114c2
Pipeline
#52372
passed with stage
in 39 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
website/studerende-dk/src/components/blocks/ActiveCourses.vue
View file @
f39069af
<
template
>
<BlockTemplate
heading=
"Aktive kurser"
>
<BlockTemplate
heading=
"Aktive kurser"
:row=
"row"
:col=
"col"
>
<ul>
<li
v-for=
"(course, index) in courses"
:key=
"index"
><a
href=
"/about"
>
{{
course
}}
</a></li>
</ul>
...
...
@@ -9,6 +9,9 @@
<
script
>
export
default
{
name
:
'
ActiveCourses
'
,
props
:
[
'
row
'
,
'
col
'
],
data
()
{
return
{
courses
:
[
'
Calculus Beta
'
,
'
Databaser
'
,
'
etc.
'
]
...
...
website/studerende-dk/src/components/blocks/BlockTemplate.vue
View file @
f39069af
<
template
>
<div
class=
"block"
>
<div
class=
"heading"
>
<div
class=
"heading"
:draggable=
"dragEnabled.value"
@
dragstart=
"startDrag($event, row, col)"
@
dragend.prevent=
"stopDrag()"
>
<h2>
{{
heading
}}
</h2>
</div>
<div
class=
"content"
>
...
...
@@ -11,7 +11,9 @@
<
script
>
export
default
{
props
:
[
'
heading
'
]
props
:
[
'
heading
'
,
'
row
'
,
'
col
'
],
inject
:
[
'
dragEnabled
'
,
'
startDrag
'
,
'
stopDrag
'
]
}
</
script
>
...
...
@@ -30,6 +32,7 @@ export default {
.heading
{
color
:
$lightest-theme-color
;
background-color
:
$theme-color
;
cursor
:
move
;
h2
{
padding
:
10px
$padding
;
...
...
website/studerende-dk/src/components/blocks/Calendar.vue
View file @
f39069af
<
template
>
<div
id=
"calendar"
>
<table>
<thead>
<thead
:draggable=
"dragEnabled.value"
@
dragstart=
"startDrag($event, row, col)"
@
dragend.prevent=
"stopDrag()"
>
<!-- Generating first header of schema -->
<tr>
<th>
...
...
@@ -52,6 +52,11 @@
<
script
>
export
default
{
name
:
'
Cal
'
,
props
:
[
'
row
'
,
'
col
'
],
inject
:
[
'
dragEnabled
'
,
'
startDrag
'
,
'
stopDrag
'
],
data
()
{
return
{
// Currently showing schema data
...
...
@@ -185,6 +190,7 @@ export default {
border
:
0
;
padding
:
0
;
height
:
100%
;
cursor
:
move
;
tr
{
height
:
37px
;
...
...
website/studerende-dk/src/components/blocks/Deadlines.vue
View file @
f39069af
<
template
>
<BlockTemplate
heading=
"Deadlines"
>
<BlockTemplate
heading=
"Deadlines"
:row=
"row"
:col=
"col"
>
<ul>
<li
v-for=
"(deadline, index) in deadlines"
:key=
"index"
>
<span
class=
"course-name"
>
{{
deadline
.
course
}}
</span>
...
...
@@ -15,13 +15,28 @@
</
template
>
<
script
>
Date
.
prototype
.
addDays
=
function
(
days
)
{
const
date
=
new
Date
(
this
.
valueOf
());
date
.
setDate
(
date
.
getDate
()
+
days
);
return
date
;
}
Date
.
prototype
.
toMidnight
=
function
()
{
const
date
=
new
Date
(
this
.
valueOf
());
date
.
setHours
(
0
,
0
,
0
,
0
);
return
date
;
}
export
default
{
name
:
'
Deadlines
'
,
props
:
[
'
row
'
,
'
col
'
],
data
()
{
return
{
deadlines
:
[{
course
:
"
Calculus Beta
"
,
name
:
"
Aflevering 1
"
,
date
:
new
Date
()
},
{
course
:
"
Databaser
"
,
name
:
"
SQL
"
,
date
:
new
Date
(
"
10 Apr 2021
"
)
},
{
course
:
"
Numerisk Lineær Algebra
"
,
name
:
"
Python for dummies
"
,
date
:
new
Date
(
"
12 Apr 2021
"
)
}]
{
course
:
"
Databaser
"
,
name
:
"
SQL
"
,
date
:
new
Date
(
).
addDays
(
2
).
toMidnight
(
)
},
{
course
:
"
Numerisk Lineær Algebra
"
,
name
:
"
Python for dummies
"
,
date
:
new
Date
(
).
addDays
(
3
).
toMidnight
(
)
}]
}
}
}
...
...
website/studerende-dk/src/components/blocks/Feed.vue
View file @
f39069af
<
template
>
<BlockTemplate
heading=
"Feed"
>
<BlockTemplate
heading=
"Feed"
:row=
"row"
:col=
"col"
>
<ul>
<li
v-for=
"(message, index) in messages"
:key=
"index"
@
click=
"$router.push('/about')"
@
keypress.enter=
"$router.push('/about')"
tabindex=
0
>
<a
href=
"/about"
>
{{
message
.
course
}}
</a>
...
...
@@ -13,6 +13,9 @@
<
script
>
export
default
{
name
:
'
Feed
'
,
props
:
[
'
row
'
,
'
col
'
],
data
()
{
return
{
messages
:
[
...
...
website/studerende-dk/src/components/blocks/Mail.vue
View file @
f39069af
<
template
>
<BlockTemplate
heading=
"Post"
>
<BlockTemplate
heading=
"Post"
:row=
"row"
:col=
"col"
>
<ul>
<li
v-for=
"(mail, index) in mails"
:key=
"index"
>
<span
style=
"width: 50%;"
>
{{
mail
.
sender
}}
</span>
...
...
@@ -15,6 +15,9 @@
<
script
>
export
default
{
name
:
'
Mail
'
,
props
:
[
'
row
'
,
'
col
'
],
data
()
{
return
{
mails
:
[
...
...
website/studerende-dk/src/views/Home.vue
View file @
f39069af
<
template
>
<div
class=
"home"
>
<div
id=
"grid"
>
<div
@
mousedown=
"resizeVertical($event, rowIndex)"
class=
"row"
v-for=
"(rowBlock, rowIndex) in layout"
:key=
"rowIndex"
:style=
"
{ height: rowBlock.height + 'px' }">
<div
@
mousedown=
"resizeHorizontal($event, rowIndex, colIndex)"
class=
"col"
v-for=
"(colBlock, colIndex) in rowBlock.blocks"
:key=
"colIndex"
:style=
"
{ 'flex-grow': colBlock.width }">
<component
:is=
"colBlock.type"
></component>
<div
@
mousedown=
"resizeVertical($event, rowIndex)"
:id=
"rowIndex"
class=
"row"
:class=
"
{ drag: draggedBlock !== null }"
v-for="(rowBlock, rowIndex) in layout" :key="rowIndex" :style="{ height: rowBlock.height + 'px' }"
@dragover="dragHover($event, rowIndex)" @dragleave="hidePreview()" @drop="drop($event, rowIndex)">
<span
class=
"col-preview"
>
<component
:is=
"previewType"
></component>
</span>
<div
@
mousedown=
"resizeHorizontal($event, rowIndex, colIndex)"
:id=
"rowIndex+','+colIndex"
class=
"col"
v-show=
"!isDragged(rowIndex, colIndex)"
v-for=
"(colBlock, colIndex) in rowBlock.blocks"
:key=
"colIndex"
:style=
"
{ 'flex-grow': colBlock.width, 'order': colIndex }">
<component
:is=
"colBlock.type"
:row=
"rowIndex"
:col=
"colIndex"
></component>
</div>
</div>
<button
class=
"add-block"
@
click=
"addBlock()"
>
...
...
@@ -14,6 +20,7 @@
</
template
>
<
script
>
import
{
computed
}
from
'
vue
'
;
import
ActiveCourses
from
"
@/components/blocks/ActiveCourses
"
;
import
Deadlines
from
"
@/components/blocks/Deadlines
"
;
import
Feed
from
"
@/components/blocks/Feed
"
;
...
...
@@ -30,6 +37,9 @@ const sendServerRequest = (type, payload) => {
return
xhr
;
}
// Maximum number of blocks allowed in a row
const
maxBlocks
=
3
;
export
default
{
name
:
'
Home
'
,
...
...
@@ -52,7 +62,10 @@ export default {
mouseDragPos
:
{
x
:
0
,
y
:
0
},
verticalResizeObject
:
{
index
:
0
},
horizontalResizeObject
:
{
row
:
0
,
col
:
0
},
prevWinWidth
:
1000
prevWinWidth
:
1000
,
draggedBlock
:
null
,
activePreview
:
null
,
dragEnabled
:
true
}
},
...
...
@@ -102,13 +115,13 @@ export default {
this
.
layout
[
row
].
blocks
[
col
].
width
=
newFlexRight
;
},
resizeVerticalMouseMove
(
event
){
resizeVerticalMouseMove
(
event
)
{
const
deltaY
=
this
.
mouseDragPos
.
y
-
event
.
y
;
this
.
mouseDragPos
.
y
=
event
.
y
;
this
.
layout
[
this
.
verticalResizeObject
.
index
].
height
-=
deltaY
},
resizeHorizontal
(
event
,
row
,
col
){
resizeHorizontal
(
event
,
row
,
col
)
{
if
(
event
.
offsetX
<
0
){
this
.
mouseDragPos
.
x
=
event
.
x
;
this
.
horizontalResizeObject
.
row
=
row
;
...
...
@@ -116,24 +129,27 @@ export default {
document
.
addEventListener
(
"
mousemove
"
,
this
.
resizeHorizontalMouseMove
,
false
);
document
.
addEventListener
(
"
mouseup
"
,
this
.
eventRemover
,
false
);
document
.
getElementsByTagName
(
"
html
"
)[
0
].
classList
.
add
(
"
no-select
"
);
this
.
dragEnabled
=
false
;
}
},
resizeVertical
(
event
,
index
){
if
(
event
.
offsetY
>
this
.
layout
[
index
].
height
){
resizeVertical
(
event
,
index
)
{
if
(
event
.
offsetY
>
this
.
layout
[
index
].
height
)
{
this
.
mouseDragPos
.
y
=
event
.
y
;
this
.
verticalResizeObject
.
index
=
index
;
document
.
addEventListener
(
"
mousemove
"
,
this
.
resizeVerticalMouseMove
,
false
);
document
.
addEventListener
(
"
mouseup
"
,
this
.
eventRemover
,
false
);
document
.
getElementsByTagName
(
"
html
"
)[
0
].
classList
.
add
(
"
no-select
"
);
this
.
dragEnabled
=
false
;
}
},
eventRemover
(){
eventRemover
()
{
document
.
removeEventListener
(
"
mousemove
"
,
this
.
resizeHorizontalMouseMove
,
false
);
document
.
removeEventListener
(
"
mousemove
"
,
this
.
resizeVerticalMouseMove
,
false
);
document
.
removeEventListener
(
"
mouseup
"
,
this
.
eventRemover
,
false
);
document
.
getElementsByTagName
(
"
html
"
)[
0
].
classList
.
remove
(
"
no-select
"
);
this
.
dragEnabled
=
true
;
},
mobileLayoutResize
(){
...
...
@@ -172,6 +188,163 @@ export default {
this
[
side
].
splice
(
row
,
1
);
},
startDrag
(
event
,
row
,
col
)
{
event
.
dataTransfer
.
effectAllowed
=
'
move
'
;
const
colElement
=
document
.
getElementById
(
row
+
'
,
'
+
col
);
event
.
dataTransfer
.
setDragImage
(
colElement
,
colElement
.
offsetWidth
/
2
,
20
);
// Workaround for a bug in Chrome causing dragend
// to be fired immediately if the timeout is not used
setTimeout
(()
=>
{
this
.
draggedBlock
=
{
row
,
col
};
this
.
showDropPreview
(
row
,
col
);
},
10
);
},
stopDrag
()
{
this
.
draggedBlock
=
null
;
},
getDropPosition
(
event
,
row
)
{
// Copy blocks
const
blocks
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
layout
[
row
].
blocks
));
const
origRow
=
this
.
draggedBlock
.
row
;
const
origCol
=
this
.
draggedBlock
.
col
;
const
origBlock
=
this
.
layout
[
origRow
].
blocks
[
origCol
];
// Don't take into account the block we are dragging when calculating the preview
if
(
origRow
===
row
)
{
const
missingWidth
=
origBlock
.
width
/
(
blocks
.
length
-
1
);
blocks
.
splice
(
origCol
,
1
);
for
(
const
block
of
blocks
)
block
.
width
+=
missingWidth
;
}
// No drop position if row is full
if
(
blocks
.
length
===
maxBlocks
)
return
null
;
const
targetRow
=
document
.
getElementById
(
row
.
toString
());
const
rowWidth
=
targetRow
.
offsetWidth
;
const
x
=
event
.
x
-
targetRow
.
offsetLeft
;
let
position
=
blocks
.
length
;
let
cutoff
=
0
;
for
(
let
i
=
0
;
i
<
blocks
.
length
;
i
++
)
{
const
block
=
blocks
[
i
];
cutoff
+=
block
.
width
/
2
;
if
(
x
<=
rowWidth
*
cutoff
/
100
)
{
position
=
i
;
break
;
}
cutoff
+=
block
.
width
/
2
;
}
return
position
;
},
// Shows a preview upon dragging a block over a row
dragHover
(
event
,
row
)
{
event
.
dataTransfer
.
dropEffect
=
'
move
'
;
let
position
=
this
.
getDropPosition
(
event
,
row
);
// Don't show preview if row is full
if
(
position
===
null
)
return
;
this
.
showDropPreview
(
row
,
position
);
event
.
preventDefault
();
},
showDropPreview
(
row
,
position
)
{
if
(
this
.
activePreview
!==
null
)
this
.
hidePreview
();
this
.
activePreview
=
row
;
const
origRow
=
this
.
draggedBlock
.
row
;
const
origCol
=
this
.
draggedBlock
.
col
;
const
origBlock
=
this
.
layout
[
origRow
].
blocks
[
origCol
];
// Fix cases when dragging to own row
if
(
origRow
===
row
&&
position
>=
origCol
)
{
position
++
;
}
const
targetRow
=
document
.
getElementById
(
row
.
toString
());
const
preview
=
targetRow
.
getElementsByClassName
(
'
col-preview
'
)[
0
];
preview
.
style
.
order
=
position
;
preview
.
style
.
flexGrow
=
origBlock
.
width
;
preview
.
style
.
display
=
'
block
'
;
},
drop
(
event
,
row
)
{
// If events get processed in an unfortunate order
if
(
this
.
draggedBlock
===
null
)
return
;
this
.
hidePreview
();
const
position
=
this
.
getDropPosition
(
event
,
row
);
// Do nothing if row full
if
(
position
==
null
)
return
;
const
origRow
=
this
.
draggedBlock
.
row
;
const
origCol
=
this
.
draggedBlock
.
col
;
const
origBlock
=
this
.
layout
[
origRow
].
blocks
[
origCol
];
// Delete at origin
const
origBlocks
=
this
.
layout
[
origRow
].
blocks
;
origBlocks
.
splice
(
origCol
,
1
);
// Insert at destination
const
destBlocks
=
this
.
layout
[
row
].
blocks
;
destBlocks
.
splice
(
position
,
0
,
origBlock
);
if
(
origBlocks
.
length
==
0
)
this
.
layout
.
splice
(
origRow
,
1
);
// Normalize rows to 100 total width
if
(
origRow
!==
row
)
{
const
origTotalWidth
=
origBlocks
.
reduce
((
total
,
block
)
=>
total
+
block
.
width
,
0
);
const
origScaleFactor
=
100
/
origTotalWidth
;
for
(
const
block
of
origBlocks
)
{
block
.
width
*=
origScaleFactor
;
}
const
destTotalWidth
=
destBlocks
.
reduce
((
total
,
block
)
=>
total
+
block
.
width
,
0
);
const
destScaleFactor
=
100
/
destTotalWidth
;
for
(
const
block
of
destBlocks
)
{
block
.
width
*=
destScaleFactor
;
}
}
this
.
draggedBlock
=
null
;
},
hidePreview
()
{
if
(
this
.
activePreview
===
null
)
return
;
const
targetRow
=
document
.
getElementById
(
this
.
activePreview
.
toString
());
const
preview
=
targetRow
.
getElementsByClassName
(
'
col-preview
'
)[
0
];
preview
.
style
.
display
=
'
none
'
;
this
.
activePreview
=
null
;
},
isDragged
(
row
,
col
)
{
return
row
===
this
.
draggedBlock
?.
row
&&
col
===
this
.
draggedBlock
?.
col
;
},
saveLayout
(
id
)
{
const
type
=
"
save
"
const
payload
=
"
id=
"
+
id
+
"
&
"
+
"
data=
"
+
JSON
.
stringify
(
this
.
$data
);
...
...
@@ -194,7 +367,6 @@ export default {
}
},
},
mounted
(){
this
.
mobileLayoutResize
();
this
.
prevWinWidth
=
window
.
innerWidth
;
...
...
@@ -205,6 +377,26 @@ export default {
this
.
mobileLayoutResize
();
},
computed
:
{
previewType
()
{
if
(
this
.
draggedBlock
==
null
)
return
null
;
const
origRow
=
this
.
draggedBlock
.
row
;
const
origCol
=
this
.
draggedBlock
.
col
;
return
this
.
layout
[
origRow
].
blocks
[
origCol
].
type
;
}
},
provide
()
{
return
{
dragEnabled
:
computed
(()
=>
this
.
dragEnabled
),
startDrag
:
this
.
startDrag
,
stopDrag
:
this
.
stopDrag
}
},
components
:
{
ActiveCourses
,
Deadlines
,
...
...
@@ -220,7 +412,7 @@ export default {
#grid
{
width
:
100%
;
padding
:
$gap
/
2
;
padding
:
$gap
$gap
/
2
;
}
.row
{
...
...
@@ -228,7 +420,11 @@ export default {
margin-bottom
:
$gap
/
2
;
flex-direction
:
column
;
position
:
relative
;
min-height
:
150px
min-height
:
150px
;
&
.drag
*
{
pointer-events
:
none
;
}
}
// Must be outside ".row" or else after affect children
...
...
@@ -242,18 +438,37 @@ export default {
cursor
:
n-resize
;
}
.col
{
.col
,
.col-preview
{
flex-basis
:
0
;
// a basis of 0px. very important!
background-color
:
$light-green-theme-color
;
border-radius
:
4px
;
border
:
2px
solid
$theme-color
;
margin
:
0
$gap
/
2
;
}
.col
{
position
:
relative
;
&
:not
(
:last-child
)
{
margin-bottom
:
$gap
/
2
;
}
&
:not
(
:first-of-type
)
::before
{
content
:
" "
;
background-color
:
rgba
(
0
,
0
,
0
,
0
);
position
:
absolute
;
left
:
-
$gap
-
2px
;
width
:
$gap
;
height
:
100%
;
cursor
:
w-resize
;
}
}
.col-preview
{
display
:
none
;
opacity
:
0
.5
;
}
.add-block
{
width
:
50px
;
height
:
50px
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment