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
  • maspect/amiv-admintool
  • emustafa/amiv-admintool
  • dvruette/amiv-admintool
  • amiv/amiv-admintool
4 results
Show changes
import m from 'mithril';
import { IconButton, Toolbar, ToolbarTitle, Button } from 'polythene-mithril';
import { Form } from 'amiv-web-ui-components';
import ItemView from './itemView';
import { icons } from './elements';
import { colors } from '../style';
export default class EditView extends ItemView {
/**
* Extension of ItemView to edit a data item
*
* Requires:
* - call constructor with vnode, resource, (valid, false by default)
* - vnode.attrs.onfinish has to be a callback function that is called after
* the edit is finished
* @param {object} vnode [as provided by mithril]
* @param {string} resource [the API resource of this view, e.g. 'events']
* @param {object} embedded [any embedding query that should be added
* to API requests for this resource]
*/
constructor(vnode) {
super(vnode);
// the form is valid in case that the item controller is in edit mode
const validInitially = this.controller.modus === 'edit';
// start a form to collect the submit data
this.form = new Form({}, validInitially, 4, Object.assign({}, this.controller.data));
this.form.setSchema(JSON.parse(JSON.stringify(this.handler.schema)));
}
/**
* Submit the changed version of this.data
*
* @param {Boolean} true if the data should be send as FormData instead of
* JSON. Necessary in cases where files are included in the
* changes.
*/
submit(data) {
return new Promise((resolve, reject) => {
let request;
if (this.controller.modus === 'edit') {
// this is a patch to an existing item
request = this.controller.patch(data);
} else {
request = this.controller.post(data);
}
request.then((response) => {
resolve(response);
}).catch((error) => {
// Process the API error
if ('_issues' in error) {
// there are problems with some fields, display them
Object.keys(error._issues).forEach((field) => {
this.form.errors[field] = [error._issues[field]];
this.form.valid = false;
});
// eslint-disable-next-line no-console
console.log(this.form.errors);
m.redraw();
reject(error);
} else {
// eslint-disable-next-line no-console
console.log(error);
}
});
});
}
beforeSubmit() {
if (Object.keys(this.form.data).length > 0) {
this.submit(this.form.data).then(() => this.controller.changeModus('view'));
} else {
this.controller.changeModus('view');
}
}
layout(children, buttonLabel = 'submit', wrapInContainer = true) {
return m('div', { style: { 'background-color': 'white' } }, [
m(Toolbar, { style: { 'background-color': colors.orange } }, [
m(IconButton, {
icon: { svg: { content: m.trust(icons.clear) } },
events: { onclick: () => { this.controller.cancel(); } },
}),
m(ToolbarTitle, `${((this.controller.modus === 'new') ? 'New' : 'Edit')}`
+ ` ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`),
m(Button, {
className: 'blue-button-filled',
extraWide: true,
label: buttonLabel,
// NOTE: Temporary fix as the `valid` flag of the `Form` instance does
// not work reliably. This ensures that the form can be submitted.
// disabled: !this.form.valid,
events: { onclick: () => { this.beforeSubmit(); } },
}),
]),
...!this.form.schema ? [''] : [
wrapInContainer && m('div.maincontainer', {
style: { height: 'calc(100vh - 130px)', 'overflow-y': 'scroll', padding: '10px' },
}, children),
!wrapInContainer && children,
],
]);
}
}
import m from 'mithril';
import { Chip } from 'amiv-web-ui-components';
export const icons = {
search: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>',
back: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>',
clear: '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',
ArrowRight: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/><path d="M0-.25h24v24H0z" fill="none"/></svg>',
ArrowDown: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z"/><path d="M0-.75h24v24H0z" fill="none"/></svg>',
iconUsersSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
iconEventSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
iconJobsSVG: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"/></svg>',
ArrowLeft: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/><path d="M0-.5h24v24H0z" fill="none"/></svg>',
checked: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>',
group: '<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>',
cloud: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></svg>',
star: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
email: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
department: '<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M0 0h48v48H0z" fill="none"/><path d="M24 14V6H4v36h40V14H24zM12 38H8v-4h4v4zm0-8H8v-4h4v4zm0-8H8v-4h4v4zm0-8H8v-4h4v4zm8 24h-4v-4h4v4zm0-8h-4v-4h4v4zm0-8h-4v-4h4v4zm0-8h-4v-4h4v4zm20 24H24v-4h4v-4h-4v-4h4v-4h-4v-4h16v20zm-4-16h-4v4h4v-4zm0 8h-4v4h4v-4z"/></svg>',
amivWheel: '<svg width="81.059502" height="80.056625" viewBox="0 0 82 82" id="svg2"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath18"><path d="m 0,849.563 1960.52,0 L 1960.52,0 0,0 0,849.563 z" id="path20" /></clipPath></defs><g transform="matrix(1.25,0,0,-1.25,-16.34525,92.96925)" id="g10"><g transform="scale(0.1,0.1)" id="g12"><g clip-path="url(#clipPath18)" id="g16"><path d="m 566.012,342.883 c -44.453,-61.184 -130.383,-74.797 -191.563,-30.344 -3.969,2.891 -7.719,5.957 -11.289,9.18 l 41.192,29.922 40.945,-56.375 51.351,117.707 37.684,-51.848 44.727,32.5 -40.387,55.598 41.469,30.132 c 19.257,-43.32 15.679,-95.437 -14.129,-136.472 m -235.504,23.465 c -19.887,43.554 -16.5,96.32 13.601,137.75 44.45,61.179 130.383,74.789 191.559,30.336 4.352,-3.161 8.391,-6.579 12.254,-10.125 l -41.762,-30.344 -40.558,55.82 -44.735,-32.5 40.563,-55.828 -0.067,-0.051 -127.726,-12.449 38.203,-52.578 -41.332,-30.031 z m 366.523,24.668 c 1.41,10.644 2.207,21.48 2.207,32.511 0,11.028 -0.797,21.86 -2.207,32.508 l -57.468,8.922 c -2.571,11.469 -6.196,22.711 -10.864,33.57 l 41.211,40.961 c -5.109,9.438 -10.828,18.676 -17.312,27.598 -6.481,8.922 -13.496,17.223 -20.899,25 l -51.679,-26.52 c -4.372,3.84 -8.93,7.532 -13.731,11.02 -4.84,3.512 -9.801,6.73 -14.84,9.719 l 9.258,57.351 c -9.676,4.641 -19.734,8.75 -30.238,12.16 -10.481,3.407 -21.039,5.993 -31.586,7.938 l -26.262,-51.918 c -11.742,1.07 -23.519,1.031 -35.199,-0.066 l -26.293,51.984 c -10.559,-1.945 -21.109,-4.531 -31.598,-7.938 -10.492,-3.41 -20.551,-7.519 -30.23,-12.148 l 9.269,-57.434 c -10.039,-5.925 -19.582,-12.859 -28.511,-20.707 l -51.746,26.559 c -7.407,-7.777 -14.422,-16.07 -20.903,-25 -6.492,-8.922 -12.211,-18.16 -17.32,-27.598 l 41.258,-41.011 c -4.715,-10.922 -8.36,-22.137 -10.887,-33.512 l -57.481,-8.93 c -1.421,-10.64 -2.218,-21.48 -2.218,-32.508 0,-11.031 0.797,-21.855 2.218,-32.511 l 57.563,-8.934 c 2.559,-11.445 6.168,-22.668 10.82,-33.496 L 240.09,307.57 c 5.109,-9.445 10.828,-18.683 17.32,-27.597 6.481,-8.926 13.488,-17.227 20.903,-25 l 51.675,26.523 c 4.41,-3.867 9,-7.59 13.84,-11.105 4.801,-3.485 9.723,-6.688 14.723,-9.657 l -9.258,-57.336 c 9.687,-4.636 19.746,-8.75 30.238,-12.156 10.489,-3.418 21.039,-5.996 31.598,-7.929 l 26.219,51.843 c 11.773,-1.093 23.57,-1.062 35.285,0.039 l 26.238,-51.894 c 10.559,1.945 21.117,4.523 31.598,7.941 10.504,3.406 20.551,7.52 30.238,12.149 l -9.246,57.285 c 10.078,5.957 19.648,12.898 28.617,20.789 l 51.621,-26.492 c 7.403,7.773 14.41,16.074 20.899,25 6.484,8.914 12.203,18.152 17.312,27.597 l -41.148,40.907 c 4.73,10.957 8.379,22.207 10.929,33.644 l 57.34,8.895" id="path30" style="fill:#f03d30;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></svg>',
menu: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>',
studydoc: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></svg>',
blacklist: '<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="#000000" d="M22.5,2.09C21.6,3 20.13,3.73 18.31,4.25C16.59,2.84 14.39,2 12,2C9.61,2 7.41,2.84 5.69,4.25C3.87,3.73 2.4,3 1.5,2.09C1.53,3.72 2.35,5.21 3.72,6.4C2.63,8 2,9.92 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,9.92 21.37,8 20.28,6.4C21.65,5.21 22.47,3.72 22.5,2.09M7.5,8.5L10.5,10C10.5,10.8 9.8,11.5 9,11.5C8.2,11.5 7.5,10.8 7.5,10V8.5M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23M16.5,10C16.5,10.8 15.8,11.5 15,11.5C14.2,11.5 13.5,10.8 13.5,10L16.5,8.5V10Z" /></svg>',
error: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/></svg>',
sortingArrow: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
};
// Property as specified by material design: small, grey title and larger
// darker content text below
// attrs is the title, children the text
// therefore, you can call it with m(Property, title, text)
export class Property {
view({ attrs: { title, leftAlign = true, ...restAttrs }, children }) {
return m('div', { style: { margin: '5px' }, ...restAttrs }, [
m('span', {
style: {
'margin-top': '10px',
'margin-bottom': '3px',
color: 'rgba(0, 0, 0, 0.54)',
},
}, m.trust(title)),
m('p', {
style: {
color: 'rgba(0, 0, 0, 0.87)',
'text-align': leftAlign ? 'left' : 'right',
},
}, children),
]);
}
}
export class selectGroup {
view(vnode) {
return m('div.form-group', { class: vnode.attrs.classes }, [
m(`label[for=${vnode.attrs.name}]`, vnode.attrs.title),
m(
`select[name=${vnode.attrs.name}][id=${vnode.attrs.name}].form-control`,
{ value: vnode.attrs.value, onchange: vnode.attrs.onchange },
vnode.attrs.options.map(option => m('option', option)),
),
]);
}
}
export class submitButton {
view({ attrs: { args, active, text } }) {
const argsCopy = args;
if (!active) {
argsCopy.disabled = 'disabled';
}
return m('div.btn', argsCopy, text);
}
}
export class FilterChip {
view({ attrs: { selected = false, onclick = () => { } }, children }) {
return m(Chip, {
'margin-left': '5px',
'margin-right': '5px',
background: selected ? '#aaaaaa' : '#dddddd',
svgBackground: '#aaaaaa',
textColor: selected ? '#000000' : '#999999',
svgColor: '#000000',
svg: selected ? icons.checked : null,
onclick,
onClick: onclick,
}, children);
}
}
import m from 'mithril';
import { IconButton, Toolbar, Dialog, Button } from 'polythene-mithril';
import { ButtonCSS } from 'polythene-css';
import { colors } from '../style';
import { loadingScreen } from '../layout';
import { icons } from './elements';
ButtonCSS.addStyle('.itemView-edit-button', {
color_light_background: colors.light_blue,
color_light_text: 'white',
});
ButtonCSS.addStyle('.itemView-delete-button', {
color_light_text: colors.amiv_red,
color_light_border: colors.amiv_red,
});
export default class ItemView {
/* Basic class to show a data item
*
* Required:
* - gets attribute 'controller' when rendered
*/
constructor({ attrs: { controller, onDelete } }) {
this.controller = controller;
this.handler = this.controller.handler;
this.data = this.controller.data;
this.resource = this.controller.resource;
if (!onDelete) this.onDelete = () => { m.route.set(`/${controller.resource}`); };
else this.onDelete = onDelete;
}
delete() {
Dialog.show({
body: 'Are you sure you want to delete this item?',
backdrop: true,
footerButtons: [
m(Button, {
label: 'Cancel',
events: { onclick: () => Dialog.hide() },
}),
m(Button, {
label: 'Delete',
events: {
onclick: () => {
Dialog.hide();
this.controller.handler.delete(this.data).then(this.onDelete);
},
},
})],
});
}
layout(children, buttons = []) {
if (!this.controller || !this.controller.data) return m(loadingScreen);
// update the data reference
this.data = this.controller.data;
return m('div', [
m(Toolbar, [
this.data._links.self.methods.indexOf('PATCH') > -1 && m('div', {
style: { width: 'calc(100% - 48px)' },
}, m('div.pe-button-row', [
m(Button, {
element: 'div',
className: 'itemView-edit-button',
label: `Edit ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`,
events: { onclick: () => { this.controller.changeModus('edit'); } },
}),
m(Button, {
label: `Delete ${this.resource.charAt(0).toUpperCase()}${this.resource.slice(1, -1)}`,
className: 'itemView-delete-button',
border: true,
events: { onclick: () => this.delete() },
}),
...buttons,
])),
m(IconButton, {
style: { 'margin-left': 'auto', 'margin-right': '0px' },
icon: { svg: { content: m.trust(icons.clear) } },
events: { onclick: () => { this.controller.cancel(); } },
}),
]),
m('div', {
style: { height: 'calc(100vh - 130px)', 'overflow-y': 'scroll' },
}, children),
]);
}
}
import m from 'mithril';
import infinite from 'mithril-infinite';
import { List, ListTile, Toolbar, Search, Button, Icon } from 'polythene-mithril';
import 'polythene-css';
import { styler } from 'polythene-core-css';
import { FilterChip, icons } from './elements';
const tableStyles = [
{
'.toolbar': {
'grid-row': 1,
display: 'flex',
},
'.tableTile': {
padding: '10px',
'border-bottom': '1px solid rgba(0, 0, 0, 0.12)',
'align-items': 'center',
},
},
];
styler.add('tableview', tableStyles);
export default class TableView {
/* Shows a table of objects for a given API resource.
*
* Required attributes:
* vnode: { attrs: { controller, titles, keys } }
* - controller: a listcontroller for some API resource data
* - titles: the titles of the table
* - keys: Keys of this resource to display as columns, e.g. ['firstname']
* Works with embedded resources, i.e. if you add
* { embedded: { event: 1 } } to a list of eventsignups,
* you can display event.title_de as a table key
* - filters: list of list of objects, each inner list is a group of mutual exclusive
* filters.
* A filter can have properties 'name', 'query' and optionally 'selected' for
* the initial selection state.
*/
constructor({
attrs: {
keys,
titles,
tileContent,
filters = null,
clickOnRows = (data) => { m.route.set(`/${data._links.self.href}`); },
clickOnTitles = (controller, title) => { controller.setSort([[title, 1]]); },
},
}) {
this.search = '';
this.tableKeys = keys || [];
this.tableTitles = titles;
this.tileContent = tileContent;
this.clickOnRows = clickOnRows;
this.clickOnTitles = clickOnTitles;
this.searchValue = '';
// make a copy of filters so we can toggle the selected status
this.filters = filters ? filters.map(
filterGroup => filterGroup.map(filter => Object.assign({}, filter)),
) : null;
}
/*
* initFilterIdxs lets you specify the filters that are active at initialization.
* They are specified as index to the nexted filterGroups array.
*/
oninit({ attrs: { controller, initFilterIdxs = [] } }) {
if (this.filters) {
initFilterIdxs.forEach((filterIdx) => {
this.filters[filterIdx[0]][filterIdx[1]].selected = true;
});
// update filters in controller
controller.setFilter(this.getSelectedFilterQuery());
}
}
getItemData(data) {
return this.tableKeys.map((key) => {
// Access a nested key, indicated by dot-notation
let nestedData = data;
key.split('.').forEach((subKey) => { nestedData = nestedData[subKey]; });
return m(
'div',
{ style: { width: `${98 / this.tableKeys.length}%` } },
nestedData,
);
});
}
item() {
return data => m(ListTile, {
className: 'themed-list-tile',
hoverable: this.clickOnRows,
compactFront: true,
compact: true,
content: m('div', {
onclick: () => {
if (this.clickOnRows) this.clickOnRows(data);
},
className: 'tableTile',
style: { width: '100%', display: 'flex' },
}, this.tileContent ? this.tileContent(data) : this.getItemData(data)),
});
}
getSelectedFilterQuery() {
// produce a list of queries from the filters that are currently selected
const selectedFilters = [].concat(...this.filters.map(filterGroup => filterGroup.filter(
filter => filter.selected === true,
).map(filter => filter.query)));
// now merge all queries into one new object
return Object.assign({}, ...selectedFilters);
}
// Display an arrow at the table title that allows sorting
arrowOrNot(controller, title) {
const titleText = title.width ? title.text : title;
if (!controller.sort) return false;
let i;
for (i = 0; i < this.tableTitles.length; i += 1) {
const tableTitlei = this.tableTitles[i].width
? this.tableTitles[i].text : this.tableTitles[i];
if (tableTitlei === titleText) break;
}
return this.tableKeys[i] === controller.sort[0][0];
}
view({
attrs: {
controller,
titles,
onAdd = false,
buttons = [],
tableHeight = false,
},
}) {
return m('div.tabletool', {
style: {
display: 'grid',
height: '100%',
'grid-template-rows': this.filters
? '48px 40px calc(100% - 120px)' : '48px calc(100% - 80px)',
'background-color': 'white',
},
}, [
m(Toolbar, {
className: 'toolbar',
compact: true,
content: [
m(Search, {
textfield: {
label: 'Search',
onChange: ({ value }) => {
// this is called not only if the value changes, but also the focus.
// we only want to change the search of the value is changed, therefore we
// have to track changes in the search value
if (value !== this.searchValue) controller.debouncedSearch(value);
this.searchValue = value;
},
},
fullWidth: false,
}),
...buttons.map(b => m(Button, {
className: 'blue-button',
style: {
'margin-right': '5px',
},
events: {
onclick: b.onclick,
},
label: b.text,
})),
onAdd ? m(Button, {
className: 'blue-button',
borders: true,
label: 'Add',
events: { onclick: () => { onAdd(); } },
}) : '',
],
}),
// please beare with this code, it is the only way possible to track the selection
// status of all the filters of the same group and make sure that they are really
// mutually exclusive (that way when you click on one filter in the group, the other
// ones in this group will be deselected)
this.filters && m('div', {
style: {
height: '50px',
'overflow-x': 'auto',
'overflow-y': 'hidden',
'white-space': 'nowrap',
padding: '0px 5px',
},
}, [].concat(['Filters: '], ...[...this.filters.keys()].map(
filterGroupIdx => [...this.filters[filterGroupIdx].keys()].map((filterIdx) => {
const thisFilter = this.filters[filterGroupIdx][filterIdx];
return m(FilterChip, {
selected: thisFilter.selected,
onclick: () => {
if (!thisFilter.selected) {
// set all filters in this group to false
[...this.filters[filterGroupIdx].keys()].forEach((i) => {
this.filters[filterGroupIdx][i].selected = false;
});
// now set this filter to selected
this.filters[filterGroupIdx][filterIdx].selected = true;
} else {
this.filters[filterGroupIdx][filterIdx].selected = false;
}
// update filters in controller
controller.setFilter(this.getSelectedFilterQuery());
},
}, thisFilter.name);
}),
))),
m(List, {
className: 'scrollTable',
style: {
'grid-row': this.filters ? 3 : 2,
...tableHeight ? { height: tableHeight } : {},
},
tiles: [
m(ListTile, {
className: 'tableTile',
hoverable: this.clickOnTitles,
content: m(
'div',
{ style: { width: '100%', display: 'flex' } },
// Either titles is a list of titles that are distributed equally,
// or it is a list of objects with text and width
titles.map((title, i) => m(
'div', {
onclick: () => {
if (this.clickOnTitles && this.tableKeys[i]) {
this.clickOnTitles(controller, this.tableKeys[i]);
}
},
style: { width: title.width || `${98 / this.tableKeys.length}%` },
},
[title.width ? title.text : title,
this.arrowOrNot(controller, title)
? m(Icon, { svg: { content: m.trust(icons.sortingArrow) } }) : ''],
)),
),
}),
m(infinite, controller.infiniteScrollParams(this.item())),
],
}),
]);
}
}
<style>
.bk-bg {
width: 100%;
height: calc(100vh - 64px);
background-image: url("res/bg/cab.jpg");
background-size: cover;
background-position: center center;
justify-content: center;
align-items: center;
display: flex;
}
.bk-bg>.mdl-card {
margin: 15px;
}
.bk-bg>.mdl-card>.mdl-card__title {
height: 180px;
background-position: cover;
background-position: center center;
background-repeat: no-repeat;
box-shadow: 0 6px 15px -3px rgba(0, 0, 0, 0.4);
}
.bk-bg>.mdl-card:first-child>.mdl-card__title {
background: url("res/bg/coffee_a.png");
}
.bk-bg>.mdl-card:last-child>.mdl-card__title {
background: url("res/bg/beer_a.png");
}
.bk-bg>.mdl-card>.mdl-card__title h2 {
background: rgba(255, 255, 255, 0.8);
padding: 2px;
border-radius: 3px;
}
.bk-bg .mdl-data-table {
width: 100%;
}
</style>
<div class="bk-bg">
<!-- Coffee -->
<div class="demo-card-wide mdl-card mdl-shadow--2dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text mdl-shadow--2dp">Coffee</h2>
</div>
<div class="mdl-card__supporting-text">
<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">SuperHero</th>
<th>Coffee</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect">Menu</a>
</div>
</div>
<!-- Beer -->
<div class="demo-card-wide mdl-card mdl-shadow--2dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text mdl-shadow--2dp">Beer</h2>
</div>
<div class="mdl-card__supporting-text">
<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">SuperHero</th>
<th>Beers</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="mdl-card__actions mdl-card--border">
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect">Stats</a>
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect">Lock Beer Machine</a>
</div>
</div>
</div>
<script>
var superheroes = [
[
['Anon', 34],
['Trololo', 23],
['Random Dude', 13]
],
[
['Anon', 138],
['Trololo', 97],
['Random Dude', 72]
]
];
var i = 0;
$('.mdl-card__supporting-text tbody').each(function() {
$(this).html('');
for (var n = 0; n < superheroes[i].length; n++)
$(this).append('<tr><td class="mdl-data-table__cell--non-numeric">' + superheroes[i][n][0] + '</td><td>' + superheroes[i][n][1] + '</td></tr>');
i++;
})
</script>
<div class="events-table-wrapper">
<div class="tools-full-height">
<table class="table table-hover events-table" id="events-table">
<thead>
<tr>
<th>Title</th>
<th>Date</th>
<th>on website</th>
<th>spots</th>
<th>signups</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<!-- modal for creating new events, easier to do it this way than js-->
<div class="modal fade" id="event-modal" role="dialog" data-etag="" data-backdrop="static"
data-keyboard="false" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" >&times;</button>
<h4 class="modal-title" id="event-modal-title"></h4>
</div>
<div class="modal-body">
<form id="event-modal-form">
<div class="form-group">
<label for="title_de">Title</label>
<input type="text" class="form-control" id="title_de"></input>
</div>
<div class="form-group">
<label for="description_de">Description</label>
<textarea type="text" class="form-control" rows="3" id="description_de"></textarea>
</div>
<div class="form-group">
<label for="catchphrase_de">Catchphrase</label>
<input type="text" class="form-control" id="catchphrase_de"></input>
</div>
<!-- <div class="container"> -->
<!-- <div class="col-md-3"> -->
<div class="form-group">
<label for="time_start">Start Time</label>
<div class="input-group date" id="time_start">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<!-- </div> -->
<!-- <div class="col-md-3"> -->
<div class="form-group">
<label for="time_end">End Time</label>
<div class="input-group date" id="time_end">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<div class="form-group">
<label for="time_start">Start Advertising</label>
<div class="input-group date" id="time_advertising_start">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<!-- </div> -->
<!-- <div class="col-md-3"> -->
<div class="form-group">
<label for="time_end">End Advertising</label>
<div class="input-group date" id="time_advertising_end">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<!-- </div> -->
<!-- </div> -->
<label class="checkbox-inline">
<input type="checkbox" id="signup-required" value="">No Signup
</label>
<label class="checkbox-inline">
<input type="checkbox" id="no-signup-limit" value="">No Signup Limit
</label>
<div class="form-group">
<label for="spots">Spots</label>
<input type="number" class="form-control" min="-1" id="spots"></input>
</div>
<!-- <div class="container"> -->
<!-- <div class="col-md-3"> -->
<div class="form-group">
<label for="time_register_start">Start of Registration</label>
<div class="input-group date" id="time_register_start">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<!-- </div> -->
<!-- <div class="col-md-3"> -->
<div class="form-group">
<label for="time_register_end">End of Registration</label>
<div class="input-group date" id="time_register_end">
<input type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon-calendar glyphicon"></span>
</span>
</div>
</div>
<!-- </div> -->
<!-- </div> -->
<label class="checkbox-inline">
<input type="checkbox" id="allow_email_signup" value="">Only amiv Members
</label>
<div class="form-group">
<label for="location">Location</label>
<input type="text" class="form-control" id="location"></input>
</div>
<div class="form-group">
<label for="price">Price [CHF]</label>
<input type="number" class="form-control" min="0" id="price"></input>
</div>
<div>
<label class="checkbox-inline">
<input type="checkbox" id="show_website" value="">Show on Webstite (requires banner image and title)
</label>
</div>
<div>
<label class="checkbox-inline">
<input type="checkbox" id="show_infoscreen" value="">Show ond Infoscreen (requires infoscreen image)
</label>
</div>
<div>
<label class="checkbox-inline">
<input type="checkbox" id="show_announce" value="">Show in Announce (requires stuff)
</label>
</div>
<div class="form-group">
<label for="price">Priority [1-10]</label>
<input type="number" class="form-control" min="0" id="priority" value=5></input>
</div>
<div class="form-group">
<label for="description_de">Additional Fields (JSON schema)</label>
<textarea type="text" class="form-control" rows="3" id="additional_fields"></textarea>
</div>
<div class="form-group">
<label for="img_infoscreen">Infoscreen Image</label>
<input type="file" id="img_infoscreen" name="myFile"/>
<img src="" id="actual_img_infoscreen">
</div>
<div class="form-group">
<label for="img_banner">Banner Image</label>
<input type="file" id="img_banner"/>
<img src="" id="actual_img_banner">
</div>
<div class="form-group">
<label for="img_poster">Poster Image</label>
<input type="file" id="img_poster"/>
<img src="" id="actual_img_poster">
</div>
<div class="form-group">
<label for="img_thumbnail">Thumbnail</label>
<input type="file" id="img_thumbnail"/>
<img src="" id="actual_img_thumbnail">
</div>
<button type="button" class "btn" data-toggle="collapse" data-target="#english-collapse">show english fields</button>
<div id="english-collapse" class="collapse">
<div class="form-group">
<label for="title_en">Title english</label>
<input type="text" class="form-control" id="title_en"></input>
</div>
<div class="form-group">
<label for="description_en">Description english</label>
<textarea type="text" class="form-control" rows="3" id="description_en"></textarea>
</div>
<div class="form-group">
<label for="catchphrase_en">Catchphrase english</label>
<input type="text" class="form-control" id="catchphrase_en"></input>
</div>
</div>
<div id="additional_info">
</div>
<!-- <input type="submit"> -->
</form>
</div>
<div class="modal-footer" id="event-modal-footer">
<!-- footer content here -->
</div>
</div>
</div>
</div>
<style>
.events-table-wrapper {
position: relative;
}
.events-table-wrapper>div {
overflow: auto;
}
#event-modal {
overflow: auto;
}
#event-modal .checkbox-inline {
margin-bottom: 10px;
}
.users-sidebar {
background: #fff;
}
.tooltip-inner {
white-space: nowrap;
max-width: none;
}
</style>
<script type="text/javascript">
var events = {
API_url: 'http://192.168.1.100',
somethingChanged: false,
showInTable: ['title_de', 'time_start', 'show_website', 'spots', 'signup_count'],
curEventData: null,
// Page
page: {
max: Number.MAX_VALUE,
cur: function() {
return parseInt(tools.mem.session.get('curPage'));
},
set: function(num) {
num = parseInt(num);
if (num > 0 && num < events.page.max + 1)
tools.mem.session.set('curPage', num);
$('.events-cur-page-cont').html(events.page.cur());
events.get();
},
inc: function() {
events.page.set(events.page.cur() + 1);
},
dec: function() {
events.page.set(events.page.cur() - 1);
}
},
//Sorting
sort: {
cur: function() {
return tools.mem.session.get('curSort');
},
set: function(sort) {
tools.mem.session.set('curSort', sort);
events.get();
},
inv: function() {
var tmp = events.sort.cur();
if (tmp.charAt(0) == '-')
events.sort.set(tmp.slice(1));
else
events.sort.set('-' + tmp);
}
},
//Searching
search: {
cur: function() {
return tools.mem.session.get('search');
},
set: function(dom, val) {
tools.mem.session.set('search', dom + '==' + val);
events.page.set(1);
},
clr: function() {
tools.mem.session.set('search', '');
events.page.set(1);
},
},
get: function() {
$('#wheel-logo').css('transform', 'rotate(360deg)');
console.log('getting events...');
amivcore.events.GET({
data: {
'max_results': '50',
page: events.page.cur(),
sort: events.sort.cur(),
where: events.search.cur(),
}
}, function(ret) {
console.log(ret);
if (ret === undefined || ret['_items'].length == 0) {
tools.log('No Data', 'w');
// Clear table from previous contentent
$('.events-table tbody').html('');
return;
}
events.meta = ret['_meta'];
events.page.max = Math.ceil(events.meta.total / events.meta.max_results);
$('.events-page-max-cont').html(events.page.max);
// Clear table from previous contentent
$('.events-table tbody').html('');
for (var n in ret['_items']) {
var tmp = '';
events.showInTable.forEach(function(i) {
tmp += '<td>' + ret['_items'][n][i] + '</td>';
});
$('.events-table tbody').append('<tr data-id="' + ret['_items'][n]['_id'] + '">' + tmp + '</tr>');
}
$('.events-table tbody tr').click(events.showDetails);
$('#wheel-logo').css('transform', 'rotate(0deg)');
});
},
createEvent: function() {
$("#event-modal-title").text("Create Event");
$('#event-modal-footer').html('<button type="button" class="btn btn-default" data-dismiss="modal">Close</button><button type="button" class="btn btn-primary" onclick="events.submitEvent(true)">Submit</button>');
$('#event-modal').modal('show');
},
//show details of an event in a modal
//TODO: fill the more beautiful event-modal
showDetails: function() {
somethingChanged = false;
console.log($(this).attr('data-id'));
amivcore.events.GET({
id: $(this).attr('data-id')
}, function(ret) {
curEventData = ret;
console.log(curEventData);
etag = ret['_etag'];
$("#event-modal-title").text("Edit Event");
$('#event-modal-footer').html('<button type="button" class="btn btn-default" data-dismiss="modal">Close</button><button type="button" class="btn btn-primary" onclick="events.submitEvent(false)">update</button><button type="button" class="btn btn-danger" onclick="events.deleteEvent()">Delete</button>');
imageData = ['img_infoscreen', 'img_thumbnail', 'img_poster', 'img_banner'];
for (i = 0; i < imageData.length; i++){
if (ret[imageData[i]]){
console.log(events.API_url + ret[imageData[i]]['file']);
$('#actual_' + imageData[i]).attr('src', events.API_url + ret[imageData[i]]['file']);
}
}
//fill fields of the form with content that has the same ID
$('#event-modal-form').find('input, textarea').val(function (index, value) {
if (this.type != 'file')
return ret[this.id];
});
//array of elements that are represented by checkboxes
var booleanEventData = ['no-signup-limit', 'allow_email_signup', 'show_website', 'show_infoscreen', 'show_announce'];
var dateEventData = ['time_start', 'time_end', 'time_register_start', 'time_register_end', 'time_advertising_start', 'time_advertising_end'];
//set the datepickers
for (i = 0; i < dateEventData.length; i++){
if (ret[dateEventData[i]] != null){
$('#' + dateEventData[i]).data("DateTimePicker").date(new Date(ret[dateEventData[i]]));
}
}
for (i = 0; i < booleanEventData.length; i++){
$("#" + booleanEventData[i]).prop('checked', ret[booleanEventData[i]]);
}
//edge cases (signup required is inverted)
// if (spots == null){
$('#signup-required').prop('checked', !ret['signup-required']);
// }
$('#event-modal').modal('show');
});
},
deleteEvent: function() {
console.log(curEventData._etag);
if (confirm("Delete " + curEventData.title_de + "?")) {
amivcore.events.DELETE({
id: curEventData._id,
header: {
// 'If-Match': $('#event-modal').attr('data-etag')
'If-Match': curEventData._etag
}
}, function(response) {
console.log(response);
});
events.get();
tools.log('Event deleted', 'w');
tools.modalClose();
} else {
tools.log('Event not Deleted', 'i');
}
},
showSignups: function(curEventData) {
var tmp = '<table class="table table-hover events-edit-table" data-etag="' + curEventData['_etag'] + '"><tbody>';
for (var user in curEventData['signups']) {
tmp += '<tr><td>' + user + '</td><td contenteditable>' + curEventData['signups'][cur] + '</td></tr>';
}
tmp += '</tbody></table>';
tools.modal({
head: curEventData.title_de,
body: tmp,
button: {
'Update': {
type: 'success',
close: false
//callback
}
}
});
},
submitEvent: function(isNew) {
console.log("submitting new event");
var newEvent = {
data: {}
};
newEvent["data"]["title_de"] = setNullIfEmpty($("#title_de").val());
newEvent["data"]["description_de"] = setNullIfEmpty($("#description_de").val());
newEvent["data"]["catchphrase_de"] = setNullIfEmpty($("#catchphrase_de").val());
if (!($("#time_start").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_start"] = $("#time_start").data("DateTimePicker").date().toISOString().split('.')[0]+"Z";
}
if (!($("#time_end").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_end"] = $("#time_end").data("DateTimePicker").date().toISOString().split('.')[0]+"Z";
}
if (!($("#time_advertising_start").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_advertising_start"] = $("#time_advertising_start").data("DateTimePicker").date().toISOString().split('.')[0]+"Z";
}
if (!($("#time_advertising_end").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_advertising_end"] = $("#time_advertising_end").data("DateTimePicker").date().toISOString().split('.')[0]+"Z";
}
if (!$("#signup-required").is(":checked")) {
if ($("#no-signup-limit").is(":checked")) {
newEvent["data"]["spots"] = 0;
} else {
if ($("#spots").val() === "") {
tools.log("Please specify a number of Spots", "e");
return;
}
newEvent["data"]["spots"] = parseInt($("#spots").val());
}
if (!($("#time_register_start").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_register_start"] = $("#time_register_start").data("DateTimePicker").date();
} else {
tools.log('field "Start of Registration" required', 'e');
return;
}
if (!($("#time_register_end").data("DateTimePicker").date() == null)) {
newEvent["data"]["time_register_end"] = $("#time_register_end").data("DateTimePicker").date();
} else {
tools.log('field "End of Registration" required', 'e');
return;
}
newEvent["data"]["allow_email_signup"] = $("#allow_email_signup").is(':checked');
} else {
newEvent["data"]["spots"] = null;
}
newEvent["data"]["location"] = setNullIfEmpty($("#location").val());
if (!($("#price").val() === "")) {
newEvent["data"]["price"] = Math.floor((parseFloat($("#price").val()) * 100));
}
newEvent["data"]["show_website"] = $("#show_website").is(':checked');
newEvent["data"]["show_infoscreen"] = $("#show_infoscreen").is(':checked');
newEvent["data"]["show_announce"] = $("#show_announce").is(':checked');
newEvent["data"]["priority"] = (parseInt($("#priority").val()));
newEvent["data"]["additional_fields"] = setNullIfEmpty($("#additional_fields").val());
newEvent["data"]["title_en"] = setNullIfEmpty($("#title_en").val());
newEvent["data"]["description_en"] = setNullIfEmpty($("#description_en").val());
newEvent["data"]["catchphrase_en"] = setNullIfEmpty($("#catchphrase_en").val());
console.log(newEvent);
form = new FormData();
// for (data in newEvent.data){
// form.append(data, newEvent['data'][data]);
// }
var imageData = ['img_infoscreen', 'img_thumbnail', 'img_poster', 'img_banner'];
for (i = 0; i < imageData.length; i++){
if ($('#' + imageData[i])[0].files[0] != undefined)
form.append(imageData[i], $('#' + imageData[i])[0].files[0]);
}
console.log(JSON.stringify(newEvent));
if(isNew) {
var response = amivcore.events.POST(form, function(ret) {
if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
else {
events.uploadCallback();
}
});
}
else {
newEvent['header'] = {};
newEvent['header']['If-Match'] = curEventData._etag;
newEvent['id'] = curEventData._id;
console.log(newEvent);
var response = amivcore.events.PATCH(newEvent, function(ret) {
if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
else {
events.uploadCallback(form);
}
});
}
console.log(response);
},
//images need to be uploaded seperately after POSTing using PATCH
uploadCallback: function(form){
amivcore.getEtag('events', curEventData._id, function(ret){
$.ajax({
url: events.API_url + '/events/' + curEventData._id,
headers: {'Authorization':'root', 'If-Match': ret},
data: form,
type: 'PATCH',
// THIS MUST BE DONE FOR FILE UPLOADING
contentType: false,
processData: false,
// ... Other options like success and etc
success: function(data){
console.log(data);
tools.log('Event Added', 's');
$('#event-modal').modal('hide');
$("#event-modal-form").trigger('reset');
events.get();
}
});
});
}
}
//setting up the date time picker
$(function() {
$('#time_start').datetimepicker({
locale: "de",
sideBySide: true
});
$('#time_end').datetimepicker({
locale: "de",
useCurrent: false, //Important! See issue #1075aa
sideBySide: true
});
$('#time_advertising_start').datetimepicker({
locale: "de",
sideBySide: true
});
$('#time_advertising_end').datetimepicker({
locale: "de",
useCurrent: false, //Important! See issue #1075aa
sideBySide: true
});
$('#time_register_start').datetimepicker({
locale: "de",
sideBySide: true
});
$('#time_register_end').datetimepicker({
locale: "de",
useCurrent: false, //Important! See issue #107534
sideBySide: true
});
$("#time_register_start").on("dp.change", function(e) {
$('#time_register_end').data("DateTimePicker").minDate(e.date);
});
$("#time_register_end").on("dp.change", function(e) {
$('#time_register_start').data("DateTimePicker").maxDate(e.date);
});
$("#time_advertising_start").on("dp.change", function(e) {
$('#time_advertising_end').data("DateTimePicker").minDate(e.date);
});
$("#time_advertising_end").on("dp.change", function(e) {
$('#time_advertising_start').data("DateTimePicker").maxDate(e.date);
});
$("#time_start").on("dp.change", function(e) {
$('#time_end').data("DateTimePicker").minDate(e.date);
});
$("#time_end").on("dp.change", function(e) {
$('#time_start').data("DateTimePicker").maxDate(e.date);
});
});
$('#signup-required').click(function() {
$('#no-signup-limit').attr('disabled', this.checked);
$('#spots').attr('disabled', this.checked);
$('#time_register_end>input').attr('disabled', this.checked);
$('#time_register_start>input').attr('disabled', this.checked);
});
$('#no-signup-limit').click(function() {
$('#spots').attr('disabled', this.checked);
});
$('#event-modal').on('hidden.bs.modal', function () {
// do something…
$('#event-modal img').attr('src', '');
$("#event-modal-form").trigger('reset');
})
// tools in the top bar
tools.ui.menu({
'<span class="glyphicon glyphicon-plus" data-toggle="tooltip" aria-hidden="true" title="Create new Event" data-placement="bottom"></span>': {
callback: events.createEvent
},
'<span class="glyphicon glyphicon-refresh" aria-hidden="true" data-toggle="tooltip" title="Refresh" data-placement="bottom"></span>': {
callback: events.get
},
'<span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>': {
callback: events.page.dec
},
'<span class="events-cur-page-cont" aria-hidden="true"></span> / <span class="events-page-max-cont" aria-hidden="true"></span>': {
callback: function() {
tools.modal({
head: 'Go To Page:',
body: '<div class="form-group"><input type="number" value="' + events.page.cur() + '" class="form-control events-go-page"></div>',
button: {
'Go': {
type: 'success',
close: true,
callback: function() {
events.page.set($('.events-go-page').val());
},
}
}
});
}
},
'<span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span>': {
callback: events.page.inc
},
'<span class="glyphicon glyphicon-sort" aria-hidden="true" data-toggle="tooltip" title="Sort" data-placement="bottom"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control events-sort-select">';
var cur = events.sort.cur();
['_id', 'title_de', 'description_de', 'time_start', 'time_register_start', 'time_end', 'time_register_end', 'show_website', 'show_announce', 'show_infoscreen', 'price', '_updated', 'location'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>&#8673; ' + i + '</option>';
tmp += '<option value="-' + i + '"' + (('-' + i == cur) ? ' selected' : '') + '>&#8675; ' + i + '</option>';
});
tmp += '</select></div>';
tools.modal({
head: 'Sort',
body: tmp,
button: {
'Sort': {
type: 'success',
close: true,
callback: function() {
events.sort.set($('.events-sort-select').val());
}
}
}
});
}
},
'<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" title="Search" data-placement="bottom"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control events-search-select">';
var cur = events.search.cur();
if (cur === null || cur == '')
cur = '';
else
cur = cur.split('==')[1];
['_id', 'title_de', 'description_de', 'title_en', 'description_en', 'time_start', 'time_register_start', 'time_end', 'time_register_end', 'show_website', 'show_announce', 'show_infoscreen', 'price', '_updated', 'location']
.forEach(
function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>' + i + '</option>';
});
tmp += '</select><br><input type="text" value="' + cur + '" class="form-control events-search-val"></div>';
tools.modal({
head: 'Search',
body: tmp,
button: {
'Clear': {
type: 'warning',
close: true,
callback: events.search.clr,
},
'Search': {
type: 'success',
close: true,
callback: function() {
events.search.set($('.events-search-select').val(), $('.events-search-val').val());
}
},
}
})
}
}
});
if (events.page.cur() === null || isNaN(events.page.cur()))
events.page.set(1);
else
events.page.set(events.page.cur());
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
$('#event-modal-form').on('keyup change', 'input, select, textarea, span ', function(){
console.log('changed shit');
events.somethingChanged = true;
});
});
function setNullIfEmpty(formData) {
if (formData === "") {
return null;
}
return formData;
}
</script>
<div>
<table class="table table-hover groups-table">
<thead>
<tr>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script type="text/javascript">
var groups = {
showInTable: ['name'],
curUserData: null,
// Page
page: {
max: Number.MAX_VALUE,
cur: function() {
return parseInt(tools.mem.session.get('curPage'));
},
set: function(num) {
num = parseInt(num);
if (num > 0 && num < groups.page.max + 1)
tools.mem.session.set('curPage', num);
$('.groups-cur-page-cont').html(groups.page.cur());
groups.get();
},
inc: function() {
groups.page.set(groups.page.cur() + 1);
},
dec: function() {
groups.page.set(groups.page.cur() - 1);
}
},
//Sorting
sort: {
cur: function() {
return tools.mem.session.get('curSort');
},
set: function(sort) {
tools.mem.session.set('curSort', sort);
groups.get();
},
inv: function() {
var tmp = groups.sort.cur();
if (tmp.charAt(0) == '-')
groups.sort.set(tmp.slice(1));
else
groups.sort.set('-' + tmp);
}
},
//Searching
search: {
cur: function() {
return tools.mem.session.get('search');
},
set: function(dom, val) {
tools.mem.session.set('search', dom + '==' + val);
groups.page.set(1);
},
clr: function() {
tools.mem.session.set('search', '');
groups.page.set(1);
},
},
// Get groups
get: function() {
amivcore.groups.GET({
data: {
'max_results': '50',
page: groups.page.cur(),
sort: groups.sort.cur(),
where: groups.search.cur(),
}
}, function(ret) {
console.log(ret);
if (ret === undefined || ret['_items'].length == 0) {
tools.log('No Data', 'w');
return;
}
groups.meta = ret['_meta'];
groups.page.max = Math.ceil(groups.meta.total / groups.meta.max_results);
$('.groups-page-max-cont').html(groups.page.max);
// Clear table from previous contentent
$('.groups-table thead tr, .groups-table tbody').html('');
groups.showInTable.forEach(function(i) {
$('.groups-table thead tr').append('<th>' + i + '</th>');
});
for (var n in ret['_items']) {
var tmp = '';
groups.showInTable.forEach(function(i) {
tmp += '<td>' + ret['_items'][n][i] + '</td>';
});
$('.groups-table tbody').append('<tr data-id="' + ret['_items'][n]['_id'] + '">' + tmp + '</tr>');
}
$('.groups-table tbody tr').click(groups.showDetails);
});
},
// Make Modal with editable table data
showDetails: function() {
amivcore.groups.GET({
id: $(this).attr('data-id')
}, function(ret) {
console.log(ret);
curUserData = ret;
var tmp = '<div class="groups-edit-cont" data-etag="' + ret['_etag'] + '" data-id="' + ret['_id'] + '">';
for (var cur in ret)
if (cur.charAt(0) != '_')
if (cur == 'user_subscribers') {
tmp += '<p><strong>Subscribed: <kbd>' + ret[cur].length + '</kbd> <kbd class="groups-show-users"><span class="glyphicon glyphicon-edit" aria-hidden="true"></span></kbd></strong></p>';
} else {
switch (amivcore.getParamType('groups', cur)) {
case 'boolean':
tmp += '<div class="checkbox"><label><input type="checkbox" value="' + ret[cur] + '" name="' + cur + '">' + cur + '</label></div>';
break;
case 'integer':
tmp += '<div class="form-group"><label>' + cur + ':</label><input type="number" value="' + ret[cur] + '" class="form-control" name="' + cur + '" min="0" step="1"></div>';
break;
default:
tmp += '<div class="form-group"><label>' + cur + ':</label><input type="text" value="' + ret[cur] + '" class="form-control" name="' + cur + '"></div>';
break;
}
}
tmp += '</div>';
tools.modal({
head: ret.firstname + ' ' + ret.lastname,
body: tmp,
button: {
'Delete': {
type: 'danger',
callback: function() {
if (confirm('Fo\' shizzle my nizzle? U fo\' real?'))
amivcore.groups.DELETE({
id: $('.groups-edit-cont').first().attr('data-id'),
header: {
'If-Match': $('.groups-edit-cont').attr('data-etag')
},
}, function(ret) {
if (ret === undefined) {
tools.log('Group successfully deleted', 's');
groups.get();
tools.modalClose();
} else {
tools.log('Error', 'e');
}
});
}
},
'Update': {
type: 'success',
close: true,
callback: groups.inspect,
},
}
});
});
$('.groups-show-users').off('click').on('click', function() {
console.log($('groups-edit-cont').first().attr('data-id'));
});
},
// Check wether changes were maid and saves it in that case
inspect: function() {
var newUserData = {};
$('.groups-edit-cont tr').each(function() {
newUserData[$(this).children('td:nth-child(1)').html()] = $(this).children('td:nth-child(2)').html();
});
var changed = false,
curUserDataChanged = {};
for (var i in newUserData) {
if (newUserData[i] != String(curUserData[i])) {
changed = true;
curUserDataChanged[i] = newUserData[i];
}
}
if (changed) {
amivcore.groups.PATCH({
id: curUserData._ id,
header: {
'If-Match': $('.groups-edit-cont').attr('data-etag')
},
data: curUserDataChanged
}, function() {
tools.log('User Updated', 's');
groups.get();
});
}
},
//Make new user
add: function() {
var tmp = '<div class="row groups-user-add-form">' +
'<div class="form-group"><label for="groups-name">Name:</label><input type="text" class="form-control" name="name" id="groups-name"></div>' +
'<div class="form-group"><label for="groups-moderator">Group Admin:</label><input type="text" class="form-control" id="groups-moderator" name="moderator_id"></div>' +
'<label class="checkbox-inline"><input type="checkbox" name="has_zoidberg_share">Has Zoidberg share</label>' +
'<label class="checkbox-inline pull-right"><input type="checkbox" name="allow_self_enrollment">Self-Enrollment</label>' +
'</div>';
tools.modal({
head: 'Create Group',
body: tmp,
button: {
'Add': {
type: 'success',
callback: function() {
var modName = $('#groups-moderator').val().trim().split(' ');
if (modName.length != 2) {
tools.log('Wrong input for Moderator', 'w');
return;
}
amivcore.users.GET({
data: {
where: 'firstname==' + modName[0] + ';lastname==' + modName[1]
}
}, function(ret) {
if (ret['_items'].length !== 1) {
tools.log('Moderator not found', 'w');
return;
}
var newUserData = {};
$('.groups-user-add-form input').each(function() {
newUserData[$(this).attr('name')] = $(this).val();
});
newUserData['moderator_id'] = ret['_items'][0]['_id'];
console.log(newUserData);
amivcore.groups.POST({
data: newUserData
}, function(ret) {
if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
else {
tools.modalClose();
tools.log('Group Created', 's');
groups.get();
}
});
});
}
}
}
});
}
};
// Setup Menu
tools.ui.menu({
'<span class="glyphicon glyphicon-plus" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="New Group"></span>': {
callback: groups.add
},
'<span class="glyphicon glyphicon-arrow-left" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Previous Page"></span>': {
callback: groups.page.dec
},
'<span data-toggle="tooltip" data-placement="bottom" title="Set Page"><span class="groups-cur-page-cont" aria-hidden="true"></span> / <span class="groups-page-max-cont" aria-hidden="true"></span></span>': {
callback: function() {
tools.modal({
head: 'Go To Page:',
body: '<div class="form-group"><input type="number" value="' + groups.page.cur() + '" class="form-control groups-go-page"></div>',
button: {
'Go': {
type: 'success',
close: true,
callback: function() {
groups.page.set($('.groups-go-page').val());
},
}
}
});
}
},
'<span class="glyphicon glyphicon-arrow-right" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Next Page"></span>': {
callback: groups.page.inc
},
'<span class="glyphicon glyphicon-sort" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Sort"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control groups-sort-select">';
var cur = groups.sort.cur();
['name'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>&#8673; ' + i + '</option>';
tmp += '<option value="-' + i + '"' + (('-' + i == cur) ? ' selected' : '') + '>&#8675; ' + i + '</option>';
});
tmp += '</select></div>';
tools.modal({
head: 'Sort',
body: tmp,
button: {
'Sort': {
type: 'success',
close: true,
callback: function() {
groups.sort.set($('.groups-sort-select').val());
}
}
}
});
}
},
'<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Search"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control groups-search-select">';
var cur = groups.search.cur();
if (cur === null || cur == '')
cur = '';
else
cur = cur.split('==')[1];
['name'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>' + i + '</option>';
});
tmp += '</select><br><input type="text" value="' + cur + '" class="form-control groups-search-val"></div>';
tools.modal({
head: 'Search',
body: tmp,
button: {
'Clear': {
type: 'warning',
close: true,
callback: groups.search.clr,
},
'Search': {
type: 'success',
close: true,
callback: function() {
groups.search.set($('.groups-search-select').val(), $('.groups-search-val').val());
}
},
}
})
}
}
});
//Set Toolpit
$('[data-toggle="tooltip"]').tooltip()
// Set Initail Page and get first groups
if (groups.page.cur() === null || isNaN(groups.page.cur()))
groups.page.set(1);
else
groups.page.set(groups.page.cur());
</script>
<style>
.home-bg {
background: url('res/bg/cab-2880.jpg') center / cover;
width: 100%;
height: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.home-bg span {
font-weight: bold;
color: rgb(232, 70, 43);
background-color: rgb(31, 45, 84);
}
</style>
<div class="home-bg">
<div>
<h1>
<span>Ich schwöre feierlich, dass ich ein Tunichtgut bin. - AMIV Admintool</span>
</h1>
<a href="http://www.amiv.ethz.ch/" target="_blank">
<img src="res/logo/main.svg" height="64px" copyright="2013 Wegmann">
</a>
</div>
</div>
<div class="studydocuments-table-wrapper">
<table class="table table-hover studydocuments-table">
<thead>
<tr>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script type="text/javascript">
var studydocuments = {
showInTable: ['_id', '_updated', '_created', 'author'],
curStudydocumentsData: null,
// Page
page: {
max: Number.MAX_VALUE,
cur: function() {
return parseInt(tools.mem.session.get('curPage'));
},
set: function(num) {
num = parseInt(num);
if (num > 0 && num < studydocuments.page.max + 1)
tools.mem.session.set('curPage', num);
$('.studydocuments-cur-page-cont').html(studydocuments.page.cur());
studydocuments.get();
},
inc: function() {
studydocuments.page.set(studydocuments.page.cur() + 1);
},
dec: function() {
studydocuments.page.set(studydocuments.page.cur() - 1);
}
},
//Sorting
sort: {
cur: function() {
return tools.mem.session.get('curSort');
},
set: function(sort) {
tools.mem.session.set('curSort', sort);
studydocuments.get();
},
inv: function() {
var tmp = studydocuments.sort.cur();
if (tmp.charAt(0) == '-')
studydocuments.sort.set(tmp.slice(1));
else
studydocuments.sort.set('-' + tmp);
}
},
//Searching
search: {
cur: function() {
return tools.mem.session.get('search');
},
set: function(dom, val) {
tools.mem.session.set('search', dom + '==' + val);
studydocuments.page.set(1);
},
clr: function() {
tools.mem.session.set('search', '');
studydocuments.page.set(1);
},
},
// Get studydocuments
get: function() {
amivcore.studydocuments.GET({
data: {
'max_results': '50',
page: studydocuments.page.cur(),
sort: studydocuments.sort.cur(),
where: studydocuments.search.cur(),
}
}, function(ret) {
if (ret === undefined || ret['_items'].length == 0) {
tools.log('No Data', 'w');
return;
}
studydocuments.meta = ret['_meta'];
studydocuments.page.max = Math.ceil(studydocuments.meta.total / studydocuments.meta.max_results);
$('.studydocuments-page-max-cont').html(studydocuments.page.max);
// Clear table from previous contentent
$('.studydocuments-table thead tr, .studydocuments-table tbody').html('');
studydocuments.showInTable.forEach(function(i) {
$('.studydocuments-table thead tr').append('<th>' + i + '</th>');
});
for (var n in ret['_items']) {
var tmp = '';
studydocuments.showInTable.forEach(function(i) {
tmp += '<td>' + ret['_items'][n][i] + '</td>';
});
$('.studydocuments-table tbody').append('<tr data-id="' + ret['_items'][n]['_id'] + '">' + tmp + '</tr>');
}
$('.studydocuments-table tbody tr').click(studydocuments.showDetails);
});
},
// Make Modal with editable table data
showDetails: function() {
amivcore.studydocuments.GET({
id: $(this).attr('data-id')
}, function(ret) {
curStudydocumentsData = ret;
var tmp = '<table class="table table-hover studydocuments-studydocuments-edit-table" data-etag="' + ret['_etag'] + '" data-id="' + ret._id + '"><tbody>';
for (var cur in ret)
if (cur.charAt(0) != '_'){
if (cur == 'files'){
tmp += '<tr><td>' + cur + '</td><td contenteditable>';
for (var fileIdx in ret[cur]){
var file = ret[cur][fileIdx];
console.log(file)
tmp += file.name;
}
tmp += '</td></tr>';
}else{
tmp += '<tr><td>' + cur + '</td><td contenteditable>' + ret[cur] + '</td></tr>';
}
}
tmp += '</tbody></table>';
tools.modal({
head: ret.firstname + ' ' + ret.lastname,
body: tmp,
button: {
'Delete': {
type: 'danger',
callback: function() {
if (confirm('Fo\' shizzle my nizzle? U fo\' real?'))
amivcore.studydocuments.DELETE({
id: $('.studydocuments-studydocuments-edit-table').first().attr('data-id'),
header: {
'If-Match': $('.studydocuments-studydocuments-edit-table').attr('data-etag')
},
}, function(ret) {
if (ret === undefined) {
tools.log('Studydocuments successfully deleted', 's');
studydocuments.get();
tools.modalClose();
} else {
tools.log('Error', 'e');
}
});
}
},
'Update': {
type: 'success',
close: true,
callback: studydocuments.inspectStudydocuments,
}
}
});
});
},
// Check wether changes were maid and saves it in that case
inspectStudydocuments: function() {
var newStudydocumentsData = {};
$('.studydocuments-studydocuments-edit-table tr').each(function() {
newStudydocumentsData[$(this).children('td:nth-child(1)').html()] = $(this).children('td:nth-child(2)').html();
});
var changed = false,
curStudydocumentsDataChanged = {};
for (var i in newStudydocumentsData) {
if (newStudydocumentsData[i] != String(curStudydocumentsData[i])) {
changed = true;
curStudydocumentsDataChanged[i] = newStudydocumentsData[i];
}
}
if (changed) {
amivcore.studydocuments.PATCH({
id: curStudydocumentsData._id,
header: {
'If-Match': $('.studydocuments-studydocuments-edit-table').attr('data-etag')
},
data: curStudydocumentsDataChanged
}, function() {
tools.log('Studydocuments Updated', 's');
studydocuments.get();
});
}
},
//Make new studydocuments
add: function() {
var tmp = '<div class="row studydocuments-studydocuments-add-form"><div class="form-group col-xs-6"><label for="studydocuments-fn">Firstname:</label><input type="text" class="form-control" name="firstname" id="studydocuments-fn"></div>' +
'<div class="form-group col-xs-6"><label for="studydocuments-ln">Lastname:</label><input type="text" class="form-control" id="studydocuments-ln" name="lastname"></div>' +
'<div class="form-group"><label for="studydocuments-email">E-Mail:</label><input type="email" class="form-control" id="studydocuments-email" name="email"></div>' +
'<div class="form-group col-xs-6"><label for="studydocuments-membership">Membership:</label><select class="form-control" id="studydocuments-membership" name="membership"><option>regular</option><option>honorary</option><option>extraordinary</option></select></div>' +
'<div class="form-group col-xs-6"><label for="studydocuments-gender">Gender:</label><select class="form-control" id="studydocuments-gender" name="gender"><option>male</option><option>female</option></select></div>' +
'</div>';
tools.modal({
head: 'Spawn new AMIV slave',
body: tmp,
button: {
'Add': {
type: 'success',
callback: function() {
var newStudydocumentsData = {};
$('.studydocuments-studydocuments-add-form input, .studydocuments-studydocuments-add-form select').each(function() {
newStudydocumentsData[$(this).attr('name')] = $(this).val();
});
amivcore.studydocuments.POST({
data: newStudydocumentsData
}, function(ret) {
if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
else {
tools.modalClose();
tools.log('Studydocuments Added', 's');
studydocuments.get();
}
});
}
}
}
});
}
};
// Setup Menu
tools.ui.menu({
'<span class="glyphicon glyphicon-plus" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Create Studydocuments"></span>': {
callback: studydocuments.add
},
'<span class="glyphicon glyphicon-arrow-left" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Previous Page"></span>': {
callback: studydocuments.page.dec
},
'<span data-toggle="tooltip" data-placement="bottom" title="Set Page"><span class="studydocuments-cur-page-cont" aria-hidden="true"></span> / <span class="studydocuments-page-max-cont" aria-hidden="true"></span></span>': {
callback: function() {
tools.modal({
head: 'Go To Page:',
body: '<div class="form-group"><input type="number" value="' + studydocuments.page.cur() + '" class="form-control studydocuments-go-page"></div>',
button: {
'Go': {
type: 'success',
close: true,
callback: function() {
studydocuments.page.set($('.studydocuments-go-page').val());
},
}
}
});
}
},
'<span class="glyphicon glyphicon-arrow-right" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Next Page"></span>': {
callback: studydocuments.page.inc
},
'<span class="glyphicon glyphicon-sort" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Sort"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control studydocuments-sort-select">';
var cur = studydocuments.sort.cur();
studydocuments.showInTable.forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>&#8673; ' + i + '</option>';
tmp += '<option value="-' + i + '"' + (('-' + i == cur) ? ' selected' : '') + '>&#8675; ' + i + '</option>';
});
tmp += '</select></div>';
tools.modal({
head: 'Sort',
body: tmp,
button: {
'Sort': {
type: 'success',
close: true,
callback: function() {
studydocuments.sort.set($('.studydocuments-sort-select').val());
}
}
}
});
}
},
'<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Search"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control studydocuments-search-select">';
var cur = studydocuments.search.cur();
if (cur === null || cur == '')
cur = '';
else
cur = cur.split('==')[1];
['_id', 'firstname', 'lastname'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>' + i + '</option>';
});
tmp += '</select><br><input type="text" value="' + cur + '" class="form-control studydocuments-search-val"></div>';
tools.modal({
head: 'Search',
body: tmp,
button: {
'Clear': {
type: 'warning',
close: true,
callback: studydocuments.search.clr,
},
'Search': {
type: 'success',
close: true,
callback: function() {
studydocuments.search.set($('.studydocuments-search-select').val(), $('.studydocuments-search-val').val());
}
},
}
})
}
}
});
//Set Toolpit
$('[data-toggle="tooltip"]').tooltip()
// Set Initail Page and get first studydocuments
if (studydocuments.page.cur() === null || isNaN(studydocuments.page.cur()))
studydocuments.page.set(1);
else
studydocuments.page.set(studydocuments.page.cur());
</script>
<div class="users-table-wrapper">
<table class="table table-hover users-table">
<thead>
<tr>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script type="text/javascript">
var users = {
showInTable: ['firstname', 'lastname', 'nethz', 'legi', 'membership'],
curUserData: null,
// Page
page: {
max: Number.MAX_VALUE,
cur: function() {
return parseInt(tools.mem.session.get('curPage'));
},
set: function(num) {
num = parseInt(num);
if (num > 0 && num < users.page.max + 1)
tools.mem.session.set('curPage', num);
$('.users-cur-page-cont').html(users.page.cur());
users.get();
},
inc: function() {
users.page.set(users.page.cur() + 1);
},
dec: function() {
users.page.set(users.page.cur() - 1);
}
},
//Sorting
sort: {
cur: function() {
return tools.mem.session.get('curSort');
},
set: function(sort) {
tools.mem.session.set('curSort', sort);
users.get();
},
inv: function() {
var tmp = users.sort.cur();
if (tmp.charAt(0) == '-')
users.sort.set(tmp.slice(1));
else
users.sort.set('-' + tmp);
}
},
//Searching
search: {
cur: function() {
return tools.mem.session.get('search');
},
set: function(dom, val) {
tools.mem.session.set('search', dom + '==' + val);
users.page.set(1);
},
clr: function() {
tools.mem.session.set('search', '');
users.page.set(1);
},
},
// Get users
get: function() {
amivcore.users.GET({
data: {
'max_results': '50',
page: users.page.cur(),
sort: users.sort.cur(),
where: users.search.cur(),
}
}, function(ret) {
if (ret === undefined || ret['_items'].length == 0) {
tools.log('No Data', 'w');
return;
}
users.meta = ret['_meta'];
users.page.max = Math.ceil(users.meta.total / users.meta.max_results);
$('.users-page-max-cont').html(users.page.max);
// Clear table from previous contentent
$('.users-table thead tr, .users-table tbody').html('');
users.showInTable.forEach(function(i) {
$('.users-table thead tr').append('<th>' + i + '</th>');
});
for (var n in ret['_items']) {
var tmp = '';
users.showInTable.forEach(function(i) {
tmp += '<td>' + ret['_items'][n][i] + '</td>';
});
$('.users-table tbody').append('<tr data-id="' + ret['_items'][n]['_id'] + '">' + tmp + '</tr>');
}
$('.users-table tbody tr').click(users.showDetails);
});
},
// Make Modal with editable table data
showDetails: function() {
amivcore.users.GET({
id: $(this).attr('data-id')
}, function(ret) {
curUserData = ret;
var tmp = '<table class="table table-hover users-user-edit-table" data-etag="' + ret['_etag'] + '" data-id="' + ret._id + '"><tbody>';
for (var cur in ret)
if (cur.charAt(0) != '_')
tmp += '<tr><td>' + cur + '</td><td contenteditable>' + ret[cur] + '</td></tr>'
tmp += '</tbody></table>';
tools.modal({
head: ret.firstname + ' ' + ret.lastname,
body: tmp,
button: {
'Delete': {
type: 'danger',
callback: function() {
if (confirm('Fo\' shizzle my nizzle? U fo\' real?'))
amivcore.users.DELETE({
id: $('.users-user-edit-table').first().attr('data-id'),
header: {
'If-Match': $('.users-user-edit-table').attr('data-etag')
},
}, function(ret) {
if (ret === undefined) {
tools.log('User successfully deleted', 's');
users.get();
tools.modalClose();
} else {
tools.log('Error', 'e');
}
});
}
},
'Update': {
type: 'success',
close: true,
callback: users.inspectUser,
}
}
});
});
},
// Check wether changes were maid and saves it in that case
inspectUser: function() {
var newUserData = {};
$('.users-user-edit-table tr').each(function() {
newUserData[$(this).children('td:nth-child(1)').html()] = $(this).children('td:nth-child(2)').html();
});
var changed = false,
curUserDataChanged = {};
for (var i in newUserData) {
if (newUserData[i] != String(curUserData[i])) {
changed = true;
curUserDataChanged[i] = newUserData[i];
}
}
if (changed) {
amivcore.users.PATCH({
id: curUserData._id,
header: {
'If-Match': $('.users-user-edit-table').attr('data-etag')
},
data: curUserDataChanged
}, function() {
tools.log('User Updated', 's');
users.get();
});
}
},
//Make new user
add: function() {
var tmp = '<div class="row users-user-add-form"><div class="form-group col-xs-6"><label for="users-fn">Firstname:</label><input type="text" class="form-control" name="firstname" id="users-fn"></div>' +
'<div class="form-group col-xs-6"><label for="users-ln">Lastname:</label><input type="text" class="form-control" id="users-ln" name="lastname"></div>' +
'<div class="form-group"><label for="users-email">E-Mail:</label><input type="email" class="form-control" id="users-email" name="email"></div>' +
'<div class="form-group col-xs-6"><label for="users-membership">Membership:</label><select class="form-control" id="users-membership" name="membership"><option>regular</option><option>honorary</option><option>extraordinary</option></select></div>' +
'<div class="form-group col-xs-6"><label for="users-gender">Gender:</label><select class="form-control" id="users-gender" name="gender"><option>male</option><option>female</option></select></div>' +
'</div>';
tools.modal({
head: 'Spawn new AMIV slave',
body: tmp,
button: {
'Add': {
type: 'success',
callback: function() {
var newUserData = {};
$('.users-user-add-form input, .users-user-add-form select').each(function() {
newUserData[$(this).attr('name')] = $(this).val();
});
amivcore.users.POST({
data: newUserData
}, function(ret) {
if (!ret.hasOwnProperty('_status') || ret['_status'] != 'OK')
tools.log(JSON.stringify(ret.responseJSON['_issues']), 'e');
else {
tools.modalClose();
tools.log('User Added', 's');
users.get();
}
});
}
}
}
});
}
};
// Setup Menu
tools.ui.menu({
'<span class="glyphicon glyphicon-plus" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Create User"></span>': {
callback: users.add
},
'<span class="glyphicon glyphicon-arrow-left" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Previous Page"></span>': {
callback: users.page.dec
},
'<span data-toggle="tooltip" data-placement="bottom" title="Set Page"><span class="users-cur-page-cont" aria-hidden="true"></span> / <span class="users-page-max-cont" aria-hidden="true"></span></span>': {
callback: function() {
tools.modal({
head: 'Go To Page:',
body: '<div class="form-group"><input type="number" value="' + users.page.cur() + '" class="form-control users-go-page"></div>',
button: {
'Go': {
type: 'success',
close: true,
callback: function() {
users.page.set($('.users-go-page').val());
},
}
}
});
}
},
'<span class="glyphicon glyphicon-arrow-right" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Next Page"></span>': {
callback: users.page.inc
},
'<span class="glyphicon glyphicon-sort" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Sort"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control users-sort-select">';
var cur = users.sort.cur();
['_id', 'firstname', 'lastname', 'membership', 'nethz'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>&#8673; ' + i + '</option>';
tmp += '<option value="-' + i + '"' + (('-' + i == cur) ? ' selected' : '') + '>&#8675; ' + i + '</option>';
});
tmp += '</select></div>';
tools.modal({
head: 'Sort',
body: tmp,
button: {
'Sort': {
type: 'success',
close: true,
callback: function() {
users.sort.set($('.users-sort-select').val());
}
}
}
});
}
},
'<span class="glyphicon glyphicon-search" aria-hidden="true" data-toggle="tooltip" data-placement="bottom" title="Search"></span>': {
callback: function() {
var tmp = '<div class="form-group"><select class="form-control users-search-select">';
var cur = users.search.cur();
if (cur === null || cur == '')
cur = '';
else
cur = cur.split('==')[1];
['_id', 'firstname', 'lastname'].forEach(function(i) {
tmp += '<option value="' + i + '"' + ((i == cur) ? ' selected' : '') + '>' + i + '</option>';
});
tmp += '</select><br><input type="text" value="' + cur + '" class="form-control users-search-val"></div>';
tools.modal({
head: 'Search',
body: tmp,
button: {
'Clear': {
type: 'warning',
close: true,
callback: users.search.clr,
},
'Search': {
type: 'success',
close: true,
callback: function() {
users.search.set($('.users-search-select').val(), $('.users-search-val').val());
}
},
}
})
}
}
});
//Set Toolpit
$('[data-toggle="tooltip"]').tooltip()
// Set Initail Page and get first users
if (users.page.cur() === null || isNaN(users.page.cur()))
users.page.set(1);
else
users.page.set(users.page.cur());
</script>
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove local server and code map
config.devServer = undefined;
//config.devtool = '';
config.mode = 'production';
config.optimization = {
usedExports: true,
sideEffects: true,
splitChunks: {
chunks: 'async', // TODO possibly set to all
automaticNameDelimiter: '-',
name: true,
},
};
// Add optimization plugins
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
);
// Replace local with development server config
config.resolve.alias.networkConfig = `${__dirname}/src/networkConfig.dev.json`;
module.exports = config;
const publicPath = '/dist';
const path = require('path');
const webpack = require('webpack');
const config = {
context: `${__dirname}/src`, // `__dirname` is root of project
entry: './index.js',
output: {
path: `${__dirname}/dist`, // `dist` is the destination
filename: 'bundle.js',
},
// To run development server
devServer: {
contentBase: __dirname,
publicPath,
compress: true,
port: 9000,
hot: true,
index: 'index.html',
historyApiFallback: {
index: 'index.html',
},
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'windows.jQuery': 'jquery',
}),
],
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
emitWarning: true, // don't fail the build for linting errors
},
},
{
test: /\.js$/, // Check for all js files
include: [
path.resolve(__dirname, './src'),
path.resolve(__dirname, 'node_modules/@material'),
path.resolve(__dirname, 'node_modules/amiv-web-ui-components'),
],
use: [
{
loader: 'babel-loader',
options: {
//presets: [['@babel/preset-env', { targets: 'last 2 years' }]],
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-object-rest-spread',
//'@babel/plugin-syntax-dynamic-import',
],
},
},
],
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
publicPath,
},
},
],
},
{
test: /\.(html)$/,
use: [
{
loader: 'file-loader',
options: {
publicPath,
},
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
// Dynamically include config
resolve: {
alias: {
networkConfig: `${__dirname}/src/networkConfig.json`,
},
},
devtool: 'eval-source-map', // Default development sourcemap
};
module.exports = config;
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove development server and code map
config.devServer = undefined;
config.devtool = '';
config.mode = 'production';
config.optimization = {
usedExports: true,
sideEffects: true,
splitChunks: {
chunks: 'async', // TODO possibly set to all
automaticNameDelimiter: '-',
name: true,
},
};
// Add optimization plugins
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
);
// Replace development with production config
config.resolve.alias.networkConfig = `${__dirname}/src/networkConfig.local.json`;
module.exports = config;
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove development server and code map
config.devServer = undefined;
config.devtool = '';
config.mode = 'production';
config.optimization = {
usedExports: true,
sideEffects: true,
splitChunks: {
chunks: 'async', // TODO possibly set to all
automaticNameDelimiter: '-',
name: true,
},
};
// Add optimization plugins
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
);
// Replace development with production config
config.resolve.alias.networkConfig = `${__dirname}/src/networkConfig.prod.json`;
module.exports = config;
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove local server and code map
config.devServer = undefined;
//config.devtool = '';
config.mode = 'production';
config.optimization = {
usedExports: true,
sideEffects: true,
splitChunks: {
chunks: 'async', // TODO possibly set to all
automaticNameDelimiter: '-',
name: true,
},
};
// Add optimization plugins
config.plugins.push(
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
);
// Replace local with staging server config
config.resolve.alias.networkConfig = `${__dirname}/src/networkConfig.staging.json`;
module.exports = config;