2019-10-15 23:46:02 +02:00
|
|
|
(function(){
|
|
|
|
|
|
|
|
let nextTooltipKey = 0;
|
|
|
|
var tooltipData = {};
|
|
|
|
|
|
|
|
var tootlipVisible = false;
|
|
|
|
var tooltipEl = LNVue.$(`<div class="ln-tooltip"></div>`);
|
|
|
|
|
|
|
|
|
|
|
|
function findTooltipData(el){
|
|
|
|
let tooltip = null;
|
|
|
|
while (!tooltip)
|
|
|
|
{
|
|
|
|
tooltip = tooltipData[el.dataset['tooltip']];
|
|
|
|
el = el.parentElement;
|
|
|
|
}
|
|
|
|
return tooltip;
|
|
|
|
}
|
|
|
|
|
|
|
|
function tooltipShow(ev,tooltip){
|
2019-10-16 22:00:03 +02:00
|
|
|
if (tooltipEl.parentElement)
|
|
|
|
document.body.appendChild(tooltipEl);
|
2019-10-15 23:46:02 +02:00
|
|
|
|
|
|
|
tooltipEl.innerText = tooltip.value;
|
2019-10-16 22:00:03 +02:00
|
|
|
tooltipEl.setAttribute("VISIBLE","");
|
2019-10-15 23:46:02 +02:00
|
|
|
|
|
|
|
tootlipVisible = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
function tooltipHide(ev,tooltip){
|
2019-10-16 22:00:03 +02:00
|
|
|
tooltipEl.removeAttribute("VISIBLE");
|
2019-10-15 23:46:02 +02:00
|
|
|
setTimeout(()=>{
|
2019-10-16 22:00:03 +02:00
|
|
|
//document.body.removeChild(tooltipEl);
|
2019-10-15 23:46:02 +02:00
|
|
|
}, 600);
|
|
|
|
|
|
|
|
tootlipVisible = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function tooltipMouseOver(ev){
|
|
|
|
let tooltip = findTooltipData(ev.target);
|
|
|
|
if (!tooltip)
|
|
|
|
console.log(ev);
|
|
|
|
if (tooltip.timeout)
|
|
|
|
clearTimeout(tooltip.timeout);
|
|
|
|
if (tootlipVisible)
|
|
|
|
tooltipHide(ev,tooltip);
|
|
|
|
else
|
|
|
|
tooltip.timeout = setTimeout(() => {
|
|
|
|
tooltipShow(ev,tooltip);
|
2019-10-16 22:00:03 +02:00
|
|
|
}, tooltip.delay || 800);
|
2019-10-15 23:46:02 +02:00
|
|
|
|
|
|
|
if (tooltipEl){
|
|
|
|
tooltipEl.style.left = `${ev.x+3}px`;
|
|
|
|
tooltipEl.style.top = `${ev.y+3}px`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function tooltipMouseOut(ev){
|
|
|
|
let tooltip = findTooltipData(ev.target);
|
|
|
|
if (tooltip.timeout)
|
|
|
|
clearTimeout(tooltip.timeout);
|
|
|
|
tooltipHide(ev,tooltip);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vue.directive('tooltip',{
|
|
|
|
bind: function(el, binding, vnode){
|
|
|
|
let tooltip = {
|
|
|
|
value: binding.value,
|
|
|
|
timeout: null,
|
2019-10-16 22:00:03 +02:00
|
|
|
delay: null,
|
2019-10-15 23:46:02 +02:00
|
|
|
};
|
|
|
|
let tooltipKey = nextTooltipKey++;
|
|
|
|
tooltipData[tooltipKey] = tooltip;
|
|
|
|
el.dataset['tooltip'] = tooltipKey;
|
|
|
|
|
|
|
|
el.addEventListener('mousemove',tooltipMouseOver);
|
|
|
|
el.addEventListener('mouseout',tooltipMouseOut);
|
|
|
|
|
|
|
|
},
|
|
|
|
update: function(el, binding, vnode, oldVnode){
|
2019-10-16 22:00:03 +02:00
|
|
|
let tooltip = findTooltipData(el);
|
|
|
|
tooltip.value = binding.value;
|
2019-10-15 23:46:02 +02:00
|
|
|
},
|
|
|
|
unbind: function(el, binding, vnode){
|
|
|
|
el.removeEventListener('mouseover',tooltipMouseOver);
|
|
|
|
el.removeEventListener('mouseout',tooltipMouseOut);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-navitem',{
|
|
|
|
props: {
|
2019-10-16 22:00:03 +02:00
|
|
|
value: {
|
|
|
|
type: Object,
|
2019-10-15 23:46:02 +02:00
|
|
|
required: true,
|
|
|
|
},
|
2019-10-16 22:00:03 +02:00
|
|
|
key: String,
|
2019-10-15 23:46:02 +02:00
|
|
|
},
|
|
|
|
template: `
|
2019-10-16 22:00:03 +02:00
|
|
|
<div
|
|
|
|
class="ln-navitem"
|
|
|
|
:id="'nav-' + key"
|
2019-10-15 23:46:02 +02:00
|
|
|
>
|
2019-10-16 22:00:03 +02:00
|
|
|
<router-link
|
|
|
|
class="ln-navitem"
|
|
|
|
v-if="value.path"
|
|
|
|
:to="value.path"
|
|
|
|
v-slot="{ href, route, navigate, isActive, isExactActive }"
|
|
|
|
>
|
|
|
|
<a
|
|
|
|
:href="href"
|
|
|
|
@click="navigate"
|
|
|
|
>{{ value.label || value.path }}</a>
|
|
|
|
</router-link>
|
|
|
|
<span
|
|
|
|
v-if="!value.path"
|
|
|
|
class="ln-navitem"
|
|
|
|
>{{ value.label }}</span>
|
|
|
|
<div class="ln-nav-children"
|
|
|
|
v-if="value.navigation"
|
|
|
|
>
|
|
|
|
<ln-navitem
|
|
|
|
v-for="(item,key) in value.navigation"
|
|
|
|
v-bind:value="item"
|
|
|
|
v-bind:key="key"
|
|
|
|
></ln-navitem>
|
2019-10-15 23:46:02 +02:00
|
|
|
</div>
|
2019-10-16 22:00:03 +02:00
|
|
|
</div>
|
2019-10-15 23:46:02 +02:00
|
|
|
`,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-navbar',{
|
|
|
|
props: {
|
2019-10-16 22:00:03 +02:00
|
|
|
value: {
|
2019-10-15 23:46:02 +02:00
|
|
|
type: Object,
|
2019-10-16 22:00:03 +02:00
|
|
|
default: function(){
|
|
|
|
return LNVue.$_.navigation;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
component: {
|
|
|
|
type: [ Object, String ],
|
|
|
|
default: 'ln-navitem',
|
|
|
|
},
|
2019-10-15 23:46:02 +02:00
|
|
|
},
|
|
|
|
template: `
|
|
|
|
<div class="ln-navbar">
|
2019-10-16 22:00:03 +02:00
|
|
|
<div
|
|
|
|
:is="component"
|
|
|
|
v-for="(item,key) in value"
|
|
|
|
v-bind:value="item"
|
|
|
|
v-bind:key="key"
|
|
|
|
>{{ item.label || item.path }}</div>
|
2019-10-15 23:46:02 +02:00
|
|
|
</div>`
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-textfield',{
|
|
|
|
props: {
|
|
|
|
value: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
template: `<input
|
|
|
|
type="text"
|
|
|
|
v-bind:value="value"
|
|
|
|
v-on:input="$emit('input', $event.target.value)">`,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-textarea',{
|
|
|
|
props: {
|
|
|
|
value: {
|
|
|
|
type: String,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
template: `<textarea v-on:input="$emit('input', $event.target.value)">{{ value }}</textarea>`,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-number',{
|
|
|
|
model: {
|
|
|
|
prop: "value",
|
|
|
|
event: "input",
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
value: {
|
|
|
|
required: false,
|
|
|
|
type: Number,
|
|
|
|
},
|
|
|
|
float: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
template: `
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
v-bind:value="value"
|
|
|
|
v-on:input="$emit('input', $event.target.value )"
|
|
|
|
v-bind:step="float ? 'any' : 1"
|
|
|
|
>`,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-slider',{
|
|
|
|
model: {
|
|
|
|
prop: 'value',
|
|
|
|
event: 'change',
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
value: {
|
|
|
|
type: Number,
|
|
|
|
default: 1,
|
|
|
|
},
|
|
|
|
min: {
|
|
|
|
type: Number,
|
|
|
|
default: 0,
|
|
|
|
},
|
|
|
|
max: {
|
|
|
|
type: Number,
|
|
|
|
default: 100,
|
|
|
|
},
|
|
|
|
step: {
|
|
|
|
type: Number,
|
|
|
|
default: 1,
|
|
|
|
},
|
|
|
|
islogarithmic: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
values: {
|
|
|
|
default: null,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data: function(){
|
|
|
|
let d = {
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.values instanceof Array){
|
|
|
|
this.min = 0;
|
|
|
|
this.max = this.values.length - 1;
|
|
|
|
this.step = 1;
|
|
|
|
} else if (this.values instanceof Object){
|
|
|
|
this.min = 0;
|
|
|
|
this.max = Object.keys(this.values).length - 1;
|
|
|
|
this.step = 1;
|
|
|
|
} else if (this.islogarithmic){
|
|
|
|
/* ToDo: Implement */
|
|
|
|
} else {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// console.log(`min=${this.min} max=${this.max} step=${this.step} value=${this.value}`);
|
|
|
|
|
|
|
|
return d;
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
keys: function(){
|
|
|
|
if (this.values instanceof Array)
|
|
|
|
{
|
|
|
|
let keys = new Array(this.values.length);
|
|
|
|
for (let n=0;n<keys.length;n++)
|
|
|
|
keys[n] = n;
|
|
|
|
return keys;
|
|
|
|
} else if (this.values instanceof Object)
|
|
|
|
{
|
|
|
|
return Object.keys(this.values);
|
|
|
|
}
|
|
|
|
console.log("ln-slider.keys: ???");
|
|
|
|
},
|
|
|
|
displayValue: function(){
|
|
|
|
if (this.values)
|
|
|
|
{
|
|
|
|
return this.values[this.value];
|
|
|
|
}
|
|
|
|
return this.mapFromRange(this.value);
|
|
|
|
},
|
|
|
|
sliderValue: {
|
|
|
|
get: function(){ return this.mapToRange(this.value); },
|
|
|
|
set: function(v){ this.value = this.mapFromRange(v); this.$emit('change', this.value); },
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
mapToRange: function(v){
|
|
|
|
if (this.values)
|
|
|
|
{
|
|
|
|
if (this.values)
|
|
|
|
{
|
|
|
|
for (let idx=0;idx<this.keys.length;idx++)
|
|
|
|
{
|
|
|
|
if (v == this.keys[idx])
|
|
|
|
{
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
console.log("slider position not found!");
|
|
|
|
console.log(this.values);
|
|
|
|
console.log(v);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return this.islogarithmic ? null : v;
|
|
|
|
},
|
|
|
|
mapFromRange: function(v){
|
|
|
|
if (this.values)
|
|
|
|
{
|
|
|
|
return this.keys[v];
|
|
|
|
}
|
|
|
|
return this.islogarithmic ? null : v;
|
|
|
|
},
|
|
|
|
fireChange: function(){
|
|
|
|
this.$emit('change',this.value);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
template: `
|
|
|
|
<div class='ln-slider'>
|
|
|
|
<input
|
|
|
|
class="ln-slider"
|
|
|
|
type="range"
|
|
|
|
v-bind:min="min"
|
|
|
|
v-bind:max="max"
|
|
|
|
v-bind:step="step"
|
|
|
|
v-model="sliderValue"
|
|
|
|
@change="fireChange"
|
|
|
|
>{{ displayValue }}
|
|
|
|
</div>`,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component("ln-file",{
|
|
|
|
props: {
|
|
|
|
file: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
remove: {
|
|
|
|
type: Function,
|
|
|
|
required: false,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
},
|
|
|
|
template: `<div
|
|
|
|
class="ln-upload-file"
|
|
|
|
>{{ file.name }} ({{ file.size }}bytes)
|
|
|
|
<sym
|
|
|
|
@click="remove && remove(file)"
|
|
|
|
class="trash"
|
|
|
|
style="position: absolute; right: 2px;"
|
|
|
|
></sym>
|
|
|
|
</div>`
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-upload',{
|
|
|
|
model: {
|
|
|
|
prop: "files",
|
|
|
|
event: "change",
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
maxSize: {
|
|
|
|
type: Number,
|
|
|
|
default: 0,
|
|
|
|
},
|
|
|
|
files: {
|
|
|
|
type: Array,
|
|
|
|
default: [],
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data: function(){ return { maxSize: this.maxSize, files: this.files, }; },
|
|
|
|
methods: {
|
|
|
|
drop: function(dropEvent){
|
|
|
|
dropEvent.preventDefault();
|
|
|
|
|
|
|
|
for (let n=0;n<dropEvent.dataTransfer.files.length;n++)
|
|
|
|
{
|
|
|
|
//let file = dropEvent.dataTransfer.files[n];
|
|
|
|
let item = dropEvent.dataTransfer.items[n];
|
|
|
|
let file = item.getAsFile();
|
|
|
|
|
|
|
|
this.files.push({
|
|
|
|
name: file.name,
|
|
|
|
size: file.size,
|
|
|
|
type: file.type,
|
|
|
|
file: file,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$emit("change",this.files);
|
|
|
|
console.log("files dropped...");
|
|
|
|
},
|
|
|
|
remove(file){
|
|
|
|
console.log(file);
|
|
|
|
let idx = this.files.indexOf(file);
|
|
|
|
if (idx != -1)
|
|
|
|
{
|
|
|
|
this.files.splice(idx,1);
|
|
|
|
this.$emit("change",this.files);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
template: `
|
|
|
|
<div
|
|
|
|
class="ln-upload"
|
|
|
|
@drop="drop"
|
|
|
|
ondragover="event.preventDefault();"
|
|
|
|
>Dateien hierher ziehen oder auswählen:<br>
|
|
|
|
<input type="file" value=""><br>
|
|
|
|
<ln-file
|
|
|
|
v-for="file in files"
|
|
|
|
v-bind:file="file"
|
|
|
|
v-bind:remove="remove"
|
|
|
|
></ln-file>
|
|
|
|
</div>
|
|
|
|
`,
|
|
|
|
});
|
|
|
|
|
|
|
|
Vue.component('ln-select',{
|
|
|
|
model: {
|
|
|
|
prop: "value",
|
|
|
|
event: "change",
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
items: {
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
value: {
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
empty: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
prepared: {
|
|
|
|
get: function(){
|
|
|
|
let prepared = {};
|
|
|
|
LNVue.each(this.items,(element,index) => {
|
|
|
|
prepared[index] = element;
|
|
|
|
});
|
|
|
|
return prepared;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
changed: function(ev){
|
|
|
|
this.$emit("change", ev.target.value );
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
template: `<div class="ln-select">
|
|
|
|
<select @change="changed">
|
|
|
|
<option
|
|
|
|
v-if="empty"
|
|
|
|
value=""
|
|
|
|
></option>
|
|
|
|
<option
|
|
|
|
v-for="(item,key) in prepared"
|
|
|
|
:value="key"
|
|
|
|
:selected="key == value"
|
|
|
|
>{{ item }}</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
`,
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
})();
|