--- /dev/null
+#!/bin/zsh
+
+# Copyright 2015 Paul Hänsch
+#
+# This file is part of Confetti.
+#
+# Confetti is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Confetti is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
+
+catfile="${_DATA}/mappings/categories"
+cgi_post
+
+remove="${_POST[remove]}"
+newcat="${_POST[newcat]}"
+
+if [ "${_POST[add]}" = "add" ]; then
+ printf %s\\n "$newcat" >>"$catfile"
+elif [ -n "$remove" ]; then
+ sed -ri '/^'"${remove}"'$/d' $catfile
+fi
+
+redirect "?p=categories"
--- /dev/null
+#!/bin/zsh
+
+# Copyright 2015 Paul Hänsch
+#
+# This file is part of Confetti.
+#
+# Confetti is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Confetti is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
+
+catfile="${_DATA}/mappings/categories"
+
+listcards() {
+ ls -1 ${_DATA}/vcard/*vcf 2>/dev/null |while read file; do
+ fn=$(sed -rn 's:^N(;.+)*\:([^;]*;){1} *([^;]*).*$:\3:p' "$file")
+ echo "$fn\t$file"
+ done |sort |sed -r 's:^.*\t(.*/)([^/]+)$:\2:'
+}
+
+get_name() {
+ cfile="${_DATA}/vcard/$1"
+ sed -rn 's:^N(;[^"\:]+|;"[^"]+")*\:([^;]*)(\;[^;]*)(\;[^;]*)?(\;[^;]*)?(\;[^;]*)?\r?$:\5 \3 \4 \2 \6:p' "$cfile" \
+ |sed -r 's:,: :;s:\;: :g;s: +: :g' \
+}
+
+get_categories(){
+ cfile="${_DATA}/vcard/$1"
+ sed -rn 's:^CATEGORIES(;[^"\:]+|;"[^"]+")*\:(.+)\r?$:\2:p' "$cfile" \
+ | sed -r 's;(^|[^\\]+)((\\\\)+),;\1\2\n;g; s;(^|[^\\]),;\1\n;g; s;(^|[^\\]+)((\\\\)+),;\1\2\n;g; s;(^|[^\\]),;\1\n;g; s;\\,;,;g' \
+ | sort -u
+}
+
+list_categories() {
+ sort -u "$catfile"
+}
--- /dev/null
+# Copyright 2014, 2015 Paul Hänsch
+#
+# This file is part of Confetti.
+#
+# Confetti is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Confetti is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
+
+cat <<EOF
+
+form.categories {
+ display: block;
+ border: solid 1px;
+ border-radius: 4px 4px 0 0;
+ margin: .5em 2em .25em 2em;
+ padding: 0 2ex .5em 2ex;
+ background: #EFF;
+}
+
+form.categories h1 {
+ display: block;
+ font-weight: bold;
+ font-size: 1.25em;
+ border-style: none none solid none;
+ border-radius: 4px 4px 0 0;
+ border-width: 1px;
+ margin: 0 -1.625ex .5em -1.625ex;
+ padding: .125em 1ex;
+ background: #EEF;
+}
+
+form.categories ul { margin: 0; padding: 0; }
+form.categories ul li {
+ display: inline-block;
+ margin: 0 .25ex;
+ padding: .125em .25ex .125em 1ex;
+ border: 1px solid black;
+ background-color: #EEF;
+}
+form.categories ul li button {
+ margin: 0 0 0 1ex;
+ background-color: #FCC;
+ border: 1px solid black;
+ min-width: 3ex;
+ text-align: center;
+}
+form.categories ul li:last-of-type { padding: .125em .25ex .125em .25ex; }
+form.categories ul li:last-of-type button { background-color: #FFF; }
+
+form.namelist {
+ display: block;
+ margin: 1em 2em;
+ padding: 0;
+}
+form.namelist > fieldset {
+ display: block;
+ border: solid 1px;
+ border-radius: 4px 4px 0 0;
+ margin: 0; padding: .25em 2ex;
+ background: #EFF;
+ text-align: right;
+}
+form.namelist > fieldset:last-of-type {
+ border-radius: 0 0 4px 4px;
+}
+ul.namelist { margin: 0; padding: 0;}
+ul.namelist > li {
+ display: block;
+ border: solid 1px;
+ margin: -1px 0;
+ background: #FFF;
+}
+ul.namelist > li:nth-of-type(2n){ background: #EEE;}
+
+ul.namelist h2 {
+ font-size: 1em;
+ display: inline-block;
+ margin: 0;
+ padding: 0 1ex;
+ min-width: 30ex;
+}
+ul.namelist ul { margin: 0; padding: 0; display: inline-block;}
+ul.namelist ul li {
+ display: inline-block;
+ margin: 0 1ex 0 0;
+}
+EOF
+
+# vi:set filetype=css:
--- /dev/null
+# Copyright 2015 Paul Hänsch
+#
+# This file is part of Confetti.
+#
+# Confetti is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Confetti is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
+
+cat_listing(){
+ list_categories | while read cat; do
+ cat <<-END
+ <li>${cat}<button type="submit" name="remove" value="${cat}">$(l10n cat_remove)</button></li>
+ END
+ done
+}
+
+list_catsel(){
+ card="$1"
+ cats="$(get_categories $card)"
+
+ list_categories |while read cat; do
+ cat <<-END
+ <li><label><input type="checkbox" name="$card" value="$cat"
+ $(printf %s "$cats" |grep -qF "$cat" && printf %s 'checked="checked"')>${cat}</label></li>
+ END
+ done
+}
+
+display_catsel(){
+ card="$1"
+ cat <<-END
+ <li><h2>$(get_name "$card")</h2><ul>$(list_catsel "$card")</ul></li>
+ END
+}
+
+cat <<EOF
+<form class="categories" action="?action=edit_categories" method="POST">
+ <h1>$(l10n categories_label)</h1>
+ <input type="hidden" name="page" value="categories"/>
+ <ul>
+ $(cat_listing)
+ <li>
+ <input type="text" name="newcat" placeholder="$(l10n cat_newlabel)">
+ <button type="submit" name="add" value="add">$(l10n cat_add)</button>
+ </li>
+ </ul>
+</form>
+
+<form class="namelist" action="?action=update_categories" method="POST">
+ <fieldset>
+ <button type="submit" name="submit" value="submit">$(l10n cat_update)</button>
+ </fieldset>
+ <ul class="namelist">
+ $(listcards |while read card; do display_catsel "$card"; done )
+ </ul>
+ <fieldset>
+ <button type="submit" name="submit" value="submit">$(l10n cat_update)</button>
+ </fieldset>
+</form>
+
+EOF
+
--- /dev/null
+# Copyright 2014, 2015 Paul Hänsch
+#
+# This file is part of Confetti.
+#
+# Confetti is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Confetti is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with Confetti. If not, see <http://www.gnu.org/licenses/>.
+
+item_name[cat_remove]="-"
+item_name[cat_add]="+"
+item_name[cat_newlabel]="neue Kategorie"
+item_name[cat_update]="Zuweisungen übernehmen"
+item_name[categories_label]="Kategorien"
item_name[p_courses]="Kurse"
item_name[p_email]="Email"
item_name[p_error]="Fehler"
+item_name[p_categories]="Kategorien"
case $PROFILE in
medical)