Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • vilem.ded/howto-cards
  • yjarosz/labCards
  • sarah.diehl/howto-cards
  • jacek.lebioda/howto-cards
  • pinar.alper/howto-cards
  • maharshi.vyas/howto-cards
  • manuel.maidorn/howto-cards
  • roland.krause/howto-cards
  • miriam.fougeras/howto-cards
  • soraya.hezzaz/howto-cards
  • fasavanh.sanichanh/howto-cards
  • marie.fossepre/howto-cards
  • jennifer.behm/howto-cards
  • annegrat.daujeumont/howto-cards
  • jon.gales/howto-cards-jpg
  • sandy.thill/howto-cards
  • jenny.tran/howto-cards
17 results
Show changes
Commits on Source (1420)
Showing with 1051 additions and 334 deletions
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
function UrlExists(url, cb){
jQuery.ajax({
url: url,
dataType: 'text',
type: 'GET',
cache: false,
complete: function(xhr){
if(typeof cb === 'function')
cb.apply(this, [xhr.status]);
}
});
}
function GetShortcutDestination() {
var s = window.location.href;
var pathArray = s.split('?');
// Cut the query if it exists
if (pathArray.length > 1) {
return pathArray[1];
} else {
return '';
}
}
function RedirectTo(newLocation) {
document.location.replace(newLocation);
}
// Pick the shortcut link destination from URL, like: `category:subcategory:card-name`
var sub = GetShortcutDestination();
// Define URLs
var internalPortalURL = 'https://r3-core.pages.uni.lu/howto-cards-internal';
var externalPortalURL = 'https://r3.pages.uni.lu/howto-cards';
// First, check whether internal pages are accessible...
var internalIndexURL = internalPortalURL + '/index.html';
UrlExists(internalIndexURL, function(status){
if(status === 200){
// If the internal pages are accessible, try to redirect into correct page
if (sub.length > 0) {
var internalCardURL = internalPortalURL + '/stable/internal/cards/' + sub;
UrlExists(internalCardURL, function(status){
if (status == 200) { // The sub-card is internal, and is accessible
RedirectTo(internalCardURL);
} else {
UrlExists(internalPortalURL + '/stable/external/cards/' + sub, function(status){
if (status == 200) { // if sub-card is internal in the external directory and exists
RedirectTo(internalPortalURL + '/stable/external/cards/' + sub);
} else {
RedirectTo(internalPortalURL + '/stable/404.html');
}
});
}
});
} else {
// The user did not request specific card, redirect him just to the stable index
var internalPortalIndexURL = internalPortalURL + '/stable';
var internalPortal404URL = internalPortalURL + '/stable/404.html';
UrlExists(internalPortalIndexURL, function(status){
if (status == 200) { // if page is accessible
RedirectTo(internalPortalIndexURL);
} else {
RedirectTo(internalPortal404URL);
}
});
}
} else {
// The internal pages are not accessible, therefore the user is redirected into correct external page
if (sub.length > 0) {
sub = 'external/cards/' + sub;
}
var externalPortalCardURL = externalPortalURL + '/stable/' + sub;
var externalPortal404URL = externalPortalURL + '/stable/404.html';
UrlExists(externalPortalURL + '/stable/' + sub, function(status){
if (status == 200) { // if sub-card is internal and exists
RedirectTo(externalPortalCardURL);
} else {
RedirectTo(externalPortal404URL);
}
});
}
});
</script>
</head>
<body>
<p>
Please follow to <a href="https://r3.pages.uni.lu/howto-cards/stable">https://r3.pages.uni.lu/howto-cards/stable</a>!
</p>
</body>
</html>
#!/bin/sh
# change this with environment
DEFAULT_NOT_SOURCE_REGEX="/\\/assets\\//"
NOT_SOURCE_REGEX="${NOT_SOURCE_REGEX:-$DEFAULT_NOT_SOURCE_REGEX}"
TIMESTAMP_SUFFIX="${SUFFIX:-.timestamp}"
LOGFILE="${LOGFILE:-/dev/null}"
[ -z "$1" ] && echo "$0: no inputs specified?" >/dev/stderr
while [ -n "$1" ]
do
echo "sourcing directory '$1' ..." >> "$LOGFILE"
find "$1" -type f -name '*.md' | grep -v "$NOT_SOURCE_REGEX" | while read file ; do
fn=`basename "$file"`
dir=`dirname "$file"`
tsfn="$fn.timestamp"
(
echo "making timestamp in '$dir' for file '$fn' ..." >> "$LOGFILE"
cd "$dir"
if [ -f "$tsfn" ]
then echo "... but it already exists; skipping!" >> "$LOGFILE"
else
TIMESTAMP=`git log -n 1 --pretty=format:%cs -- "$fn"`
mv "$fn" "$fn.temporary"
head -n1 "$fn.temporary" > "$fn"
echo "timestamp: \"$TIMESTAMP\"" >> "$fn"
tail -n+2 "$fn.temporary" >> "$fn"
rm -f "$fn.temporary"
fi
)
done
shift
done
import os, re
from os import path
from natsort import natsorted
from generator import core, save
def line_prepender(filename, line):
with open(filename, 'r+') as f:
content = f.read()
f.seek(0, 0)
f.write(line.rstrip('\r\n') + '\n' + content)
# walk through the folders with all the cards
ind, wl = core.core(["external"])
def build_link(title, href):
return f'\t\t\t<li><a href="{href}">{title}</a></li>\n'
def build_section_start(title):
title = title.replace("Gdpr", "GDPR")
title = title.replace("Handbook", "PI Handbook")
title = title.replace("Covid 19", "COVID-19")
return f'\n\t<div class="index-box">\n\t\t<h3>{title}</h3>\n\t\t<ul>\n'
def build_section_end():
return "\t\t</ul>\n\t</div>"
def remove_header(localroot, root, filename, n=5):
nfirstlines = []
#cwd = os.getcwd()
os.chdir(localroot)
#print("Local root folder:" + os.getcwd())
os.chdir(root)
#print("Local folder:" + os.getcwd())
# count the number of lines
count = 0
headerCheck = False
with open(filename, 'r') as f:
for line in f:
count += 1
# check if the header is actually a header
if (count == 0 or count == n) and line[0:3] == "---":
headerCheck = True
# remove the header
if count > n and headerCheck:
with open(filename) as f, open("tmp"+filename, "w") as out:
for _ in range(n):
nfirstlines.append(next(f))
for line in f:
out.write(line)
os.remove(filename)
os.rename("tmp"+filename, filename)
print(" - Old header removed.")
# change back to the local root
os.chdir(localroot)
#print("exit folder:" + os.getcwd())
# loop through the entire internal tree
localroot = os.getcwd()
# generate the index properly speaking
cardDirs = ["internal", "external", "policies"]
sections = []
# determine first the directories
for direct in cardDirs:
if path.isdir(direct):
dirs = os.listdir(direct)
dirs = natsorted(dirs)
for d in dirs:
if d[0] != ".":
sections.append(d)
sections = list(set(sections))
sections = natsorted(sections)
# Index contains the generated content, init it with an empty container
index = ''
index += '\n<div class="index-box-container">\n'
localIndexArr = [[]] * len(sections)
for folder in cardDirs:
# check if folder exists
if path.isdir(folder):
dirs = os.listdir(folder)
dirs = natsorted(dirs)
for d in dirs:
if d[0] != ".":
# set the header of the section
#index += "\n### " + d.replace("-", " ").capitalize() + "\n"
# get the index of the section
indexS = sections.index(d)
#print(indexS)
if len(localIndexArr[indexS]) == 0:
localIndexArr[indexS] = ["\n"]
# walk through the folders with all the cards
for root, dirs, files in os.walk(folder+"/"+d):
for file in files:
if file.endswith(".md"):
fileName = os.path.join(root, file)
# ignore subsections (.md files that start with _)
if file[0] != "_":
print(" > Generating header for: " + fileName)
# remove the previous header
remove_header(localroot, root, file, 8)
# generate a permalink
permalink = "/" + root + "/"
# generate the shortcut
shortcut = re.sub(folder, '', root)
# remove the first /
shortcut = shortcut[1:]
# replace the / with a :
shortcut = re.sub('/', ':', shortcut)
# define the header for each card
header = "---\n"
header += "layout: page\n"
header += "permalink: " + permalink + "\n"
header += "shortcut: " + shortcut + "\n"
header += "redirect_from:\n"
header += " - /cards/" + shortcut + "\n"
header += " - /" + folder + "/cards/" + shortcut + "\n"
header += "---"
# add the header properly speaking
line_prepender(fileName, header)
# open file and get the title after the header
count = 0
title = ""
bp = 9
with open(fileName, 'r') as f:
for line in f:
count += 1
if count == bp:
if len(line) > 2:
title = line
break
else:
bp += 1
# remove first and last chars
title = title.rstrip("\n\r")
title = title[2:]
localIndexArr[indexS].append(build_link(title, root))
# output
print(" + New header added.")
print("-----------------------")
# join all subcategories to the index
localIndexArr[indexS] = natsorted(localIndexArr[indexS])
print(localIndexArr)
# determine the index
k = 0
for s in sections:
index += build_section_start(s.replace("-", " ").capitalize())
index += ''.join(localIndexArr[k])
index += build_section_end()
k += 1
# Close the container
index += "\n</div>"
# output the index
#print(index)
# Read in the file
indexFile = "index.md"
filedata = ""
with open(indexFile, 'r') as file :
for line in file:
filedata += line
# stop reading once the index place holder has been reached
if re.search("<!-- index -->", line):
filedata += "[[ index ]]"
break
# Replace the target string
filedata = filedata.replace('[[ index ]]', index)
# Write the file out again
with open(indexFile, 'w') as file:
file.write(filedata)
print("\n > New index generated and saved in " + indexFile)
save.save_index(ind, "cards.md")
save.save_whitelist(wl, ".ci/whitelist.txt")
Subproject commit 53a922a13c4e8916c97599b5242493a47ea0a2e2
/privacy-policy
/search
https://www.dev47apps.com/
https://www.dev47apps.com/droidcam/connect/
https://cerbere.uni.lu/
http://iptel.uni.lux/
javascript:%20showBanner();
javascript:showBanner();
media/7zip-encryption-windows.mp4?width=400
media/Get_MD5_checksum_windows.mp4
https://intranet.uni.lux
https://intranet.uni.lux/the_university/lcsb/lscb_internal/
https://uniluxembourg.sharepoint.com/sites/lcsb/lscb_internal/LCSB%20Handbook/Appendix%20files/Godparent%20Checklist%20-%20newcomers.pdf
https://uniluxembourg.sharepoint.com/sites/lcsb/lscb_internal/LCSB%20Handbook/Appendix%20files/Newcomer%20Checklist%20Before%20Arriving%20in%20Luxembourg.pdf
https://uniluxembourg.sharepoint.com/sites/lcsb/lscb_internal/LCSB%20Handbook/Appendix%20files/Newcomer%20Checklist%20upon%20Arrival%20in%20Luxembourg.pdf
https://uniluxembourg.sharepoint.com/sites/lcsb/lscb_internal/SitePages/default.aspx
https://uniluxembourg.sharepoint.com/sites/sc/Lists/Policies%20%20Procedures/DispForm.aspx?ID=9
https://uniluxembourg.sharepoint.com/sites/siu/Documents%20partages/Dropit%20client%20-%20configuration%20guide.pdf#search=dropit
https://uniluxembourg.sharepoint.com/sites/siu/SitePages/siu-guides.aspx
\ No newline at end of file
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
......@@ -35,3 +35,13 @@ __pycache__/
contribute.egg-info/
policies
.tmp
env/.jekyll-cache/
env/Gemfile.lock
env/_site/
handbook/
internal/handbook
internal/handbook-additional
internal/handbook-annexes
!internal/covid-19/exit-strategy/*.pdf
checkFolder
.cache/
# In case something goes horribly wrong, you can fall back to `image: ruby:2.5`
image: git-r3lab.uni.lu:4567/r3/docker/jekyll-lcsb:1.6
stages:
- prepare
- save
- build
- check
- generate
- deploy
- trigger
variables:
GIT_STRATEGY: clone
GIT_DEPTH: 0
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
GIT_SUBMODULE_STRATEGY: recursive
# prepare
# ------------------------------------------------------------------------------------
......@@ -18,11 +26,12 @@ prepare:index:
- if: $CI_COMMIT_REF_NAME
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_MESSAGE !~ /tmpBranch/ && $CI_COMMIT_MESSAGE !~ /Update index/'
before_script:
- pip install natsort
- pip install -r .ci/generator/requirements.txt
script:
- python .ci/generateIndex.py
- mkdir .tmp
- cp index.md .tmp/.
- cp cards.md .tmp/.
- cp .ci/whitelist.txt .tmp/.
artifacts:
expire_in: 1 day
paths:
......@@ -37,7 +46,7 @@ save:commitIndex:
entrypoint: [""]
stage: save
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_MESSAGE !~ /tmpBranch/ && $CI_COMMIT_MESSAGE !~ /Update index/'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_MESSAGE !~ /tmpBranch/ && $CI_COMMIT_MESSAGE !~ /Update index/ && $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == "R3/howto-cards"'
before_script:
- apk add git-lfs
- git fetch --all
......@@ -47,7 +56,7 @@ save:commitIndex:
- git config user.email $GIT_ACCESS_EMAIL
script:
# copy the index and remove the temporary directory
- cp .tmp/index.md .
- cp .tmp/cards.md .
- rm -rf .tmp
# commit
......@@ -65,35 +74,61 @@ save:commitIndex:
# ------------------------------------------------------------------------------------
build:pages:
image: $CI_REGISTRY/r3/docker/jekyll-lcsb
stage: build
variables:
JEKYLL_ENV: production
BUNDLER_VERSION: 2.0.2
BUNDLER_VERSION: 2.1.4
artifacts:
expire_in: 1 day
paths:
- build
- .tmp
rules:
- if: $CI_COMMIT_REF_NAME
- if: $CI_MERGE_REQUEST_ID
before_script:
- apt-get -qq update
- apt-get install -y -qq git-lfs
- gem install bundler:$BUNDLER_VERSION && bundle install
script:
# copy the index
- cp .tmp/cards.md .
# Generate the configuration for forks (will use Gitlab Pages on personal namespaces)
- 'echo "url: https://$CI_PROJECT_NAMESPACE.$CI_PAGES_DOMAIN" >> .ci/_config_gitlab_pages.yml'
- 'echo "baseurl: /$CI_PROJECT_NAME" >> .ci/_config_gitlab_pages.yml'
# If there is no config for the current branch, use the one for Gitlab Pages
- 'if [ ! -f ".ci/_config_$CI_COMMIT_REF_NAME.yml" ]; then mv .ci/_config_gitlab_pages.yml .ci/_config_$CI_COMMIT_REF_NAME.yml; fi'
- |
if [ $CI_MERGE_REQUEST_ID ]; then
export CI_COMMIT_REF_NAME="develop";
else
echo "url: https://$CI_PROJECT_NAMESPACE.$CI_PAGES_DOMAIN" >> .ci/_config_gitlab_pages.yml;
echo "baseurl: /$CI_PROJECT_NAME" >> .ci/_config_gitlab_pages.yml;
# If there is no config for the current branch, use the one for Gitlab Pages
if [ ! -f ".ci/_config_$CI_COMMIT_REF_NAME.yml" ]; then
mv .ci/_config_gitlab_pages.yml .ci/_config_$CI_COMMIT_REF_NAME.yml;
fi
fi
# Display, which configuration is used
- 'echo "Configuration: " && cat ".ci/_config_$CI_COMMIT_REF_NAME.yml"'
- |
echo "Configuration: " && cat ".ci/_config_$CI_COMMIT_REF_NAME.yml"
# Run Jekyll with custom configuration
- LOGFILE=/dev/stdout .ci/add-timestamp-to-howtocard.sh external
- bundle exec jekyll build -d build --config "_config.yml,.ci/_config_$CI_COMMIT_REF_NAME.yml"
# check
# ------------------------------------------------------------------------------------
check:links:
stage: check
image: $CI_REGISTRY/r3/apps/tailorbird/linkchecker
rules:
- if: $CI_COMMIT_REF_NAME
- if: $CI_MERGE_REQUEST_ID
allow_failure: true
before_script:
- cp .tmp/whitelist.txt build/.
- cp -r build /check
- cd /
script:
- python link_check.py
# generate
# ------------------------------------------------------------------------------------
......@@ -119,7 +154,8 @@ pages:
image: alpine:3.11.3
stage: deploy
rules:
- if: '$CI_MERGE_REQUEST_ID && $CI_PROJECT_NAMESPACE != "R3" && $CI_PROJECT_NAMESPACE != "R3-core"'
- if: '$CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_PATH == "R3/howto-cards"'
- if: '$CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_REF_NAME == "master" && $CI_PROJECT_PATH == "R3/howto-cards"'
script:
- mv processed_build public
artifacts:
......@@ -140,10 +176,22 @@ deploy:vm:
- echo "$KNOWNHOSTS" > ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
rules:
- if: '$CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_PATH == "R3/howto-cards"'
#- if: '$CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_REF_NAME == "develop" && $CI_PROJECT_PATH == "R3/howto-cards"'
- if: '$CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_REF_NAME == "master" && $CI_PROJECT_PATH == "R3/howto-cards"'
script:
- ssh -p $SSHPORT $SSHCONNECT "mkdir -p ~/$CI_COMMIT_REF_NAME/sources/public/$CI_JOB_ID ~/$CI_COMMIT_REF_NAME/public"
- scp -P $SSHPORT -r processed_build/* $SSHCONNECT:~/$CI_COMMIT_REF_NAME/sources/public/$CI_JOB_ID
- ssh -p $SSHPORT $SSHCONNECT "cd ~/$CI_COMMIT_REF_NAME/public && ln -fs ../sources/public/$CI_JOB_ID/* . && cd ~/$CI_COMMIT_REF_NAME/sources/public/ && find . -type d -not -newermt '-1 minutes' -exec rm -rf {} +;"
# Trigger pipelines in internal repo
# ------------------------------------------------------------------------------------
trigger:
stage: trigger
image: curlimages/curl
rules:
- if: '$CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "develop"'
tags:
- privileged
script:
- curl --silent --output /dev/null -X POST -F token=$INTERNAL_TRIGGER_TOKEN -F ref=$CI_COMMIT_BRANCH $INTERNAL_REPO
[submodule ".ci/generator"]
path = .ci/generator
url = https://gitlab.lcsb.uni.lu/R3/apps/generator.git
......@@ -12,7 +12,7 @@ gem "jekyll", "~> 4.0"
gem "bundler", "> 2.0"
gem "minima", "~> 2.5"
gem 'jekyll-theme-lcsb-default', '~> 0.4.5'
gem 'jekyll-theme-lcsb-default', '~> 0.5.0'
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
......@@ -32,7 +32,7 @@ group :jekyll_plugins do
gem 'jekyll-theme-lcsb-frozen-components',
'~> 0.0.2',
:git => "https://git-r3lab.uni.lu/core-services/jekyll-theme-lcsb-frozen-components.git",
:git => "https://gitlab.lcsb.uni.lu/core-services/jekyll-theme-lcsb-frozen-components.git",
:tag => "0.0.2"
gem 'jekyll-redirect-from',
......@@ -45,4 +45,6 @@ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# Performance-booster for watching directories on Windows
gem "wdm", "~> 0.1.1" if Gem.win_platform?
gem 'jekyll-spaceship', "0.6.0"
gem 'jekyll-spaceship', "~> 0.9"
gem "webrick", "~> 1.7"
......@@ -19,14 +19,17 @@ description: >- # this means to ignore newlines until "baseurl:"
This page is an index for lab cards that are intended to provide practical guidance in implementing Data Management, Data Protection and IT setup.
# URL settings (the most difficult part, please refer to the guide)
baseurl: "/" # the subpath of your site, e.g. /gitlab-repository-name
url: "https://localhost" # the base hostname & protocol for your site, e.g. http://gitlab-namespace-name.pages.uni.lu/
baseurl: "/howto-cards" # the subpath of your site, e.g. /gitlab-repository-name
url: "https://howto.lcsb.uni.lu" # the base hostname & protocol for your site, e.g. http://gitlab-namespace-name.pages.uni.lu/
# Banner settings
banner: howto-card # When you have custom images, change this setting's value to the name of the folder containing them
logo: small # Change to "big" (without quotas) in case of having broad logo
date: "2020"
# Is internal or external?
internal: false
# Social media icon settings
twitter_username: uni_lu
facebook_username: uni.lu
......
<footer class="site-footer h-card">
<div class="wrapper footer-wrapper">
<data class="u-url" href="{{ "/" | relative_url }}"></data>
<div class="footer-cp">
<div class="r3-logo-container">
<img class="r3-logo" src="{{ '/assets/banners/r3-logo.svg' | relative_url }}" type="image/svg+xml" />
<img class="lcsb-logo" src="{{ '/assets/banners/lcsb-compact.svg' | relative_url }}" type="image/svg+xml" />
</div>
{% comment %}This is used to generate share URL for howto-pages{% endcomment %}
<div class="footer-text-container">
{% if page.timestamp %}
<p>Last page modification: {{ page.timestamp }}</p>
{% endif %}
{% if page.shortcut %}
<p>
Share this page:
<a href="{{ site.share_url }}{{ page.shortcut }}">
{{ site.share_url }}{{ page.shortcut }}
</a>
</p>
{% elsif page.include_link %}
{% assign parts = page.url | absolute_url | replace: ".html", "" | replace: "http://", "" | replace: "https://", "" | split: "/" %}
<p>
Share this page:
<a href="{{ site.share_url }}{{ parts[site.include_link_index] }}">
{{ site.share_url }}{{ parts[site.include_link_index] }}
</a>
</p>
{% endif %}
<p>
The contents are available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike License (CC-BY-SA 4.0)</a>.
</p>
{% if site.siteID > 0 %}
{%- include policy.html -%}
{% endif %}
</div>
<div class="social-container">
{%- include social.html -%}
</div>
</div>
</div>
</footer>
{% if site.siteID > 0 %}
{%- include gdpr-banner.html -%}
{% endif %}
<script src="{{ '/assets/vendor/js/jquery-3.6.0.min.js' | relative_url }}"></script>
<script type="text/javascript" src="https://analytics.lcsb.uni.lu/lap/static/js/jquery.min.js"></script>
<script type="text/javascript" src="{{ "assets/js/router.js" | relative_url }}"></script>
\ No newline at end of file
<script type="text/javascript" src="{{ "assets/js/router.js" | relative_url }}"></script>
<script type="text/javascript" src="{{ "assets/js/box_hider.js" | relative_url }}"></script>
<script>
window.addEventListener('load', function() {
window.boxHider.Trigger();
})
</script>
......@@ -54,7 +54,7 @@
window.content = { {% for card in the_cards %}
"{{ card.url | slugify }}": {
"title": "{{ card.shortcut | xml_escape }}",
"content": {{ card.content | strip_html | strip_newlines | jsonify }},
"content": {{ card.content | markdownify | strip_html | strip_newlines | truncate: 150 | jsonify }},
"url": "{{ card.url | xml_escape | relative_url }}"
} {% unless forloop.last %},{% endunless %} {% endfor %}
};
......@@ -68,7 +68,7 @@
for (var i = 0; i < results.length; i++) {
var node = document.createElement("tr");
node.innerHTML = construct_cell(prettify(window.content[results[i].ref].title),
window.content[results[i].ref].content.substring(0, 125) + '...',
window.content[results[i].ref].content.substring(0, 150) + '...',
window.content[results[i].ref].url);
el_table_body.appendChild(node);
}
......@@ -84,4 +84,4 @@
el_tr_placeholder.style.display = "none";
})
</script>
\ No newline at end of file
</script>
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
{%- include head.html -%}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
<link href="{{ "assets/css/landing.css" | relative_url }}"" rel="stylesheet" />
<body>
<div class="main">
<div class="content-wrapper">
<header class="site-header" role="banner">
<div>
{%- if site.banner_link -%}
{%- assign banner_link = site.banner_link -%}
{%- else -%}
{%- assign banner_link = '/' | relative_url -%}
{%- endif -%}
<div class="custom-header">
<a href="{{ banner_link }}"><img class="img-uni-lu"
src="{{ '/assets/banners/uni-logo.svg' | relative_url }}"
type="image/svg+xml"
/></a>
<img class="img-banner img-banner-main"
src="{{ '/assets/banners/' | relative_url }}{{ site.banner }}/banner.svg"
type="image/svg+xml"
/>
<img class="img-banner img-banner-motto"
src="{{ '/assets/banners/' | relative_url }}{{ site.banner }}/motto.svg"
type="image/svg+xml"
/>
<img class="img-lcsb img-logo-{{ site.logo }}"
src="{{ '/assets/banners/' | relative_url }}{{ site.banner }}/logos.svg"
type="image/svg+xml"
/>
</div>
</div>
</header>
<main class="page-content" aria-label="Content" style="margin-right: 0%">
{% if site.internal %}
<div class="indicator tooltip" id="internal-indicator">
<p>
Internal
<i class="material-icons">info</i>
</p>
<span class="tooltip-text">
You are connected to the uni.lu network. <br />You see all the cards.
</span>
</div>
{% else %}
<div class="indicator tooltip" id="external-indicator">
<p>
External
<i class="material-icons">info</i>
</p>
<span class="tooltip-text">
You are <strong>not connected</strong> to the uni.lu network. <br />You can see only publicly available cards. <br />In order to see all, please connect to the university network via VPN.
</span>
</div>
{% endif %}
<div class="wrapper">
{%- if page.show_print_button -%}
<div class="print-button">
<img src="{{ "assets/pdf.svg" | relative_url }}">
<a href="javascript:window.print()"><span>Print the page</span></a>
</div>
{%- endif -%}
{{ content }}
<!-- index -->
<form action="search" method="GET">
<div class="search-bar">
<input placeholder="What would you like to look for?" type="text" name="search_query" />
<i class="large material-icons">search</i>
</div>
</form>
<div class="container">
<div class="left-inner-container" id="left-inner-container" ondrop="window.cardDropDiscard(event)" ondragover="window.allowDrop(event)">
</div>
<div class="right-inner-container" id="right-inner-container" ondrop="window.cardDrop(event)" ondragover="window.allowDrop(event)">
<div id="drop-to-add" class="card-pinned card-grayed card-pulsate">
<div class="card-header">
<div class="card-icon"><i class="large material-icons">add</i></div>
</div>
<div class="card-content">
<div class="card-title">
<small>Drop to add...</small>
</div>
</div>
</div>
<div class="card-pinned card-grayed cursor-hand" onclick="clear_pinned()">
<div class="card-header">
<div class="card-icon"><i class="large material-icons">delete</i></div>
</div>
<div class="card-content">
<div class="card-title">
<small>Remove all...</small>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
{%- include footer.html -%}
</div>
</body>
{%- include scripts.html -%}
<script>
window.is_internal = false;
</script>
<script src="{{ "assets/js/landing.js" | relative_url }}"></script>
</html>
......@@ -5,7 +5,7 @@ Jekyll::Hooks.register([:pages, :posts, :documents], :pre_render) do |post|
include Jekyll::EmailProtect::EmailProtectionFilter
# Using a simpler version of email regexp
email_regexp = /mailto\:(?:[\'\"]*)(?:[\w+\-]\.?)+@[a-z\d\-]+(?:\.[a-z]+)*\.[a-z]+(?:[\'\"]*)/i
email_regexp = /mailto\:(?:[\w+\-]\.?)+@[a-z\d\-]+(?:\.[a-z]+)*\.[a-z]+/i
# Take post's content, and transform every occurence of the following regexp (an email)
post.content = post.content.gsub(email_regexp) {
......
:root {
--primary-color: rgb(0, 170, 220);
--secondary-color: #dddedd;
--red-color: rgb(255, 20, 11);
--tooltip-bg: rgb(25, 25, 25);
--border-radius: 25px;
--border-radius-pinned: 18px;
--title-height: 30px;
--animation-time: 300ms;
}
.wrapper {
padding-right: 15px;
}
.container {
font-family: Helvetica;
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 5fr 1fr;
}
@media (max-width: 1080px) {
.container {
grid-template-columns: 5fr 0fr;
}
}
.container > .left-inner-container {
grid-column: 1;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
padding-right: 10px;
border: solid 1px rgba(0,0,0,0);
border-right: solid 2px rgba(240, 240, 240, 0.7);
}
@media (max-width: 1080px) {
.container > .left-inner-container {
border: none;
padding-right: 0px;
}
}
.full-bleed {
width: 100%;
grid-column: 1 / 4;
}
.container > .right-inner-container {
height: 100%;
border: solid 1px rgba(0,0,0,0);
grid-column: 2;
transition: border var(--animation-time) linear, background-color var(--animation-time) linear;
margin: 0px auto;
display: block;
padding-top: 12px;
width: 100%;
border-radius: 0px 20px 20px 0;
padding-left: 5px;
}
@media (max-width: 1080px) {
.container > .right-inner-container {
display: none;
}
}
.droppable {
background: #eee;
border: solid 1px var(--secondary-color);
}
.cursor-hand {
cursor: pointer !important;
}
/* ==================================================== */
/* Normal cards */
/* ==================================================== */
.card-link {
color: unset !important;
text-decoration: none;
cursor: pointer;
}
.card-link:hover {
text-decoration: none;
}
.card-link:hover > .card > .card-content {
border-color: var(--primary-color) !important;
}
.card {
margin: 10px;
margin-bottom: 20px;
width: 160px;
min-height: 100px;
}
@media (max-width: 10px) {
.card {
width: 100%;
grid-template-columns: 3fr 5fr;
display: grid;
height: 60px;
}
}
.card.card-dragged {
height: 80px;
}
.card > .card-header {
height: 50%;
border: solid 3px var(--primary-color);
border-radius: var(--border-radius) var(--border-radius) 0 0;
background-color: white;
transition: background-color var(--animation-time) linear, border-style var(--animation-time) linear;
}
@media (max-width: 10px) {
.card > .card-header {
display: grid;
grid-template-rows: 2fr 2fr;
border-radius: var(--border-radius) 0px 0px var(--border-radius);
min-height: 100px;
}
}
.card > .card-header:hover {
border-color: var(--primary-color);
background-color: var(--primary-color);
}
.card > .card-header:hover > .card-icon {
color: white;
}
.card > .card-header.card-dragged {
border-style: dotted !important;
border-color: #66c9e9 !important;
height: 150px;
border-radius: var(--border-radius);
}
.card > .card-header.card-dragged > .card-title {
background: none !important;
position: relative;
top: -35px;
}
.card > .card-content {
border: solid 3px var(--secondary-color);
border-top: 0;
border-radius: 0 0 var(--border-radius) var(--border-radius);
/* min-height: calc(50% - 20px); */
min-height: 110px;
padding: 10px 10px 5px 10px;
text-align: center;
transition: height var(--animation-time) linear, border-color var(--animation-time) linear;
background-color: white;
font-size: 15px;
}
@media (max-width: 10px) {
.card > .card-content {
display: flex;
border-radius: 0 var(--border-radius) var(--border-radius) 0px;
min-height: 100px;
}
}
.card > .card-content.card-dragged {
opacity: 0;
background: rgba(255,255,255,0.0);
height: 0px;
}
.card > .card-header > .card-icon {
height: calc(100% - var(--title-height));
width: 80%;
margin: 0px auto;
display: block;
text-align: center;
color: var(--primary-color);
transition: color var(--animation-time) linear;
}
.card > .card-header > .card-icon i {
padding-top: 10px;
font-size: 4rem;
}
.card > .card-header > .card-title {
cursor: move;
--card-title-padding: 6px;
background-color: var(--primary-color);
color: white;
width: 100%;
height: calc(var(--title-height) - var(--card-title-padding));
padding-top: var(--card-title-padding);
text-align: center;
vertical-align: middle;
font-size: 14pt;
}
@media (max-width: 10px) {
.card > .card-header > .card-title {
border-radius: 0px 0px 0px var(--border-radius);
height: 15px;
padding: 0 0 5px 0;
font-size: unset;
}
}
/* ==================================================== */
/* Pinned cards */
/* ==================================================== */
.card-pinned {
width: 74px;
height: 72px;
margin-bottom: 60px;
margin-left: 25%;
cursor: pointer;
}
.card-pinned[draggable="True"] > .card-header > .card-title {
cursor: pointer;
}
.card-pinned > .card-header {
height: 100%;
border: solid 3px var(--primary-color);
border-radius: var(--border-radius-pinned);
background-color: white;
transition: background-color var(--animation-time) linear, border-style var(--animation-time) linear;
}
.card-pinned > .card-header > .card-icon {
text-align: center;
color: var(--primary-color);
}
.card-pinned > .card-header > .card-icon i {
padding-top: 10px;
font-size: 3rem;
}
.card-pinned > .card-content {
padding: 4px 0px;
font-size: smaller;
color: #777;
text-align: center;
}
.card-pinned.card-red > .card-header {
border-color: var(--red-color);
}
.card-pinned.card-red > .card-header > .card-icon {
color: var(--red-color);
}
.card-pinned.card-grayed > .card-header {
border-color: #ccc;
border-style: dashed;
user-select: none;
}
#drop-to-add > * {
cursor: auto;
}
.card-pinned.card-grayed > .card-header > .card-icon {
color: #ccc;
}
.right-inner-container.droppable > .card-pinned.card-grayed.card-pulsate {
animation-name: stretch;
animation-duration: 0.6s;
animation-direction: alternate;
animation-iteration-count: infinite;
animation-play-state: running;
}
@keyframes stretch {
0% {
transform: scale(.90);
}
100% {
transform: scale(1.1);
}
}
/* ==================================================== */
/* Search bar */
/* ==================================================== */
div.search-bar {
width: 60%;
margin-left: 12%;
display: flex;
}
@media (max-width: 1080px) {
div.search-bar {
margin-left: 3%;
width: 100%;
}
}
.search-bar > input {
width: 100%;
margin: 0px 0px 40px 0px;
border-radius: 20px;
border: solid 2px #eee ;
padding: 8px 25px;
height: 15pt;
font-size: 16px;
transition: border var(--animation-time) linear, font-size var(--animation-time) linear;
}
.search-bar > i {
position: relative;
left: -40px;
top: 7px;
}
.search-bar > input:focus {
border-color: var(--primary-color);
outline: none;
font-size: larger;
}
.search-bar > input:active {
border-color: var(--primary-color);
outline: none;
font-size: larger;
}
/* ==================================================== */
/* Internal/external indicator */
/* ==================================================== */
.indicator {
position: absolute;
top: 190px;
right: 59px;
color: #d6d6d6;
text-align: center;
cursor: pointer;
}
@media (max-width: 1080px) {
.indicator {
top: 128px;
right: 72px;
}
}
@media (max-width: 700px) {
.indicator {
top: 10px;
right: 50px;
}
}
.indicator > p > i {
font-size: 20px;
position: relative;
top: 5px;
left: 5px;
}
.indicator > p {
font-size: 14px;
}
/* ==================================================== */
/* Tooltip */
/* ==================================================== */
.tooltip .tooltip-text {
visibility: hidden;
width: 400px;
right: 120%;
top: -43px;
background-color: var(--tooltip-bg);
color: var(--secondary-color);
text-align: center;
padding: 10px 0;
border-radius: 8px;
position: absolute;
z-index: 1;
}
.tooltip:hover .tooltip-text {
visibility: visible;
}
.tooltip .tooltip-text::after {
content: " ";
position: absolute;
top: 50%;
left: 100%; /* To the right of the tooltip */
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent transparent var(--tooltip-bg);
}
/**
* This is used to hide the sections of the index page
* based on the URL fragment (a.k.a. "hash")
*/
window.boxHider = (function() {
function GetSelectedId() {
var boxId = window.location.hash + '-card';
if (boxId.length > 0) {
return boxId.substring(1);
}
return "";
}
function GetAllBoxElements() {
return document.getElementsByClassName('index-box');
}
function GetAllBoxElementsArray() {
var allBoxes = GetAllBoxElements();
var allBoxesArray = Array.prototype.slice.call(allBoxes);
return allBoxesArray;
}
function GetSelectedBoxElement(id) {
var allBoxesArray = GetAllBoxElementsArray();
// note: handbook and lab are actually grouped sections
if (id.startsWith('handbook') || id.startsWith('lab') || id.startsWith('qms') || id.startsWith('publication')) {
return true;
} else {
var element = document.getElementById(id);
if (allBoxesArray.includes(element)) {
return element;
}
return false;
}
}
function HideElement(element) {
if (element instanceof HTMLElement) {
element.style['display'] = 'none';
}
}
function ShowElement(element) {
if (element instanceof HTMLElement) {
element.style['display'] = 'inline-block';
}
}
function HideAllCategories() {
var allCategoriesElement = document.getElementById('all-categories');
HideElement(allCategoriesElement);
}
function ShowAllBoxes() {
var allBoxes = GetAllBoxElementsArray();
allBoxes.map(function(box) {
ShowElement(box);
});
}
function Trigger() {
// First, try to get the hash from the URL (https://example.com/uri?param#hash)
var boxId = GetSelectedId();
if (boxId.length == 0) {
// If there is no hash in the URL, just show all the boxes
ShowAllBoxes();
return;
}
// Otherwise, proceed to getting the corresponding div element
var selectedBox = GetSelectedBoxElement(boxId);
if (selectedBox == false) {
// If the user selection is not a `div.index-box`, then just show all the boxes
ShowAllBoxes();
return;
}
// Hide the "All Categories" element
HideAllCategories();
// Finally, hide all boxes except of the selected one
// Moreover, make sure that the selected boxes are displayed.
var allBoxes = GetAllBoxElementsArray();
if (boxId.startsWith('handbook')) {
allBoxes.map(function(box) {
if (!box.id.startsWith('handbook')) {
HideElement(box);
} else {
ShowElement(box);
}
});
} else if (boxId.startsWith('lab')) {
allBoxes.map(function(box) {
if (!box.id.startsWith('lab')) {
HideElement(box);
} else {
ShowElement(box);
}
});
} else if (boxId.startsWith('qms')) {
allBoxes.map(function(box) {
if (!box.id.startsWith('qms')) {
HideElement(box);
} else {
ShowElement(box);
}
});
} else if (boxId.startsWith('publication')) {
allBoxes.map(function(box) {
if (!box.id.startsWith('publication')) {
HideElement(box);
} else {
ShowElement(box);
}
});
} else {
allBoxes.map(function(box) {
if (box != selectedBox) {
HideElement(box);
} else {
ShowElement(box);
}
});
}
}
return {
'Trigger': Trigger,
'ShowAllBoxes': ShowAllBoxes
}
})();
window.cards_limit = 6;
var storage_key = "pinnedCards";
if (window.is_internal) {
storage_key += "Internal"
} else {
storage_key += "External"
}
let $left_inner_container = document.getElementById("left-inner-container");
let $right_inner_container = document.getElementById("right-inner-container");
let $drop_to_add = document.getElementById("drop-to-add");
// ============= DATA ========================================
let pinned_cards_store = localStorage.getItem(storage_key);
window.pinned_cards = [
];
// ============= DOM functions ========================================
let create_card = function(icon, title, caption, link) {
let new_div = document.createElement('div');
new_div.innerHTML = `
<a class="card-link card-dynamic" ondragstart="window.cardDragStart(event)" ondragend="window.cardDragEnd(event)" href="${link}">
<div class="card" draggable="True" ondragstart="window.cardDragStart(event)" ondragend="window.cardDragEnd(event)" data-icon='${icon}' data-title='${title}' data-caption='${caption}' data-link="${link}">
<div class="card-header">
<div class="card-icon">${icon}</div>
<div class="card-title">${title}</div>
</div>
<div class="card-content">
<div class="card-caption">${caption}</div>
</div>
</div>
</a>
`;
return new_div;
};
let create_pinned_card = function(icon, title, caption, link) {
let new_div = document.createElement('div');
new_div.innerHTML = `
<a class="card-link card-dynamic-pinned" ondragstart="window.pinnedCardDragStart(event)" ondragend="window.pinnedCardDragEnd(event)" href="${link}">
<div class="card-pinned" draggable="True" draggable="false" ondragstart="window.pinnedCardDragStart(event)" ondragend="window.pinnedCardDragEnd(event)" data-icon='${icon}' data-title='${title}' data-caption='${caption}' data-link="${link}">
<div class="card-header">
<div class="card-icon">${icon}</div>
</div>
<div class="card-content">
<div class="card-title">${title}</div>
</div>
</div>
</a>
`;
return new_div;
}
let attach_card = function(container, card) {
container.append(card);
}
let attach_pinned_card = function(container, card) {
let card_el = create_pinned_card(card.icon, card.title, card.caption, card.link);
let first_child = container.children[1];
// might as well remove all children and rebuild the contents using window.pinned_cards
container.insertBefore(card_el, first_child);
}
// ============= Helper functions ========================================
let list_contains = function(the_list, the_object, key) {
for (const element of the_list) {
if (the_object[key] === element[key])
return true;
}
return false;
}
let remove_from_list = function(the_list, the_object, key) {
var index = -1;
for (var i = 0; i < the_list.length; i++) {
if (the_list[i][key] == the_object[key]) {
index = i;
break;
}
}
if (index != -1) {
the_list.splice(i, 1);
}
}
// ============= DRAG&DROP functions ========================================
window.cardDragStart = function(event) {
var target = event.target;
if (target.nodeName == 'A') {
target = target.firstElementChild;
}
// First, attach classes for animations
target.classList.add('card-dragged');
target.children[1].classList.add('card-dragged');
target.children[0].classList.add('card-dragged');
$right_inner_container.classList.add('droppable');
// Attach data about the card to drag&drop event
let card = {
"title": target.dataset['title'],
"icon": target.dataset['icon'],
"caption": target.dataset['caption'],
"link": target.dataset['link'],
"type": "big"
}
event.dataTransfer.setData("card", JSON.stringify(card));
// Allow drag&drop
event.dataTransfer.effectAllowed = 'move';
return true;
}
window.cardDragEnd = function(event) {
var target = event.target;
if (target.nodeName == 'A') {
target = target.firstElementChild;
}
target.classList.remove('card-dragged');
target.children[1].classList.remove('card-dragged');
target.children[0].classList.remove('card-dragged');
$right_inner_container.classList.remove('droppable');
return true;
}
window.pinnedCardDragStart = function(event) {
var target = event.target;
if (target.nodeName == 'A') {
target = target.firstElementChild;
}
$left_inner_container.classList.add('droppable');
// Attach data about the card to drag&drop event
let card = {
"title": target.dataset['title'],
"icon": target.dataset['icon'],
"caption": target.dataset['caption'],
"link": target.dataset['link'],
"type": "small"
}
event.dataTransfer.setData("card", JSON.stringify(card));
// Allow drag&drop
event.dataTransfer.effectAllowed = 'move';
return true;
}
window.pinnedCardDragEnd = function(event) {
$left_inner_container.classList.remove('droppable');
return true;
}
window.cardDrop = function(event) {
let serializedCard = event.dataTransfer.getData("card");
let card = JSON.parse(serializedCard);
// Don't react to dropping small (shortcut) cards
if (card['type'] == "small") {
return;
}
// Add limit of pinned cards
if (window.pinned_cards.length >= window.cards_limit) {
return;
}
if (!list_contains(window.pinned_cards, card, "title")) {
window.pinned_cards.push(card);
localStorage.setItem(storage_key, JSON.stringify(pinned_cards));
window.cards = window.cards.filter(function(el) { return el['title'] != card['title'];});
rebuild_pinned_cards();
rebuild_cards();
}
refresh_drop_to_add_button();
if (event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
}
window.cardDropDiscard = function(event) {
let serializedCard = event.dataTransfer.getData("card");
let card = JSON.parse(serializedCard);
if (card['type'] == "big")
return;
if (list_contains(window.pinned_cards, card, "title")) {
remove_from_list(window.pinned_cards, card, "title");
localStorage.setItem(storage_key, JSON.stringify(pinned_cards));
cards.push(card);
rebuild_pinned_cards();
rebuild_cards();
}
refresh_drop_to_add_button();
if (event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
}
window.allowDrop = function(event) {
event.preventDefault();
}
window.rebuild_cards = function() {
while ($left_inner_container.firstChild) {
$left_inner_container.removeChild($left_inner_container.firstChild);
}
for (const card of window.cards) {
let card_el = create_card(card.icon, card.title, card.caption, card.link);
attach_card($left_inner_container, card_el);
}
}
window.rebuild_pinned_cards = function() {
var old_pinned_cards = document.getElementsByClassName("card-dynamic-pinned");
while (old_pinned_cards.length > 0){
old_pinned_cards[0].parentNode.removeChild(old_pinned_cards[0]);
}
for (const card of pinned_cards) {
let card_el = create_pinned_card(card.icon, card.title, card.caption, card.link);
attach_pinned_card($right_inner_container, card);
}
}
window.refresh_drop_to_add_button = function() {
if (window.pinned_cards.length == window.cards_limit) {
$drop_to_add.style.display = "none"
} else {
$drop_to_add.style.display = "block"
}
}
window.clear_pinned = function() {
for (card of pinned_cards) {
cards.push(card);
}
pinned_cards = [];
localStorage.setItem(storage_key, JSON.stringify(pinned_cards));
rebuild_pinned_cards();
rebuild_cards();
refresh_drop_to_add_button();
}
window.start_cards = function() {
// ============= Initialization ========================================
if (pinned_cards_store == null) {
localStorage.setItem(storage_key, JSON.stringify(pinned_cards));
} else {
pinned_cards = JSON.parse(pinned_cards_store);
// Sort alphabetically
pinned_cards = pinned_cards.sort(function(a, b) { if (a.title > b.title) return -1; else if (a.title < b.title) return 1; else return 0; });
// Remove duplicates of pinned cards
for (const card of pinned_cards) {
remove_from_list(cards, card, "title");
}
}
refresh_drop_to_add_button();
rebuild_cards();
rebuild_pinned_cards();
}