vuetify 0.17.3

This commit is contained in:
Andy Bunce 2017-12-04 09:25:49 +00:00
parent 2cdc2c50c1
commit 929f7c3ea0
39 changed files with 1320 additions and 807 deletions

View file

@ -1,5 +1,5 @@
WARNING=DO NOT MODIFY THIS FILE IF YOU DON'T UNDERSTAND
defaultDestination=C\:/Users/andy/Desktop/basex.9b/webapp
defaultDestination=C\:/Users/andy/Desktop/basex.versions/webapp
defaultVariables=
eclipse.preferences.version=1
includeTeamPrivateFiles=false

View file

@ -7,6 +7,8 @@ Includes:
* localforage for persistence
Edit via android
## Bugs
* requests not stopped after unload
## Settings
Global `settings` provides `getItem(name)` and `setItem(name.value)`

View file

@ -28,6 +28,19 @@ const Auth={
};
Vue.use(Auth);
//Notification Object
const Notification={
messages:[],
add(msg){
this.messages.unshift({text: msg, index: this.messages.length})
},
install(Vue){
Object.defineProperty(Vue.prototype, '$notification', {
get () { return Notification }
}) }
};
Vue.use(Notification);
// Mimetype info
const MimeTypes={
"text/xml":"xml",

View file

@ -22,6 +22,30 @@
</description>
</namespace>
<namespace uri="http://www.w3.org/2005/xpath-functions/math"
prefix="math">
<description>Xpath math </description>
</namespace>
<namespace uri="http://www.w3.org/2005/xpath-functions/map"
prefix="map">
<description>Xpath map </description>
</namespace>
<namespace uri="http://www.w3.org/2005/xpath-functions/array"
prefix="array">
<description>Xpath array </description>
</namespace>
<namespace uri="http://www.w3.org/2005/xqt-errors" prefix="err">
<description>Xpath errors </description>
</namespace>
<namespace uri="http://www.w3.org/2010/xslt-xquery-serialization"
prefix="output">
<description>serialization parameters </description>
</namespace>
<namespace uri="http://www.w3.org/2001/XMLSchema" prefix="xsd">
<description>XML Schema Part 1: Structures namespace. </description>
</namespace>
@ -38,6 +62,18 @@
</description>
</namespace>
<namespace uri="http://www.w3.org/2005/xpath-functions"
prefix="fn">
<description>XPath functions
</description>
</namespace>
<namespace uri="http://www.w3.org/2005/xquery-local-functions"
prefix="local">
<description>Xquery functions
</description>
</namespace>
<namespace uri="http://www.w3.org/2000/svg" prefix="svg">
<description>Scalable Vector Graphics namespace
</description>
@ -68,6 +104,11 @@
</description>
</namespace>
<namespace uri="http://www.opengis.net/gml" prefix="gml">
<description>GML
</description>
</namespace>
<namespace uri="http://www.w3.org/ns/xproc" prefix="xproc">
<description>XProc
</description>
@ -77,8 +118,9 @@
</description>
</namespace>
<namespace uri="http://www.w3.org/ns/xproc-step" prefix="pkg">
<namespace uri="http://expath.org/ns/pkg" prefix="pkg">
<description>EXpath packaging
</description>
</namespace>
</namespaces>

View file

@ -120,7 +120,11 @@
</v-layout>
<v-navigation-drawer left persistent v-model="showInfo" :disable-route-watcher="true">
</v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
<v-navigation-drawer left absolute v-model="showInfo" :disable-route-watcher="true">
<v-card flat tile>
<v-toolbar >
<v-card-title >{{ selection[0] && selection[0].name }}</v-card-title>
@ -133,10 +137,8 @@
</v-card-actions>
</v-card>
</v-navigation-drawer>
</v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
</v-container>
</template>
<script>{
@ -154,7 +156,6 @@
buttons: [
{method: this.todo, icon: "view_quilt"},
{method: this.add, icon: "add"},
{method: this.load, icon: "refresh"},
{method: this.todo, icon: "sort"},
{method: this.selectAll, icon: "select_all"}
],

View file

@ -22,16 +22,15 @@
</v-menu>
<span>{{ path.join('/') }}</span>
</v-tooltip>
<v-toolbar-title >
<span >{{ name }}</span>
</v-toolbar-title>
<v-tooltip top>
<span slot="activator">
<v-chip v-if="dirty" label small class="red white--text">*</v-chip>
<v-chip v-if="!dirty" label small class="green white--text">.</v-chip>
</span>
<span>Changed?</span>
</v-tooltip>
<v-badge right v-model="dirty" >
<span slot="badge" >*</span>
<v-toolbar-title >{{ name }}</v-toolbar-title>
</v-badge>
<v-btn v-if="dirty" icon @click="save()">
<v-icon>file_upload</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-menu left transition="v-fade-transition" >
<v-chip label small slot="activator" >{{ mode }}</v-chip>
@ -55,7 +54,7 @@
</v-tooltip>
<v-spacer></v-spacer>
<v-btn icon @click="acecmd('outline')" title="outline -todo">
<v-icon>star</v-icon>
<v-icon>label_outline</v-icon>
</v-btn>
@ -67,9 +66,7 @@
<v-icon>wrap_text</v-icon>
</v-btn>
<v-btn icon @click="save()">
<v-icon>file_upload</v-icon>
</v-btn>
<v-btn icon @click="beautify()">
<v-icon>format_align_center</v-icon>
@ -77,35 +74,26 @@
<v-btn icon @click="clearDialog = true">
<v-icon>delete</v-icon>
</v-btn>
<v-menu left transition="v-fade-transition">
<v-btn icon slot="activator">
<v-icon>help</v-icon>
</v-btn>
<v-list>
<v-list-tile @click="acecmd('showSettingsMenu')" avatar >
<v-list-tile-avatar>
<v-icon >settings</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showSettingsMenu')" >Show settings</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar>
<v-list-tile-avatar>
<v-icon >keyboard</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')" >Show keyboard commands</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-menu left transition="v-fade-transition">
<v-btn icon slot="activator">
<v-icon>more_vert</v-icon>
</v-btn>
<v-list dense>
<v-list-tile v-for="t in mimeTypes" :key="t">
<v-list-tile-title v-text="t" @click="setMode(t)"></v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showSettingsMenu')" avatar >
<v-list-tile-avatar>
<v-icon >settings</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showSettingsMenu')" >Show ACE settings</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar>
<v-list-tile-avatar>
<v-icon >keyboard</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')" >Show ACE keyboard shortcuts</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>

View file

@ -2,44 +2,58 @@
<template id="eval">
<v-container fluid>
<v-card >
<v-toolbar dense>
<v-toolbar>
<v-menu offset-y>
<v-btn slot="activator">
<v-icon>play_circle_outline</v-icon>
Run</v-btn>
<v-list>
<v-list-tile @click="submit">
<v-list-tile-title>Submit</v-list-tile-title>
</v-list-tile>
<v-divider></v-divider>
<v-list-tile @click="run">
<v-list-tile-title>Run</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="plan">
<v-list-tile-title>Show query plan</v-list-tile-title>
</v-list-tile>
</v-list>
<v-menu offset-x>
<v-btn slot="activator" flat icon color="pink">
<v-icon>label_outline</v-icon>
</v-btn>
<v-card>
<v-card-title>Outline here</v-card-title>
</v-card>
</v-menu>
<v-spacer></v-spacer>
<v-btn @click="imports">
<v-menu offset-x>
<v-btn slot="activator" flat icon color="pink">
<v-icon>add_circle</v-icon>
</v-btn>
<v-card>
<v-btn @click="imports">
<v-icon>library_books</v-icon>
Imports</v-btn>
<v-btn @click="namespaces">
<v-icon>label</v-icon>
Namespaces</v-btn>
<v-menu offset-y>
<v-btn icon color="primary" slot="activator"> <v-icon>more_vert</v-icon></v-btn>
<v-list dense>
<v-list-tile @click="plan">Show query plan</v-list-tile>
</v-card>
</v-menu>
<v-spacer></v-spacer>
<v-btn @click="submit">
<v-icon>play_circle_outline</v-icon>jobs:run
</v-btn>
<v-menu offset-y>
<v-btn slot="activator" flat icon>
<v-icon>more_vert</v-icon>
</v-btn>
<v-list dense>
<v-subheader>More actions...</v-subheader>
<v-divider></v-divider>
<v-list-tile @click="run">
<v-list-tile-title>xquery:eval</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="plan">
<v-list-tile-title>Show query plan</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="hitme">
<v-list-tile-title>Test large result.</v-list-tile-title>
</v-list-tile>
</v-list>
<v-list>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-menu>
</v-toolbar>
@ -53,7 +67,7 @@
<v-card-actions v-if="show" >
<v-chip class="primary white--text">{{jobId}}</v-chip>
<v-chip class="primary white--text">{{job.result}}</v-chip>
<v-chip label class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
@ -91,10 +105,11 @@
result:'',
elapsed: null,
show: false,
showError: false, //unused
showError: false,
showResult: false, //
jobId: null,
job: {}, // {id:"12",result:"job13"}
waiting: false,
destroyed: false,
start: null,
jobState: {},
aceSettings:{}
@ -130,7 +145,7 @@
HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq}))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.jobId=r.data.job
this.job=r.data
this.show=true
this.pollState()
@ -138,14 +153,15 @@
.catch(r=> {
alert("catch")
console.log("error",r)
this.jobId=r.response.job
this.job=r.response.job
this.showError=true;
});
},
pollState(){
if(this.destroyed)return;
this.waiting=true;
HTTP.get("job/"+this.jobId)
HTTP.get("job/"+this.job.result)
.then(r=>{
this.jobState=r.data
this.waiting=r.data.state!="cached";
@ -159,7 +175,7 @@
},
getResult(){
this.awaitResult(true)
HTTPNE.post("eval/result/"+this.jobId)
HTTPNE.post("eval/result/"+this.job.result)
.then(r=>{
this.result=r.data.result+" "
}).catch(r=> {
@ -182,7 +198,7 @@
alert("@TODO namespaces")
},
plan(){
this.awaitResult(false)
this.awaitResult(true)
HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{
this.result=r.data.result
@ -212,7 +228,12 @@
})})
},
created:function(){
console.log("eval: creatd");
localforage.getItem('eval/xq').then((value) => { this.xq=value || this.xq});
}
},
beforeDestroy:function(){
this.destroyed=true;
console.log("eval: before destroy");
}
}
</script>

View file

@ -8,22 +8,58 @@ import module namespace rest = "http://exquery.org/ns/restxq";
import module namespace util = 'vue-poc/util' at "../../lib/util.xqm";
import module namespace ufile = 'vue-poc/file' at "../../lib/file.xqm";
declare variable $vue-api:db as xs:string:="vue-poc";
declare variable $vue-api:id as element(last-id):=db:open("vue-poc","/state.xml")/state/last-id;
(:~
: eval
:)
declare
%updating
%rest:POST %rest:path("/vue-poc/api/eval/execute")
%rest:form-param("xq", "{$xq}")
%output:method("json")
function vue-api:eval($xq )
{
let $x:=fn:trace($xq,"task: ")
let $r:=util:query($xq,())
return <json type="object" >
<result>{$r}</result>
</json>
return vue-api:response($r)
};
(:~
: return id and return
:)
declare
%updating
function vue-api:response($r)
{
let $id:=$vue-api:id + 1
let $out:= <json type="object" >
<id>{ $id }</id>
<result>{$r}</result>
</json>
return (
replace value of node $vue-api:id with $id,
db:output($out)
)
};
(:~
: submit a simple job
:)
declare
%updating
%rest:POST %rest:path("/vue-poc/api/eval/submit")
%rest:form-param("xq", "{$xq}")
%output:method("json")
function vue-api:submit($xq )
{
let $bindings:=map{}
let $opts:=map{"cache":true()}
let $r:=jobs:eval($xq,$bindings,$opts)
return vue-api:response($r)
};
(:~
: query plan
:)
@ -40,22 +76,6 @@ function vue-api:plan($xq )
</json>
};
(:~
: submit a simple job
:)
declare
%rest:POST %rest:path("/vue-poc/api/eval/submit")
%rest:form-param("xq", "{$xq}")
%output:method("json")
function vue-api:submit($xq )
{
let $bindings:=map{}
let $opts:=map{"cache":true()}
let $r:=jobs:eval($xq,$bindings,$opts)
return <json type="object" >
<job>{$r}</job>
</json>
};
(:~
: submit a simple job from path
@ -93,6 +113,9 @@ let $n:='import module namespace fw="quodatum:file.walker";'
</json>
};
(:~
: get result for job with $id
:)
declare
%rest:POST %rest:path('/vue-poc/api/eval/result/{$id}')
%output:method("json")

View file

@ -6,7 +6,7 @@
<template id="images">
<v-card>
<v-toolbar class="green white--text">
<v-toolbar dense >
<v-btn @click.stop="showFilter = true" icon><v-icon>search</v-icon></v-btn>
<v-toolbar-title>{{ qtext }}</v-toolbar-title>
<v-tooltip top v-if="query.keyword || query.from || query.until">
@ -16,18 +16,42 @@
</v-btn>
<span>Clear search</span>
</v-tooltip>
<v-btn icon @click="getImages">
<v-avatar>
<v-icon >refresh</v-icon>
</v-avatar>
</v-btn>
<v-spacer></v-spacer>
<span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip>
Page:{{ query.page+1 }}
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon color="primary">
<v-toolbar-items v-if="!selection.length">
<v-btn icon v-for="b in buttons" :key="b.icon" @click="action(b)">
<v-avatar>
<v-icon v-text="b.icon"></v-icon>
</v-avatar>
</v-btn>
</v-toolbar-items>
<v-toolbar-items v-if="selection.length">
<v-btn icon v-for="b in selopts" :key="b.icon" @click="action(b)">
<v-avatar>
<v-icon v-text="b.icon"></v-icon>
</v-avatar>
</v-btn>
</v-toolbar-items>
</span>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon >
<v-avatar>
<v-icon>arrow_back</v-icon>
</v-avatar>
</v-btn>
<v-btn @click.stop="pageNext()" icon color="primary">
<v-btn @click.stop="pageNext()" icon >
<v-avatar>
<v-icon>arrow_forward</v-icon>
</v-avatar>
</v-btn>
</span>
</v-toolbar-items>
</v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-container v-if="!busy" fluid grid-list-md>
@ -37,32 +61,18 @@
v-for="image in images"
:key="image.name"
>
<v-card class="grey lighten-2 pt-1">
<v-card-media :src="src(image)" @dblclick="go(image)"
height="80px" contain>
<v-card flat tile class="grey lighten-2 pa-1" >
<v-card-media :src="src(image)" @dblclick="go(image)" @click.prevent.stop="image.selected =! image.selected "
height="100px" contain>
<span v-if="image.keywords >0 ">#{{image.keywords}}</span>
<v-avatar icon small v-if="image.geo">
<v-icon>place</v-icon>
</v-avatar>
</v-card-media>
<v-card-actions >
<v-tooltip bottom >
<v-btn icon small slot="activator">
<v-icon>info</v-icon>
</v-btn>
<span v-text="image.path"></span>
</v-tooltip>
<span v-if="image.keywords >0 ">#{{image.keywords}}</span>
<v-btn icon small v-if="image.geo">
<v-icon>place</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn icon small @click="selected(image)">
<v-icon>share</v-icon>
</v-btn>
</v-card-actions>
<div style="position:absolute;right:0;top:0" >
<div v-if="image.selected" style="position:absolute;right:0;top:0" >
<v-icon class="white primary--text">check_circle</v-icon>
</div
</v-card>
@ -70,7 +80,7 @@
</v-layout>
</v-container>
<v-navigation-drawer left persistent v-model="showFilter" :disable-route-watcher="true">
<v-navigation-drawer left fixed v-model="showFilter" :disable-route-watcher="true">
<v-card>
<v-toolbar class="green white--text">
<v-toolbar-title >Show images with...</v-toolbar-title>
@ -162,14 +172,20 @@
</v-card-actions>
</v-card>
</v-navigation-drawer>
<v-navigation-drawer left persistent v-model="showInfo" :disable-route-watcher="true">
<v-navigation-drawer left fixed v-model="showInfo" :disable-route-watcher="true">
<v-card>
<v-toolbar class="green white--text">
<v-toolbar-title >{{selitem.name}}</v-toolbar-title>
<v-toolbar-title >{{selection.length}} selected</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn flat icon @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
</v-toolbar>
<v-card-text> blah blah </v-card-text>
<v-card-text>
<ul>
<li v-for="sel in selection" :key="sel.name">
{{sel.name}} {{sel.path}}
</li>
</ul>
</v-card-text>
</v-card>
</v-navigation-drawer>
@ -178,7 +194,9 @@
</template>
<script>{
data: () => ({
data(){
return {
images:[],
query: {page:0, // current page
from:null,
@ -194,8 +212,18 @@
keywords: [],
showInfo: false,
selitem: "TODO",
location: {use:false,value:true}
}),
location: {use:false,value:true},
buttons: [
{method: this.selectAll, icon: "select_all"}
],
selopts: [
{method: this.selectNone, icon: "select_all"},
{method: ()=>{this.showInfo= ! this.showInfo}, icon: "info"},
{method: this.share, icon: "share"}
]
}
},
methods:{
src(item){
return "data:image/jpeg;base64,"+item.data
@ -212,19 +240,36 @@
this.total=r.data.total
this.images=r.data.items
var t1 = performance.now();
this.elapsed= 0.001 *(t1 - t0)
var elapsed= 0.001 *(t1 - t0);
var round = Vue.filter('round');
this.$notification.add("Found " + this.total + " in : "+ round(elapsed,1) +" secs");
})
},
slideShow(){
alert("slideshow not yet");
},
clear(){
this.query.from=null;
this.query.until=null;
this.query.keyword=null;
this.query.page=0;
},
selectAll(){
this.images.forEach(item=>{item.selected=true})
},
selectNone(){
this.images.forEach(item=>{item.selected=false})
},
selected(image){
this.selitem=image;
this.showInfo=true;
},
action(b){
b.method(b.icon)
},
share(){
alert("sHARE: "+ this.selection.length);
},
isChanged(vnew,vold){
if(vnew.keyword != vold.keyword) return true
if(vnew.from != vold.from) return true
@ -247,6 +292,9 @@
var k=this.query.keyword,f=this.query.from, u=this.query.until
var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"")
return t?t:"(All)"
},
selection(){
return this.images.filter(item=>{return item.selected} )
}
},
watch:{

View file

@ -25,6 +25,30 @@ function vue-api:id( $id as xs:integer)
{ vue-api:get-image($image) }
</json>
};
(:~
: get report
:)
declare
%rest:GET %rest:path("/vue-poc/api/images/report")
%output:method("html") %output:version("5.0")
function vue-api:report()
{
<div>
something
<ol>
<li>$cfg:IMAGEDIR: <code>{ $cfg:IMAGEDIR }</code> </li>
<li>$cfg:THUMBDIR: <code>{ $cfg:THUMBDIR }</code> </li>
<li><a href="#A30">A30</a></li>
<li><a href="#A50">A50</a></li>
</ol>
{for $i in 1 to 50 return <p>{$i}:
<a name="A{$i}">Lorem ipsum</a> dolor sit amet, consectetur adipiscing elit. Morbi aliquam sodales justo, aliquet eleifend ex bibendum eget. Nullam vitae maximus ipsum. Sed maximus felis in interdum maximus. Vestibulum quis urna vel dolor placerat iaculis non at metus. Curabitur nec dictum mauris. Duis placerat magna non pellentesque pulvinar. Nam a eleifend sapien. Suspendisse potenti. Vestibulum nunc massa, eleifend a dolor quis, feugiat condimentum est. Integer diam eros, blandit in purus in, euismod ultrices felis. Donec ipsum magna, elementum non lacus vel, rutrum ornare ante. Integer egestas sapien quam, ut posuere nisi rhoncus nec. Etiam ornare enim eu tellus laoreet, in laoreet urna sodales. Donec interdum, augue non lobortis sodales, leo elit tincidunt mi, vitae varius augue libero vel lectus. Cras imperdiet quis dolor nec gravida.
<a href="#A1">top</a></p>
}
</div>
};
(:~
: get set of thumbnails matching search
:)
@ -146,12 +170,15 @@ let $geo:=$vue-api:entity?json?geo($image)
let $keywords:=$vue-api:entity?json?keywords($image)
let $thumb:= $cfg:THUMBDIR || $path
let $thumb:=if(file:exists($thumb)) then $thumb else $cfg:THUMBDIR || "missing.jpg"
return ( <id>{$id}</id>
return (
<id>{$id}</id>
,<name>{$name}</name>
,<path>{$path}</path>
,$geo,$keywords
,<data>{fetch:binary($thumb)}</data>
,<mime>{fetch:content-type($thumb)}</mime>)
,<mime>{fetch:content-type($thumb)}</mime>
,<selected type="boolean">false</selected>
)
};

View file

@ -15,14 +15,34 @@
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text>
body
</v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-card-text v-if="!busy" v-html="report"></v-card-text>
</v-card>
</v-container>
</template>
<script>{
data: ()=>({
busy: false,
report: null,
elapsed: null
}),
methods:{
get(){
this.busy=true
var t0 = performance.now();
HTTP.get("images/report")
.then(r=>{
this.busy=false
this.report=r.data
var t1 = performance.now();
this.elapsed= 0.001 *(t1 - t0)
})
}
},
created:function(){
console.log("reports")
this.get()
}
}
</script>

View file

@ -13,7 +13,9 @@
</v-card-title>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search"
hide-details single-line @keyup.enter="setfilter"
:append-icon="this.q?'clear':''" :append-icon-cb="e=>this.q=''"></v-text-field>
</v-toolbar>
<v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
@ -44,7 +46,8 @@
busy: false,
total: 0,
items: [],
elapsed: null
elapsed: null,
q:""
}),
methods:{
@ -62,6 +65,9 @@
},
show(keyword){
this.$router.push({ name: 'images', query: { keyword: keyword.text }})
},
setfilter(){
alert("not yet")
}
},
created:function(){

View file

@ -1,7 +1,7 @@
(:~
: create xml file list by scanning $SRC and write to vue-poc
:)
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
import module namespace fw="quodatum:file.walker";
declare namespace c="http://www.w3.org/ns/xproc-step";

View file

@ -3,7 +3,7 @@
: done in batches of 1000
: @return initial number of missing docs
:)
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
import module namespace imgmeta = "expkg-zone58:image.metadata" ;
declare namespace c="http://www.w3.org/ns/xproc-step";

View file

@ -3,7 +3,7 @@
: <metadata/> -> <image/>
:)
import module namespace metadata = 'expkg-zone58:image.metadata';
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
for $meta in collection($cfg:DB-IMAGE || "/meta")/metadata
let $loc:=db:path($meta)=>tokenize("/")
let $name:=$loc[count($loc)-1]

View file

@ -3,7 +3,7 @@
: @return initial number of missing docs
:)
import module namespace t="expkg-zone58:image.thumbnailator";
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
declare namespace c="http://www.w3.org/ns/xproc-step";
declare variable $CHUNK:=1000;

View file

@ -1,5 +1,5 @@
(:~ set original:)
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
for $i in collection($cfg:DB-IMAGE || "/image")/image
where $i[file/@path=>contains('original')]

View file

@ -4,7 +4,7 @@
: <idref>14569796 14569818 </idref>
: </keyword>
:)
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
declare %updating function local:put($data,$path){
db:replace($cfg:DB-IMAGE,$path,$data)
};

View file

@ -4,11 +4,12 @@
: <idref>14569796 14569818 </idref>
: </keyword>
:)
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
import module namespace cfg = "quodatum:media.image.configure" at "../config.xqm";
declare %updating function local:put($data,$path){
db:replace($cfg:DB-IMAGE,$path,$data)
};
declare variable $DEST:="/datetaken.xml";
let $dates:=<dates date="{current-dateTime()}">{
for $image in collection($cfg:DB-IMAGE || "/image")/image[not(@original)]
let $year:=substring($image/datetaken,1,4)

View file

@ -15,6 +15,7 @@
hide-details
v-model="search"
></v-text-field>
<v-btn icon ><v-icon>add</v-icon></v-btn>
<v-spacer></v-spacer>
<v-btn

View file

@ -2,7 +2,7 @@
<template id="map">
<v-container fluid>
<v-layout row wrap>
<v-flex xs12 style="height:400px">
<v-flex xs12 ref="page" v-resize="onResize" style="height:400px">
<v-map :zoom="zoom" :center="center" >
<v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
<v-marker :lat-lng="marker"></v-marker>
@ -22,6 +22,15 @@
marker: L.latLng(54.320498718, -2.739663708)
}
},
methods:{
onResize(){
var el=this.$refs["page"]
console.log("top",el.offsetTop)
var h=Math.max(1,window.innerHeight - el.offsetTop)-60
console.log("h",h)
el.style.height=h +"px"
}
},
created:function(){
console.log("map")
}

View file

@ -1,7 +1,8 @@
<!DOCTYPE html>
<template id="svg">
<v-container fluid>
svg
<div id="canvasqPWKOg" class="canvas"></div>
<button id="resetButtonqPWKOg">Reset</button>
</v-container>
</template>

View file

@ -1,21 +1,7 @@
<!DOCTYPE html>
<template id="tabs">
<v-tabs scroll-bars >
<v-card >
<v-card-actions>
<v-btn icon >
<v-icon>menu</v-icon>
</v-btn>
<v-card-title>Page Title</v-card-title>
<v-spacer></v-spacer>
<v-btn icon >
<v-icon>search</v-icon>
</v-btn>
<v-btn icon >
<v-icon>more_vert</v-icon>
</v-btn>
</v-card-actions>
</v-card>
<v-tabs scroll-bars fixed>
<v-tabs-bar class="grey lighten-3" dense>
<v-tabs-item
@ -31,9 +17,26 @@
<v-icon>close</v-icon>
</v-btn>
</v-tabs-item>
<v-btn icon >
<v-icon>menu</v-icon>
</v-btn>
<v-tabs-slider class="primary"></v-tabs-slider>
</v-tabs-bar>
<v-card >
<v-card-actions>
<v-btn icon >
<v-icon>menu</v-icon>
</v-btn>
<v-card-title>Page Title</v-card-title>
<v-spacer></v-spacer>
<v-btn icon >
<v-icon>search</v-icon>
</v-btn>
<v-btn icon >
<v-icon>more_vert</v-icon>
</v-btn>
</v-card-actions>
</v-card>
<v-tabs-items>
<v-tabs-content v-for="i in 13"
:key="i"

View file

@ -33,7 +33,7 @@
</v-card>
</v-menu>
</v-toolbar>
<v-card-text v-resize="onResize" style="height:400px; " class="amber" ref="page">
<v-card-text ref="page" v-resize="onResize" style="height:400px; " class="amber" >
<v-layout v-if="showOptions.includes('result')" style="height:100%" fill-height >
<v-flex >

View file

@ -16,7 +16,7 @@ as xs:string
let $file:=if(starts-with($file,"/")) then
substring($file,2)
else
error(xs:QName('vue-api:badpath'),"leading slash")
error(xs:QName('ufile:badpath'),"leading slash")
let $webroot:=db:system()/globaloptions/webpath/concat(.,"/")
return file:resolve-path($file,$webroot)
@ -25,7 +25,7 @@ as xs:string
declare function ufile:webfile($url as xs:string)
as element(c:directory)
{
let $path := ufile:web( $url)=>trace("vue-api:web ")
let $path := ufile:web( $url)=>trace("ufile:web ")
return if( file:exists($path))then
fw:directory-list($path,map{"max-depth":1,"include-info":true()})
else

View file

@ -0,0 +1,157 @@
(:~
: pipeline library
: @author Andy Bunce
: @version 0.2
: @date nov 2017
:)
module namespace qipe='http://quodatum.com/ns/pipeline';
import module namespace schematron = "http://github.com/Schematron/schematron-basex";
declare variable $qipe:DEBUG:=false(); (: currently unused :)
(:~ run a pipeline
: @param $pipe the pipeline document
: @param $initial starting data as sequence
: @result
:)
declare function qipe:run($pipe as document-node(),$initial as item()* )
as item()*
{
let $steps:=$pipe/*/qipe:*
return fold-left($steps,$initial,qipe:step#2)
};
(:~ check pipeline is valid against schema :)
declare function qipe:validate-pipeline($pipe as document-node() )
as document-node()
{
validate:rng($pipe , "schemas/pipeline.rnc",true()),$pipe
};
(:~ run a step
: @param $acc current state
: @param $this current step as qipe:* element
:)
declare function qipe:step($acc,$this as element(*))
{
typeswitch($this)
case element(qipe:validate) return qipe:validate($acc,$this)
case element(qipe:xquery) return qipe:xquery($acc,$this)
case element(qipe:xslt) return qipe:xslt($acc,$this)
case element(qipe:load) return qipe:load($acc,$this)
case element(qipe:store) return qipe:store($acc,$this)
default return error(xs:QName('qipe'), 'unknown step:' || name($this))
};
(:~ run validate step based on @type
:)
declare function qipe:validate($acc,$this as element(qipe:validate))
{
let $href:=qipe:resolve($this/@href)
let $failOnError:=boolean($this/@failOnError)
let $fn:= switch ($this/@type/string())
case "relax-ng" return qipe:relax-ng(?,$href )
case "schematron" return qipe:schematron(?,$href )
case "xml-schema" return qipe:validate-xsd(?,$href )
default return error(xs:QName('qipe'), 'unknown validation type: ' || $this/@type/string() )
for $doc in $acc
let $report:=$fn($doc)
return
if($report/status = "valid") then
$doc
else
let $_:=trace($report,"validation errors")
return if($failOnError) then
error(xs:QName('qipe'), ' validation fails: ' || base-uri($doc))
else
$doc
};
(:~
: run xquery referenced by @href and append result sequence to accumulator
:)
declare function qipe:xquery($acc,$this as element(qipe:xquery))
{
let $href:=$this/@href/string()
let $result:=xquery:invoke($href)
return ($acc,$result)
};
(:~
: apply XSLT transform to each item in accumulator
:)
declare function qipe:xslt($acc,$this as element(qipe:xslt))
{
let $href:=qipe:resolve($this/@href)
let $result:=$acc!xslt:transform(., $href)
return $result
};
(:~
: store each item in accumulator at computed path
:)
declare function qipe:store($acc,$this as element(qipe:store))
{
let $href:=qipe:resolve($this/@base)
let $dated:=boolean($this/@dated)
let $name:=$this/@fileExpression/string()
let $href:=$href || (if( $dated) then format-date(current-date(),"/[Y0001][M01][D01]") else ())
return ($acc,
if(file:exists($href)) then () else file:create-dir($href),
for $item in $acc
let $name:=xquery:eval($name,map{"":$item}) (:eval against doc:)
let $dest:=$href || "/" || $name
return file:write($dest,$item)
)
};
(:~ validate with xml-schema :)
declare function qipe:validate-xsd($doc,$xsd )
as element(report)
{
validate:xsd-report($doc,$xsd)
};
(:~ validate with relax-ng :)
declare function qipe:relax-ng($doc,$rng )
as element(report)
{
let $compact:=matches($rng,".*\.rnc")
return validate:rng-report($doc,$rng,$compact)
};
(:~
: validate with schematron
: NOTE: relative paths in doc() references in schematron may cause issues
:)
declare function qipe:schematron($doc,$uri-sch )
as element(report)
{
let $sch := schematron:compile(doc($uri-sch))
let $svrl := schematron:validate($doc, $sch)
return <report>
<status>{
if(schematron:is-valid($svrl)) then 'valid' else 'invalid'
}</status>
{$svrl}
</report>
};
(:~ load from file system :)
declare function qipe:load($acc,$this )
{
let $href:=qipe:resolve($this/@href)=>trace("load")
let $new:=if(file:is-dir($href)) then
error(xs:QName('qipe'), 'dir loading not implemented') (: @TODO load all:)
else
doc($href)
return ($acc,$new)
};
(:~ resolve locations relative to this document typically from @href :)
declare function qipe:resolve($href as node()? )
{
resolve-uri( $href,base-uri($href))
};

View file

@ -38,7 +38,7 @@ as xs:string
declare %updating function util:update-query(
$query as xs:string?
) {
xquery:update($query, map { }, util:query-options())
xquery:eval-update($query, map { }, util:query-options())
};
(:~

View file

@ -54,14 +54,14 @@ declare function http-created($location,$response){
(:~ CORS header with download option :)
declare function headers($attachment,$response){
(<restxq:response>
(<rest:response>
<http:response>
<http:header name="Access-Control-Allow-Origin" value="*"/>
{if($attachment)
then <http:header name="Content-Disposition" value='attachment;filename="{$attachment}"'/>
else ()}
</http:response>
</restxq:response>, $response)
</rest:response>, $response)
};
(:~ download as zip file :)
@ -71,24 +71,24 @@ declare function zip-download($zipname,$data){
(:~ headers for download :)
declare function method($method as xs:string){
<restxq:response>
<rest:response>
<output:serialization-parameters>
<output:method value="{$method}"/>
</output:serialization-parameters>
</restxq:response>
</rest:response>
};
(:~ headers for download :)
declare function download-response($method,$filename){
<restxq:response>
<rest:response>
<output:serialization-parameters>
<output:method value="{$method}"/>
</output:serialization-parameters>
<http:response>
<http:header name="Content-Disposition" value='attachment;filename="{$filename}"'/>
</http:response>
</restxq:response>
</rest:response>
};
(:~

View file

@ -9,7 +9,7 @@
<xsl:param name="resources" as="xs:string" select="'resources/'" />
<xsl:variable name="css" select="'resources/base.css'" />
<xsl:variable name="css" select="concat($resources,'base.css')" />
<xsl:template match="/">
<html>
@ -57,9 +57,11 @@
<xsl:template match="c:file">
<li>
<a href="{@name}/index.html">
<a href="F{position()}/index.html">
<xsl:value-of select="@name" />
</a>
<xsl:value-of select="position()" />
</li>
</xsl:template>

View file

@ -89,11 +89,12 @@
<xsl:template match="doc:module">
<h1>
<xsl:value-of select="@type" />
module&#160;
<span class="namespace">
<xsl:value-of select="doc:uri" />
</span>
&#160;<xsl:value-of select="@type" />
module
</h1>
<dl>
<xsl:apply-templates select="doc:comment/doc:description" />

View file

@ -1,5 +1,5 @@
(:~
: Genrate html xquery documntation
: Generate XQuery documentation in html
: using file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models
: $efolder:="file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models"
: $target:="file:///C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"
@ -14,6 +14,9 @@ declare variable $xqd:XML:=map{"indent": "no"};
declare variable $xqd:mod-xslt external :="html-module.xsl";
declare variable $xqd:index-xslt external :="html-index.xsl";
(:~ save documentation for files to target
:
:)
declare function xqd:save-xq($files,$target)
{
let $params:=map{
@ -21,7 +24,7 @@ let $params:=map{
let $f:= document{$files} transform with { delete node //c:directory[not(.//c:file)]}
return (
$files//c:file!xqd:gendoc(.,$target,$params),
$files//c:file!xqd:gendoc(.,"F" || position(),$target,$params),
$f=>xqd:store($target || "/files.xml",$xqd:XML),
$f=>xqd:index-html($params)=>xqd:store($target || "/index.html",$xqd:HTML5),
xqd:export-resources($target)
@ -32,10 +35,12 @@ return (
: save xqdoc and html for source file $f
: @param $f <c:file/>
: @param $target destination folder
: @params map
: @param map
: @param
:)
declare function xqd:gendoc(
$f as element(c:file),
$op as xs:string,
$target as xs:string,
$params as map(*)
)
@ -43,7 +48,6 @@ declare function xqd:gendoc(
let $_:= if(file:is-dir($target)) then () else file:create-dir($target)
let $target:= file:path-to-native($target)
let $ip:= $f/@name/resolve-uri(.,base-uri(.))
let $op:= $f/ancestor-or-self::*/@name=>tail()=>string-join("/")
let $dest:= file:resolve-path($op,$target)
let $xqdoc:= xqd:xqdoc($ip,map{})

View file

@ -1,6 +1,18 @@
// vue-poc application routes
const router = new VueRouter({
base:"/vue-poc/ui/",
mode: 'history',
//
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else if (to.hash) {
return { selector: to.hash, behavior: 'smooth' }
} else {
return { x: 0, y: 0 }
}
},
routes: [
{ path: '/', component: Home, meta:{title:"Home"} },
{ path: '/session', component: Session ,meta: {title:"Session"}},

View file

@ -6275,24 +6275,14 @@ exports.StaticContext = function (parent, pos) {
type: 'module',
override: true
};
namespaces['http://expath.org/ns/file'] = {
prefixes: ['file'],
pos: emptyPos,
type: 'module',
override: true
};
namespaces['http://expath.org/ns/http-client'] = {
prefixes: ['http'],
pos: emptyPos,
type: 'module',
override: true
};
namespaces['http://basex.org/modules/archive'] = {
prefixes: ['archive'],
pos: emptyPos,
type: 'module',
override: true
};
namespaces['http://basex.org/modules/client'] = {
prefixes: ['client'],
pos: emptyPos,
@ -6323,6 +6313,12 @@ exports.StaticContext = function (parent, pos) {
type: 'module',
override: true
};
namespaces['http://basex.org/modules/db'] = {
prefixes: ['db'],
pos: emptyPos,
type: 'module',
override: true
};
namespaces['http://basex.org/modules/web'] = {
prefixes: ['web'],
pos: emptyPos,
@ -6374,30 +6370,26 @@ exports.StaticContext = function (parent, pos) {
pos: emptyPos,
type: 'declare'
};
namespaces['http://zorba.io/annotations'] = {
prefixes: ['an'],
namespaces['http://expath.org/ns/file'] = {
prefixes: ['file'],
pos: emptyPos,
type: 'declare',
type: 'module',
override: true
};
namespaces['http://www.28msec.com/annotations/rest'] = {
prefixes: ['rest'],
namespaces['http://expath.org/ns/http-client'] = {
prefixes: ['http'],
pos: emptyPos,
type: 'declare',
type: 'module',
override: true
};
namespaces['http://www.w3.org/2005/xqt-errors'] = {
prefixes: ['err'],
pos: emptyPos,
type: 'declare',
override: true
};
namespaces['http://zorba.io/errors'] = {
prefixes: ['zerr'],
pos: emptyPos,
type: 'declare',
override: true
};
}
var s = {

View file

@ -1,4 +1,4 @@
// generated 2017-10-26T21:35:41.214+01:00
// generated 2017-12-03T22:15:08.778Z
Vue.component('qd-confirm',{template:`
<v-dialog v-model="value">
<v-card>
@ -625,7 +625,11 @@ Vue.filter('round', function(value, decimals) {
</v-layout>
<v-navigation-drawer left="" persistent="" v-model="showInfo" :disable-route-watcher="true">
</v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
<v-navigation-drawer left="" absolute="" v-model="showInfo" :disable-route-watcher="true">
<v-card flat="" tile="">
<v-toolbar>
<v-card-title>{{ selection[0] &amp;&amp; selection[0].name }}</v-card-title>
@ -638,10 +642,8 @@ Vue.filter('round', function(value, decimals) {
</v-card-actions>
</v-card>
</v-navigation-drawer>
</v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
</v-container>
`,
@ -658,7 +660,6 @@ Vue.filter('round', function(value, decimals) {
buttons: [
{method: this.todo, icon: "view_quilt"},
{method: this.add, icon: "add"},
{method: this.load, icon: "refresh"},
{method: this.todo, icon: "sort"},
{method: this.selectAll, icon: "select_all"}
],
@ -846,16 +847,15 @@ Vue.filter('round', function(value, decimals) {
</v-menu>
<span>{{ path.join('/') }}</span>
</v-tooltip>
<v-toolbar-title>
<span>{{ name }}</span>
</v-toolbar-title>
<v-tooltip top="">
<span slot="activator">
<v-chip v-if="dirty" label="" small="" class="red white--text">*</v-chip>
<v-chip v-if="!dirty" label="" small="" class="green white--text">.</v-chip>
</span>
<span>Changed?</span>
</v-tooltip>
<v-badge right="" v-model="dirty">
<span slot="badge">*</span>
<v-toolbar-title>{{ name }}</v-toolbar-title>
</v-badge>
<v-btn v-if="dirty" icon="" @click="save()">
<v-icon>file_upload</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-menu left="" transition="v-fade-transition">
<v-chip label="" small="" slot="activator">{{ mode }}</v-chip>
@ -879,7 +879,7 @@ Vue.filter('round', function(value, decimals) {
</v-tooltip>
<v-spacer></v-spacer>
<v-btn icon="" @click="acecmd('outline')" title="outline -todo">
<v-icon>star</v-icon>
<v-icon>label_outline</v-icon>
</v-btn>
@ -891,9 +891,7 @@ Vue.filter('round', function(value, decimals) {
<v-icon>wrap_text</v-icon>
</v-btn>
<v-btn icon="" @click="save()">
<v-icon>file_upload</v-icon>
</v-btn>
<v-btn icon="" @click="beautify()">
<v-icon>format_align_center</v-icon>
@ -901,35 +899,26 @@ Vue.filter('round', function(value, decimals) {
<v-btn icon="" @click="clearDialog = true">
<v-icon>delete</v-icon>
</v-btn>
<v-menu left="" transition="v-fade-transition">
<v-btn icon="" slot="activator">
<v-icon>help</v-icon>
</v-btn>
<v-list>
<v-list-tile @click="acecmd('showSettingsMenu')" avatar="">
<v-list-tile-avatar>
<v-icon>settings</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showSettingsMenu')">Show settings</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar="">
<v-list-tile-avatar>
<v-icon>keyboard</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')">Show keyboard commands</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-menu left="" transition="v-fade-transition">
<v-btn icon="" slot="activator">
<v-icon>more_vert</v-icon>
</v-btn>
<v-list dense="">
<v-list-tile v-for="t in mimeTypes" :key="t">
<v-list-tile-title v-text="t" @click="setMode(t)"></v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showSettingsMenu')" avatar="">
<v-list-tile-avatar>
<v-icon>settings</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showSettingsMenu')">Show ACE settings</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar="">
<v-list-tile-avatar>
<v-icon>keyboard</v-icon>
</v-list-tile-avatar>
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')">Show ACE keyboard shortcuts</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
@ -1129,44 +1118,58 @@ Entities
const Eval=Vue.extend({template:`
<v-container fluid="">
<v-card>
<v-toolbar dense="">
<v-toolbar>
<v-menu offset-y="">
<v-btn slot="activator">
<v-icon>play_circle_outline</v-icon>
Run</v-btn>
<v-list>
<v-list-tile @click="submit">
<v-list-tile-title>Submit</v-list-tile-title>
</v-list-tile>
<v-divider></v-divider>
<v-list-tile @click="run">
<v-list-tile-title>Run</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="plan">
<v-list-tile-title>Show query plan</v-list-tile-title>
</v-list-tile>
</v-list>
<v-menu offset-x="">
<v-btn slot="activator" flat="" icon="" color="pink">
<v-icon>label_outline</v-icon>
</v-btn>
<v-card>
<v-card-title>Outline here</v-card-title>
</v-card>
</v-menu>
<v-spacer></v-spacer>
<v-btn @click="imports">
<v-menu offset-x="">
<v-btn slot="activator" flat="" icon="" color="pink">
<v-icon>add_circle</v-icon>
</v-btn>
<v-card>
<v-btn @click="imports">
<v-icon>library_books</v-icon>
Imports</v-btn>
<v-btn @click="namespaces">
<v-icon>label</v-icon>
Namespaces</v-btn>
<v-menu offset-y="">
<v-btn icon="" color="primary" slot="activator"> <v-icon>more_vert</v-icon></v-btn>
</v-card>
</v-menu>
<v-spacer></v-spacer>
<v-btn @click="submit">
<v-icon>play_circle_outline</v-icon>jobs:run
</v-btn>
<v-menu offset-y="">
<v-btn slot="activator" flat="" icon="">
<v-icon>more_vert</v-icon>
</v-btn>
<v-list dense="">
<v-list-tile @click="plan">Show query plan</v-list-tile>
<v-subheader>More actions...</v-subheader>
<v-divider></v-divider>
<v-list-tile @click="run">
<v-list-tile-title>xquery:eval</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="plan">
<v-list-tile-title>Show query plan</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="hitme">
<v-list-tile-title>Test large result.</v-list-tile-title>
</v-list-tile>
</v-list>
<v-list>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-menu>
</v-toolbar>
@ -1178,7 +1181,7 @@ Entities
<v-card-actions v-if="show">
<v-chip class="primary white--text">{{jobId}}</v-chip>
<v-chip class="primary white--text">{{job.result}}</v-chip>
<v-chip label="" class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
@ -1214,10 +1217,11 @@ Entities
result:'',
elapsed: null,
show: false,
showError: false, //unused
showError: false,
showResult: false, //
jobId: null,
job: {}, // {id:"12",result:"job13"}
waiting: false,
destroyed: false,
start: null,
jobState: {},
aceSettings:{}
@ -1253,7 +1257,7 @@ Entities
HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq}))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.jobId=r.data.job
this.job=r.data
this.show=true
this.pollState()
@ -1261,14 +1265,15 @@ Entities
.catch(r=> {
alert("catch")
console.log("error",r)
this.jobId=r.response.job
this.job=r.response.job
this.showError=true;
});
},
pollState(){
if(this.destroyed)return;
this.waiting=true;
HTTP.get("job/"+this.jobId)
HTTP.get("job/"+this.job.result)
.then(r=>{
this.jobState=r.data
this.waiting=r.data.state!="cached";
@ -1282,7 +1287,7 @@ Entities
},
getResult(){
this.awaitResult(true)
HTTPNE.post("eval/result/"+this.jobId)
HTTPNE.post("eval/result/"+this.job.result)
.then(r=>{
this.result=r.data.result+" "
}).catch(r=> {
@ -1305,7 +1310,7 @@ Entities
alert("@TODO namespaces")
},
plan(){
this.awaitResult(false)
this.awaitResult(true)
HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{
this.result=r.data.result
@ -1335,8 +1340,13 @@ Entities
})})
},
created:function(){
console.log("eval: creatd");
localforage.getItem('eval/xq').then((value) => { this.xq=value || this.xq});
}
},
beforeDestroy:function(){
this.destroyed=true;
console.log("eval: before destroy");
}
}
);
@ -1513,7 +1523,7 @@ Entities
const Images=Vue.extend({template:`
<v-card>
<v-toolbar class="green white--text">
<v-toolbar dense="">
<v-btn @click.stop="showFilter = true" icon=""><v-icon>search</v-icon></v-btn>
<v-toolbar-title>{{ qtext }}</v-toolbar-title>
<v-tooltip top="" v-if="query.keyword || query.from || query.until">
@ -1522,55 +1532,65 @@ Entities
</v-btn>
<span>Clear search</span>
</v-tooltip>
<v-btn icon="" @click="getImages">
<v-avatar>
<v-icon>refresh</v-icon>
</v-avatar>
</v-btn>
<v-spacer></v-spacer>
<span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip>
Page:{{ query.page+1 }}
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon="" color="primary">
<v-toolbar-items v-if="!selection.length">
<v-btn icon="" v-for="b in buttons" :key="b.icon" @click="action(b)">
<v-avatar>
<v-icon v-text="b.icon"></v-icon>
</v-avatar>
</v-btn>
</v-toolbar-items>
<v-toolbar-items v-if="selection.length">
<v-btn icon="" v-for="b in selopts" :key="b.icon" @click="action(b)">
<v-avatar>
<v-icon v-text="b.icon"></v-icon>
</v-avatar>
</v-btn>
</v-toolbar-items>
</span>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon="">
<v-avatar>
<v-icon>arrow_back</v-icon>
</v-avatar>
</v-btn>
<v-btn @click.stop="pageNext()" icon="" color="primary">
<v-btn @click.stop="pageNext()" icon="">
<v-avatar>
<v-icon>arrow_forward</v-icon>
</v-avatar>
</v-btn>
</span>
</v-toolbar-items>
</v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
<v-container v-if="!busy" fluid="" grid-list-md="">
<v-layout row="" wrap="" v-touch="{ left: () => pageNext(), right: () => pageBack()}">
<v-flex height="80px" xs2="" v-for="image in images" :key="image.name">
<v-card class="grey lighten-2 pt-1">
<v-card-media :src="src(image)" @dblclick="go(image)" height="80px" contain="">
<v-card flat="" tile="" class="grey lighten-2 pa-1">
<v-card-media :src="src(image)" @dblclick="go(image)" @click.prevent.stop="image.selected =! image.selected " height="100px" contain="">
<span v-if="image.keywords >0 ">#{{image.keywords}}</span>
<v-avatar icon="" small="" v-if="image.geo">
<v-icon>place</v-icon>
</v-avatar>
</v-card-media>
<v-card-actions>
<v-tooltip bottom="">
<v-btn icon="" small="" slot="activator">
<v-icon>info</v-icon>
</v-btn>
<span v-text="image.path"></span>
</v-tooltip>
<span v-if="image.keywords >0 ">#{{image.keywords}}</span>
<v-btn icon="" small="" v-if="image.geo">
<v-icon>place</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn icon="" small="" @click="selected(image)">
<v-icon>share</v-icon>
</v-btn>
</v-card-actions>
<div style="position:absolute;right:0;top:0">
<div v-if="image.selected" style="position:absolute;right:0;top:0">
<v-icon class="white primary--text">check_circle</v-icon>
</div>
</v-card></v-flex>
</v-layout>
</v-container>
<v-navigation-drawer left="" persistent="" v-model="showFilter" :disable-route-watcher="true">
<v-navigation-drawer left="" fixed="" v-model="showFilter" :disable-route-watcher="true">
<v-card>
<v-toolbar class="green white--text">
<v-toolbar-title>Show images with...</v-toolbar-title>
@ -1627,14 +1647,20 @@ Entities
</v-card-actions>
</v-card>
</v-navigation-drawer>
<v-navigation-drawer left="" persistent="" v-model="showInfo" :disable-route-watcher="true">
<v-navigation-drawer left="" fixed="" v-model="showInfo" :disable-route-watcher="true">
<v-card>
<v-toolbar class="green white--text">
<v-toolbar-title>{{selitem.name}}</v-toolbar-title>
<v-toolbar-title>{{selection.length}} selected</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn flat="" icon="" @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
</v-toolbar>
<v-card-text> blah blah </v-card-text>
<v-card-text>
<ul>
<li v-for="sel in selection" :key="sel.name">
{{sel.name}} {{sel.path}}
</li>
</ul>
</v-card-text>
</v-card>
</v-navigation-drawer>
@ -1642,7 +1668,9 @@ Entities
`,
data: () => ({
data(){
return {
images:[],
query: {page:0, // current page
from:null,
@ -1658,8 +1686,18 @@ Entities
keywords: [],
showInfo: false,
selitem: "TODO",
location: {use:false,value:true}
}),
location: {use:false,value:true},
buttons: [
{method: this.selectAll, icon: "select_all"}
],
selopts: [
{method: this.selectNone, icon: "select_all"},
{method: ()=>{this.showInfo= ! this.showInfo}, icon: "info"},
{method: this.share, icon: "share"}
]
}
},
methods:{
src(item){
return "data:image/jpeg;base64,"+item.data
@ -1676,19 +1714,36 @@ Entities
this.total=r.data.total
this.images=r.data.items
var t1 = performance.now();
this.elapsed= 0.001 *(t1 - t0)
var elapsed= 0.001 *(t1 - t0);
var round = Vue.filter('round');
this.$notification.add("Found " + this.total + " in : "+ round(elapsed,1) +" secs");
})
},
slideShow(){
alert("slideshow not yet");
},
clear(){
this.query.from=null;
this.query.until=null;
this.query.keyword=null;
this.query.page=0;
},
selectAll(){
this.images.forEach(item=>{item.selected=true})
},
selectNone(){
this.images.forEach(item=>{item.selected=false})
},
selected(image){
this.selitem=image;
this.showInfo=true;
},
action(b){
b.method(b.icon)
},
share(){
alert("sHARE: "+ this.selection.length);
},
isChanged(vnew,vold){
if(vnew.keyword != vold.keyword) return true
if(vnew.from != vold.from) return true
@ -1711,6 +1766,9 @@ Entities
var k=this.query.keyword,f=this.query.from, u=this.query.until
var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"")
return t?t:"(All)"
},
selection(){
return this.images.filter(item=>{return item.selected} )
}
},
watch:{
@ -1765,14 +1823,34 @@ Entities
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text>
body
</v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
<v-card-text v-if="!busy" v-html="report"></v-card-text>
</v-card>
</v-container>
`,
data: ()=>({
busy: false,
report: null,
elapsed: null
}),
methods:{
get(){
this.busy=true
var t0 = performance.now();
HTTP.get("images/report")
.then(r=>{
this.busy=false
this.report=r.data
var t1 = performance.now();
this.elapsed= 0.001 *(t1 - t0)
})
}
},
created:function(){
console.log("reports")
this.get()
}
}
);
@ -1786,7 +1864,7 @@ body
</v-card-title>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search" hide-details="" single-line="" @keyup.enter="setfilter" :append-icon="this.q?'clear':''" :append-icon-cb="e=>this.q=''"></v-text-field>
</v-toolbar>
<v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
@ -1812,7 +1890,8 @@ body
busy: false,
total: 0,
items: [],
elapsed: null
elapsed: null,
q:""
}),
methods:{
@ -1830,6 +1909,9 @@ body
},
show(keyword){
this.$router.push({ name: 'images', query: { keyword: keyword.text }})
},
setfilter(){
alert("not yet")
}
},
created:function(){
@ -1946,6 +2028,7 @@ people
<v-btn @click="stop()" :disabled="noSelection">Stop</v-btn>
<v-text-field append-icon="search" label="Filter jobs" single-line="" hide-details="" v-model="search"></v-text-field>
<v-btn icon=""><v-icon>add</v-icon></v-btn>
<v-spacer></v-spacer>
<v-btn icon="" :loading="loading" @click="getJobs()" @dblclick="autorefresh = !autorefresh" :disabled="loading">
@ -2089,7 +2172,7 @@ people
const Map=Vue.extend({template:`
<v-container fluid="">
<v-layout row="" wrap="">
<v-flex xs12="" style="height:400px">
<v-flex xs12="" ref="page" v-resize="onResize" style="height:400px">
<v-map :zoom="zoom" :center="center">
<v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
<v-marker :lat-lng="marker"></v-marker>
@ -2108,6 +2191,15 @@ people
marker: L.latLng(54.320498718, -2.739663708)
}
},
methods:{
onResize(){
var el=this.$refs["page"]
console.log("top",el.offsetTop)
var h=Math.max(1,window.innerHeight - el.offsetTop)-60
console.log("h",h)
el.style.height=h +"px"
}
},
created:function(){
console.log("map")
}
@ -2814,7 +2906,8 @@ namespaces
);
const Svg=Vue.extend({template:`
<v-container fluid="">
svg
<div id="canvasqPWKOg" class="canvas"></div>
<button id="resetButtonqPWKOg">Reset</button>
</v-container>
`,
@ -2830,8 +2923,25 @@ svg
);
const Tabs=Vue.extend({template:`
<v-tabs scroll-bars="">
<v-card>
<v-tabs scroll-bars="" fixed="">
<v-tabs-bar class="grey lighten-3" dense="">
<v-tabs-item v-for="i in 13" :key="i" :href="'#mobile-tabs-6-' + i">
<v-icon>favorite</v-icon>
<span>Item {{ i }} more</span>
<v-spacer></v-spacer>
<v-btn small="" icon="" class="grey">
<v-icon>close</v-icon>
</v-btn>
</v-tabs-item>
<v-btn icon="">
<v-icon>menu</v-icon>
</v-btn>
<v-tabs-slider class="primary"></v-tabs-slider>
</v-tabs-bar>
<v-card>
<v-card-actions>
<v-btn icon="">
<v-icon>menu</v-icon>
@ -2846,20 +2956,6 @@ svg
</v-btn>
</v-card-actions>
</v-card>
<v-tabs-bar class="grey lighten-3">
<v-tabs-item v-for="i in 13" :key="i" :href="'#mobile-tabs-6-' + i">
<v-icon>favorite</v-icon>
<span>Item {{ i }} more</span>
<v-spacer></v-spacer>
<v-btn small="" icon="" class="grey">
<v-icon>close</v-icon>
</v-btn>
</v-tabs-item>
<v-tabs-slider class="primary"></v-tabs-slider>
</v-tabs-bar>
<v-tabs-items>
<v-tabs-content v-for="i in 13" :key="i" :id="'mobile-tabs-6-' + i">
<v-card flat="">
@ -3397,7 +3493,7 @@ created(){
</v-card>
</v-menu>
</v-toolbar>
<v-card-text v-resize="onResize" style="height:400px; " class="amber" ref="page">
<v-card-text ref="page" v-resize="onResize" style="height:400px; " class="amber">
<v-layout v-if="showOptions.includes('result')" style="height:100%" fill-height="">
<v-flex>
@ -3490,9 +3586,21 @@ created(){
}
);
const router = new VueRouter({
// vue-poc application routes
const router = new VueRouter({
base:"/vue-poc/ui/",
mode: 'history',
//
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else if (to.hash) {
return { selector: to.hash, behavior: 'smooth' }
} else {
return { x: 0, y: 0 }
}
},
routes: [
{ path: '/', component: Home, meta:{title:"Home"} },
{ path: '/session', component: Session ,meta: {title:"Session"}},
@ -3560,19 +3668,23 @@ router.beforeEach((to, from, next) => {
}
});const Vuepoc=Vue.extend({template:`
<v-app id="app" :dark="dark">
<v-navigation-drawer persistent="" v-model="drawerRight" right="" clipped="" :disable-route-watcher="true" app="">
<v-navigation-drawer absolute="" v-model="showNotifications" right="" clipped="" :disable-route-watcher="true" app="">
<v-card>
<v-toolbar class="teal white--text">
<v-toolbar-title>Notifications</v-toolbar-title>
<v-toolbar class="teal white--text">
<v-toolbar-title>Notifications </v-toolbar-title>
<v-spacer></v-spacer>
<v-btn @click="drawerRight = false" icon=""><v-icon>close</v-icon></v-btn>
<v-btn @click="showNotifications = false" icon=""><v-icon>close</v-icon></v-btn>
</v-toolbar>
<v-card-text>
TODO
<v-card-text>
<ul>
<li v-for="msg in $notification.messages" :key="msg.index">
{{msg.text}}
</li>
</ul>
</v-card-text>
</v-card>
</v-navigation-drawer>
<v-navigation-drawer persistent="" app="" :mini-variant.sync="mini" v-model="drawer" :disable-route-watcher="true" :enable-resize-watcher="true">
<v-navigation-drawer app="" :mini-variant.sync="mini" v-model="drawer" absolute="" :disable-route-watcher="true" :enable-resize-watcher="true">
<v-list class="pa-0">
<v-list-tile avatar="" tag="div">
@ -3598,11 +3710,12 @@ router.beforeEach((to, from, next) => {
<v-toolbar class="indigo" app="" dark="">
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-toolbar-title class="hidden-sm-and-down">{{$route.meta.title}}</v-toolbar-title>
<v-btn @click="frmFav = !frmFav" icon="" flat="" title="Bookmark this page">
<v-menu offset-x="" :close-on-content-click="false" :nudge-width="200" v-model="frmFav">
<v-btn slot="activator" @click="frmFav = !frmFav" icon="" flat="" title="Bookmark this page">
<v-icon>star_border</v-icon>
</v-btn>
<v-dialog v-model="frmFav">
<v-card>
</v-btn>
<v-card style="width:400px;">
<v-toolbar class="amber">
<v-card-title>
Bookmark this page
@ -3613,11 +3726,12 @@ router.beforeEach((to, from, next) => {
<v-select v-model="tags" label="tags" chips="" tags="" :items="taglist"></v-select>
</v-card-text>
<v-card-actions>
<v-btn color="primary" flat="" @click.stop="frmFav=false">Save</v-btn>
<v-spacer></v-spacer>
<v-btn color="primary" flat="" @click.stop="frmFav=false">Cancel</v-btn>
<v-btn color="primary" flat="" @click.stop="favorite();frmFav=false">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-menu>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Search..." v-model="q" hide-details="" single-line="" dark="" @keyup.enter="search"></v-text-field>
<v-spacer></v-spacer>
@ -3639,11 +3753,11 @@ router.beforeEach((to, from, next) => {
</v-list>
</v-menu>
<qd-fullscreen></qd-fullscreen>
<v-btn @click="notifications" icon="" flat="" title="Notifications">
<v-btn @click="showNotifications = ! showNotifications" icon="" flat="" title="Notifications">
<v-icon>notifications</v-icon>
</v-btn>
</v-toolbar>
<main>
<v-content>
<v-alert color="error" value="true" dismissible="" v-model="alert.show">
<pre style="overflow:auto;">{{ alert.msg }}</pre>
@ -3652,7 +3766,7 @@ router.beforeEach((to, from, next) => {
<router-view class="view ma-3"></router-view>
</transition>
</v-content>
</main>
</v-app>
`,
@ -3661,7 +3775,7 @@ router.beforeEach((to, from, next) => {
q: "",
status: {},
drawer: true,
drawerRight: false,
showNotifications: false,
mini: false,
dark: false,
alert: {show:false,msg:"Hello"},
@ -3767,9 +3881,6 @@ router.beforeEach((to, from, next) => {
},
favorite(){
alert("@TODO")
},
notifications(){
this.drawerRight=true
}
},
@ -3844,6 +3955,19 @@ const Auth={
};
Vue.use(Auth);
//Notification Object
const Notification={
messages:[],
add(msg){
this.messages.unshift({text: msg, index: this.messages.length})
},
install(Vue){
Object.defineProperty(Vue.prototype, '$notification', {
get () { return Notification }
}) }
};
Vue.use(Notification);
// Mimetype info
const MimeTypes={
"text/xml":"xml",

View file

@ -124,3 +124,34 @@ height: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.canvas {
overflow: hidden;
}
.canvas .wrapper.outer > .background {
fill: #000000;
}
.canvas .wrapper.inner > .background {
fill: #CCCCCC;
cursor: move;
}
.canvas .background {
fill: #F6F6F6;
stroke: #333333;
cursor: move;
}
.canvas .panCanvas {
cursor: move;
}
.canvas .minimap .frame {
pointer-events: all;
}
.canvas .minimap .frame .background {
stroke: #111111;
stroke-width: 4px;
fill-opacity: 0.1;
fill: #000000;
fill: url(#minimapGradient_qwpyza);
filter: url(#minimapDropShadow_qwpyza);
cursor: move;
}

View file

@ -7,25 +7,22 @@
<meta name="description" content="Vue poc" />
<meta name="author" content="andy bunce." />
<title>Vue Router Test</title>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<link href="https://unpkg.com/vuetify@0.16.9/dist/vuetify.min.css" rel="stylesheet" type="text/css">
<link href="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic"/>
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons"/>
<link href="https://unpkg.com/vuetify@0.17.3/dist/vuetify.min.css" rel="stylesheet" type="text/css"/>
<link href="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
crossorigin=""/>
<link href="/vue-poc/ui/app.css" rel="stylesheet" type="text/css">
<link href="/vue-poc/ui/svg-pan-zoom.css" rel="stylesheet" type="text/css">
<link href="/vue-poc/ui/app.css" rel="stylesheet" type="text/css"/>
<link href="/vue-poc/ui/svg-pan-zoom.css" rel="stylesheet" type="text/css"/>
<link rel="shortcut icon" href="/vue-poc/ui/icon.png"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis-timeline-graph2d.min.css" />
</head>
<body>
<div id="app">
<h3><code>vue-poc</code> <small>(v0.2.??)</small> </h3>
<h3><code>vue-poc</code> <small>(v0.3.??)</small> </h3>
<div class="spinner">
<div class="rect1"></div>
@ -37,26 +34,27 @@
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.1/vue-router.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.4.0/qs.js"></script>
<script src="https://unpkg.com/vuetify@0.16.9/dist/vuetify.min.js"></script>
<script src="https://unpkg.com/vuetify@0.17.3/dist/vuetify.min.js"></script>
<script src="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-language_tools.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.12/beautify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.12/beautify-css.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.6.12/beautify-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/localforage/1.5.1/localforage.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis-timeline-graph2d.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/brutusin/json-forms@1.6.3/dist/js/brutusin-json-forms.js"></script>
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
crossorigin=""></script>
<script src="https://unpkg.com/vue2-leaflet@0.0.55/dist/vue2-leaflet.js"></script>
<script src="/vue-poc/ui/svg=pan-zoom.js"></script>
<script src="/vue-poc/ui/svg-pan-zoom.js"></script>
<script src="/vue-poc/ui/perf-stat.js"></script>
<script src="/vue-poc/ui/app-gen.js"></script>
</body>

View file

@ -1,13 +1,5 @@
html, body {
font-family: Arial, sans-serif;
}
.title {
font-size: 12px;
}
.canvas {
overflow: hidden;
fill: #808040;
}
.canvas .wrapper.outer > .background {
fill: #000000;
@ -25,12 +17,15 @@ html, body {
cursor: move;
}
.canvas .minimap .frame {
pointer-events: all;
}
.canvas .minimap .frame .background {
stroke: #111111;
stroke-width: 4px;
fill-opacity: 0.4;
fill-opacity: 0.1;
fill: #000000;
fill: url(#minimapGradient_qwpyza);
xfilter: url(#minimapDropShadow_qwpyza);
filter: url(#minimapDropShadow_qwpyza);
cursor: move;
}

View file

@ -1,436 +1,419 @@
// http://www.billdwhite.com/wordpress/2013/11/26/d3-minimap-pan-and-zoom-demo/
// http://www.billdwhite.com/wordpress/2017/09/12/d3-v4-zooming-understanding-zoombehavior-in-the-pan-and-zoom-minimap/
d3.demo = {};
/** CANVAS **/
d3.demo.canvas = function() {
/** CANVAS **/
d3.demo.canvas = function() {
"use strict";
"use strict";
var width = 500,
height = 500,
zoomEnabled = true,
dragEnabled = true,
scale = 1,
translation = [0,0],
base = null,
wrapperBorder = 2,
minimap = null,
minimapPadding = 20,
minimapScale = 0.25;
var width = 500,
height = 500,
base = null,
wrapperBorder = 0,
minimap = null,
minimapPadding = 10,
minimapScale = 0.25;
function canvas(selection) {
function canvas(selection) {
base = selection;
base = selection;
var xScale = d3.scale.linear()
.domain([-width / 2, width / 2])
.range([0, width]);
var svgWidth = (width + (wrapperBorder*2) + minimapPadding*2 + (width*minimapScale));
var svgHeight = (height + (wrapperBorder*2) + minimapPadding*2);
var svg = selection.append("svg")
.attr("class", "svg canvas")
.attr("width", svgWidth)
.attr("height", svgHeight)
.attr("shape-rendering", "auto");
var yScale = d3.scale.linear()
.domain([-height / 2, height / 2])
.range([height, 0]);
var svgDefs = svg.append("defs");
svgDefs.append("clipPath")
.attr("id", "wrapperClipPath_qwpyza")
.attr("class", "wrapper clipPath")
.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
svgDefs.append("clipPath")
.attr("id", "minimapClipPath_qwpyza")
.attr("class", "minimap clipPath")
.attr("width", width)
.attr("height", height)
.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var zoomHandler = function(newScale) {
if (!zoomEnabled) { return; }
if (d3.event) {
scale = d3.event.scale;
} else {
scale = newScale;
}
if (dragEnabled) {
var tbound = -height * scale,
bbound = height * scale,
lbound = -width * scale,
rbound = width * scale;
// limit translation to thresholds
translation = d3.event ? d3.event.translate : [0, 0];
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
}
var filter = svgDefs.append("svg:filter")
.attr("id", "minimapDropShadow_qwpyza")
.attr("x", "-20%")
.attr("y", "-20%")
.attr("width", "150%")
.attr("height", "150%");
filter.append("svg:feOffset")
.attr("result", "offOut")
.attr("in", "SourceGraphic")
.attr("dx", "1")
.attr("dy", "1");
filter.append("svg:feColorMatrix")
.attr("result", "matrixOut")
.attr("in", "offOut")
.attr("type", "matrix")
.attr("values", "0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.5 0");
filter.append("svg:feGaussianBlur")
.attr("result", "blurOut")
.attr("in", "matrixOut")
.attr("stdDeviation", "10");
filter.append("svg:feBlend")
.attr("in", "SourceGraphic")
.attr("in2", "blurOut")
.attr("mode", "normal");
d3.select(".panCanvas, .panCanvas .bg")
.attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")");
var minimapRadialFill = svgDefs.append("radialGradient")
.attr('id', "minimapGradient")
.attr('gradientUnits', "userSpaceOnUse")
.attr('cx', "500")
.attr('cy', "500")
.attr('r', "400")
.attr('fx', "500")
.attr('fy', "500");
minimapRadialFill.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#FFFFFF");
minimapRadialFill.append("stop")
.attr("offset", "40%")
.attr("stop-color", "#EEEEEE")
minimapRadialFill.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#E0E0E0");
minimap.scale(scale).render();
}; // startoff zoomed in a bit to show pan/zoom rectangle
var outerWrapper = svg.append("g")
.attr("class", "wrapper outer")
.attr("transform", "translate(0, " + minimapPadding + ")");
outerWrapper.append("rect")
.attr("class", "background")
.attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2);
var zoom = d3.behavior.zoom()
.x(xScale)
.y(yScale)
.scaleExtent([0.1, 10])
.on("zoom.canvas", zoomHandler);
var w=width + (wrapperBorder*2) + minimapPadding*2 + (width*minimapScale);
var h=height + (wrapperBorder*2);
var svg = selection.append("svg")
.attr("class", "svg canvas")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 "+w + " "+h)
.attr("shape-rendering", "auto");
var innerWrapper = outerWrapper.append("g")
.attr("class", "wrapper inner")
.attr("clip-path", "url(#wrapperClipPath_qwpyza)")
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")");
var svgDefs = svg.append("defs");
innerWrapper.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
svgDefs.append("clipPath")
.attr("id", "wrapperClipPath_qwpyza")
.attr("class", "wrapper clipPath")
.append("rect")
.attr("class", "background")
var panCanvas = innerWrapper.append("g")
.attr("class", "panCanvas")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(0,0)");
panCanvas.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var zoom = d3.zoom()
.scaleExtent([0.5, 5]);
// updates the zoom boundaries based on the current size and scale
var updateCanvasZoomExtents = function() {
var scale = innerWrapper.property("__zoom").k;
var targetWidth = svgWidth;
var targetHeight = svgHeight;
var viewportWidth = width;
var viewportHeight = height;
zoom.translateExtent([
[-viewportWidth/scale, -viewportHeight/scale],
[(viewportWidth/scale + targetWidth), (viewportHeight/scale + targetHeight)]
]);
};
var zoomHandler = function() {
panCanvas.attr("transform", d3.event.transform);
// here we filter out the emitting of events that originated outside of the normal ZoomBehavior; this prevents an infinite loop
// between the host and the minimap
if (d3.event.sourceEvent instanceof MouseEvent || d3.event.sourceEvent instanceof WheelEvent) {
minimap.update(d3.event.transform);
}
updateCanvasZoomExtents();
};
zoom.on("zoom", zoomHandler);
innerWrapper.call(zoom);
// initialize the minimap, passing needed references
minimap = d3.demo.minimap()
.host(canvas)
.target(panCanvas)
.minimapScale(minimapScale)
.x(width + minimapPadding)
.y(minimapPadding);
svg.call(minimap);
/** ADD SHAPE **/
canvas.addItem = function(item) {
panCanvas.node().appendChild(item.node());
minimap.render();
};
/** RENDER **/
canvas.render = function() {
svgDefs
.select(".clipPath .background")
.attr("width", width)
.attr("height", height);
svgDefs.append("clipPath")
.attr("id", "minimapClipPath_qwpyza")
.attr("class", "minimap clipPath")
.attr("width", width)
.attr("height", height)
//.attr("transform", "translate(" + (width + minimapPadding) + "," + (minimapPadding/2) + ")")
.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
svg
.attr("width", width + (wrapperBorder*2) + minimapPadding*2 + (width*minimapScale))
.attr("height", height + (wrapperBorder*2));
var filter = svgDefs.append("svg:filter")
.attr("id", "minimapDropShadow_qwpyza")
.attr("x", "-20%")
.attr("y", "-20%")
.attr("width", "150%")
.attr("height", "150%");
filter.append("svg:feOffset")
.attr("result", "offOut")
.attr("in", "SourceGraphic")
.attr("dx", "1")
.attr("dy", "1");
filter.append("svg:feColorMatrix")
.attr("result", "matrixOut")
.attr("in", "offOut")
.attr("type", "matrix")
.attr("values", "0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.1 0 0 0 0 0 0.5 0");
filter.append("svg:feGaussianBlur")
.attr("result", "blurOut")
.attr("in", "matrixOut")
.attr("stdDeviation", "10");
filter.append("svg:feBlend")
.attr("in", "SourceGraphic")
.attr("in2", "blurOut")
.attr("mode", "normal");
var minimapRadialFill = svgDefs.append("radialGradient")
.attr({
id:"minimapGradient_qwpyza",
gradientUnits:"userSpaceOnUse",
cx:"500",
cy:"500",
r:"400",
fx:"500",
fy:"500"
});
minimapRadialFill.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#FFFFFF");
minimapRadialFill.append("stop")
.attr("offset", "40%")
.attr("stop-color", "#EEEEEE");
minimapRadialFill.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#E0E0E0");
var outerWrapper = svg.append("g")
.attr("class", "wrapper outer")
.attr("transform", "translate(0, " + minimapPadding + ")");
outerWrapper.append("rect")
.attr("class", "background")
outerWrapper
.select(".background")
.attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2);
var innerWrapper = outerWrapper.append("g")
.attr("class", "wrapper inner")
.attr("clip-path", "url(#wrapperClipPath_qwpyza)")
innerWrapper
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")")
.call(zoom);
innerWrapper.append("rect")
.attr("class", "background")
.select(".background")
.attr("width", width)
.attr("height", height);
var panCanvas = innerWrapper.append("g")
.attr("class", "panCanvas")
panCanvas
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(0,0)");
panCanvas.append("rect")
.attr("class", "background")
.select(".background")
.attr("width", width)
.attr("height", height);
minimap = d3.demo.minimap()
.zoom(zoom)
.target(panCanvas)
.minimapScale(minimapScale)
minimap
.x(width + minimapPadding)
.y(minimapPadding);
svg.call(minimap);
// startoff zoomed in a bit to show pan/zoom rectangle
zoom.scale(1.75);
zoomHandler(1.75);
/** ADD SHAPE **/
canvas.addItem = function(item) {
panCanvas.node().appendChild(item.node());
minimap.render();
};
canvas.clear = function() {
var node=panCanvas.node();
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
};
};
/** RENDER **/
canvas.render = function() {
svgDefs
.select(".clipPath .background")
.attr("width", width)
.attr("height", height);
var w=width + (wrapperBorder*2) + minimapPadding*2 + (width*minimapScale);
var h=height + (wrapperBorder*2);
svg
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 "+w + " "+h);
outerWrapper
.select(".background")
.attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2);
innerWrapper
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")")
.select(".background")
.attr("width", width)
.attr("height", height);
panCanvas
.attr("width", width)
.attr("height", height)
.select(".background")
.attr("width", width)
.attr("height", height);
minimap
.x(width + minimapPadding)
.y(minimapPadding)
.render();
};
canvas.zoomEnabled = function(isEnabled) {
if (!arguments.length) { return zoomEnabled }
zoomEnabled = isEnabled;
};
canvas.dragEnabled = function(isEnabled) {
if (!arguments.length) { return dragEnabled }
dragEnabled = isEnabled;
};
canvas.reset = function() {
svg.call(zoom.event);
zoom.scale(1);
zoom.translate([0,0]);
svg.transition().duration(750).call(zoom.event);
};
}
//============================================================
// Accessors
//============================================================
canvas.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
return this;
.y(minimapPadding)
.render();
};
canvas.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
canvas.reset = function() {
//svg.call(zoom.event);
//svg.transition().duration(750).call(zoom.event);
zoom.transform(panCanvas, d3.zoomIdentity);
svg.property("__zoom", d3.zoomIdentity);
minimap.update(d3.zoomIdentity);
};
canvas.scale = function(value) {
if (!arguments.length) { return scale; }
scale = value;
return this;
canvas.update = function(minimapZoomTransform) {
zoom.transform(panCanvas, minimapZoomTransform);
// update the '__zoom' property with the new transform on the rootGroup which is where the zoomBehavior stores it since it was the
// call target during initialization
innerWrapper.property("__zoom", minimapZoomTransform);
updateCanvasZoomExtents();
};
return canvas;
updateCanvasZoomExtents();
}
//============================================================
// Accessors
//============================================================
canvas.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
return this;
};
canvas.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
};
return canvas;
};
/** MINIMAP **/
d3.demo.minimap = function() {
"use strict";
/** MINIMAP **/
d3.demo.minimap = function() {
var minimapScale = 0.15,
scale = 1,
zoom = null,
base = null,
target = null,
width = 0,
height = 0,
x = 0,
y = 0,
frameX = 0,
frameY = 0;
"use strict";
function minimap(selection) {
var minimapScale = 0.15,
host = null,
base = null,
target = null,
width = 0,
height = 0,
x = 0,
y = 0;
base = selection;
function minimap(selection) {
var container = selection.append("g")
.attr("class", "minimap")
.call(zoom);
base = selection;
zoom.on("zoom.minimap", function() {
scale = d3.event.scale;
});
var zoom = d3.zoom()
.scaleExtent([0.5, 5]);
// updates the zoom boundaries based on the current size and scale
var updateMinimapZoomExtents = function() {
var scale = container.property("__zoom").k;
var targetWidth = parseInt(target.attr("width"));
var targetHeight = parseInt(target.attr("height"));
var viewportWidth = host.width();
var viewportHeight = host.height();
zoom.translateExtent([
[-viewportWidth/scale, -viewportHeight/scale],
[(viewportWidth/scale + targetWidth), (viewportHeight/scale + targetHeight)]
]);
};
var zoomHandler = function() {
frame.attr("transform", d3.event.transform);
// here we filter out the emitting of events that originated outside of the normal ZoomBehavior; this prevents an infinite loop
// between the host and the minimap
if (d3.event.sourceEvent instanceof MouseEvent || d3.event.sourceEvent instanceof WheelEvent) {
// invert the outgoing transform and apply it to the host
var transform = d3.event.transform;
// ordering matters here! you have to scale() before you translate()
var modifiedTransform = d3.zoomIdentity.scale(1/transform.k).translate(-transform.x, -transform.y);
host.update(modifiedTransform);
}
updateMinimapZoomExtents();
};
zoom.on("zoom", zoomHandler);
var container = selection.append("g")
.attr("class", "minimap");
container.call(zoom);
minimap.node = container.node();
var frame = container.append("g")
.attr("class", "frame")
frame.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.attr("filter", "url(#minimapDropShadow_qPWKOg)");
minimap.node = container.node();
minimap.update = function(hostTransform) {
// invert the incoming zoomTransform; ordering matters here! you have to scale() before you translate()
var modifiedTransform = d3.zoomIdentity.scale((1/hostTransform.k)).translate(-hostTransform.x, -hostTransform.y);
// call this.zoom.transform which will reuse the handleZoom method below
zoom.transform(frame, modifiedTransform);
// update the new transform onto the minimapCanvas which is where the zoomBehavior stores it since it was the call target during initialization
container.property("__zoom", modifiedTransform);
var frame = container.append("g")
.attr("class", "frame")
updateMinimapZoomExtents();
};
frame.append("rect")
.attr("class", "background")
/** RENDER **/
minimap.render = function() {
// update the placement of the minimap
container.attr("transform", "translate(" + x + "," + y + ")scale(" + minimapScale + ")");
// update the visualization being shown by the minimap in case its appearance has changed
var node = target.node().cloneNode(true);
node.removeAttribute("id");
base.selectAll(".minimap .panCanvas").remove();
minimap.node.appendChild(node); // minimap node is the container's node
d3.select(node).attr("transform", "translate(0,0)");
// keep the minimap's viewport (frame) sized to match the current visualization viewport dimensions
frame.select(".background")
.attr("width", width)
.attr("height", height)
.attr("filter", "url(#minimapDropShadow_qwpyza)");
var drag = d3.behavior.drag()
.on("dragstart.minimap", function() {
var frameTranslate = d3.demo.util.getXYFromTranslate(frame.attr("transform"));
frameX = frameTranslate[0];
frameY = frameTranslate[1];
})
.on("drag.minimap", function() {
d3.event.sourceEvent.stopImmediatePropagation();
frameX += d3.event.dx;
frameY += d3.event.dy;
frame.attr("transform", "translate(" + frameX + "," + frameY + ")");
var translate = [(-frameX*scale),(-frameY*scale)];
target.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
zoom.translate(translate);
});
frame.call(drag);
/** RENDER **/
minimap.render = function() {
scale = zoom.scale();
container.attr("transform", "translate(" + x + "," + y + ")scale(" + minimapScale + ")");
var node = target.node().cloneNode(true);
node.removeAttribute("id");
base.selectAll(".minimap .panCanvas").remove();
minimap.node.appendChild(node);
var targetTransform = d3.demo.util.getXYFromTranslate(target.attr("transform"));
frame.attr("transform", "translate(" + (-targetTransform[0]/scale) + "," + (-targetTransform[1]/scale) + ")")
.select(".background")
.attr("width", width/scale)
.attr("height", height/scale);
frame.node().parentNode.appendChild(frame.node());
d3.select(node).attr("transform", "translate(1,1)");
};
}
//============================================================
// Accessors
//============================================================
minimap.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
return this;
.attr("height", height);
frame.node().parentNode.appendChild(frame.node());
};
minimap.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
};
updateMinimapZoomExtents();
}
minimap.x = function(value) {
if (!arguments.length) return x;
x = parseInt(value, 10);
return this;
};
//============================================================
// Accessors
//============================================================
minimap.y = function(value) {
if (!arguments.length) return y;
y = parseInt(value, 10);
return this;
};
minimap.scale = function(value) {
if (!arguments.length) { return scale; }
scale = value;
return this;
};
minimap.minimapScale = function(value) {
if (!arguments.length) { return minimapScale; }
minimapScale = value;
return this;
};
minimap.zoom = function(value) {
if (!arguments.length) return zoom;
zoom = value;
return this;
};
minimap.target = function(value) {
if (!arguments.length) { return target; }
target = value;
width = parseInt(target.attr("width"), 10);
height = parseInt(target.attr("height"), 10);
return this;
};
return minimap;
minimap.width = function(value) {
if (!arguments.length) return width;
width = parseInt(value, 10);
return this;
};
/** UTILS **/
d3.demo.util = {};
d3.demo.util.getXYFromTranslate = function(translateString) {
var currentTransform = d3.transform(translateString);
currentX = currentTransform.translate[0];
currentY = currentTransform.translate[1];
return [currentX, currentY];
minimap.height = function(value) {
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
};
/** RUN SCRIPT **/
minimap.x = function(value) {
if (!arguments.length) return x;
x = parseInt(value, 10);
return this;
};
minimap.y = function(value) {
if (!arguments.length) return y;
y = parseInt(value, 10);
return this;
};
minimap.host = function(value) {
if (!arguments.length) { return host;}
host = value;
return this;
}
minimap.minimapScale = function(value) {
if (!arguments.length) { return minimapScale; }
minimapScale = value;
return this;
};
minimap.target = function(value) {
if (!arguments.length) { return target; }
target = value;
width = parseInt(target.attr("width"), 10);
height = parseInt(target.attr("height"), 10);
return this;
};
return minimap;
};
/** RUN SCRIPT **/
var canvasWidth = 800;
var canvas = d3.demo.canvas().width(435).height(400);
d3.select("#canvasqPWKOg").call(canvas);
d3.select("#resetButtonqPWKOg").on("click", function() {
canvas.reset();
});
//d3.xml("https://upload.wikimedia.org/wikipedia/en/1/15/Logo_D3.svg",function(error, xml) {
d3.xml("https://gist.githubusercontent.com/billdwhite/496a140e7ab26cef02635449b3563e54/raw/50a49bfbcafbe1005cba39a118e8b609c4d4ca29/butterfly.svg",function(error, xml) {
if (error) throw error;
addItem(xml.documentElement);
});
function addItem(item) {
canvas.addItem(d3.select(item));
}

View file

@ -2,25 +2,29 @@
<template id="vuepoc">
<v-app id="app" :dark="dark" >
<v-navigation-drawer
persistent
v-model="drawerRight"
absolute
v-model="showNotifications"
right
clipped
:disable-route-watcher="true"
app
>
<v-card>
<v-toolbar class="teal white--text">
<v-toolbar-title >Notifications</v-toolbar-title>
<v-toolbar class="teal white--text">
<v-toolbar-title >Notifications </v-toolbar-title>
<v-spacer></v-spacer>
<v-btn @click="drawerRight = false" icon><v-icon>close</v-icon></v-btn>
<v-btn @click="showNotifications = false" icon><v-icon>close</v-icon></v-btn>
</v-toolbar>
<v-card-text>
TODO
<v-card-text>
<ul>
<li v-for="msg in $notification.messages" :key="msg.index">
{{msg.text}}
</li>
</ul>
</v-card-text>
</v-card>
</v-navigation-drawer>
<v-navigation-drawer persistent app :mini-variant.sync="mini" v-model="drawer"
<v-navigation-drawer app :mini-variant.sync="mini" v-model="drawer" absolute
:disable-route-watcher="true" :enable-resize-watcher="true">
<v-list class="pa-0">
@ -47,11 +51,17 @@
<v-toolbar class="indigo" app dark >
<v-toolbar-side-icon @click.stop="drawer = !drawer" ></v-toolbar-side-icon>
<v-toolbar-title class="hidden-sm-and-down" >{{$route.meta.title}}</v-toolbar-title>
<v-btn @click="frmFav = !frmFav" icon flat title="Bookmark this page">
<v-menu
offset-x
:close-on-content-click="false"
:nudge-width="200"
v-model="frmFav"
>
<v-btn slot="activator" @click="frmFav = !frmFav" icon flat title="Bookmark this page">
<v-icon>star_border</v-icon>
</v-btn>
<v-dialog v-model="frmFav">
<v-card>
</v-btn>
<v-card style="width:400px;">
<v-toolbar class="amber">
<v-card-title>
Bookmark this page
@ -68,11 +78,12 @@
></v-select>
</v-card-text>
<v-card-actions>
<v-btn color="primary" flat @click.stop="frmFav=false">Save</v-btn>
<v-spacer></v-spacer>
<v-btn color="primary" flat @click.stop="frmFav=false">Cancel</v-btn>
<v-btn color="primary" flat @click.stop="favorite();frmFav=false">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-menu>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Search..." v-model="q"
hide-details single-line dark @keyup.enter="search"></v-text-field>
@ -95,11 +106,11 @@
</v-list>
</v-menu>
<qd-fullscreen></qd-fullscreen>
<v-btn @click="notifications" icon flat title="Notifications">
<v-btn @click="showNotifications = ! showNotifications" icon flat title="Notifications">
<v-icon>notifications</v-icon>
</v-btn>
</v-toolbar>
<main>
<v-content>
<v-alert color="error" value="true" dismissible v-model="alert.show">
<pre style="overflow:auto;">{{ alert.msg }}</pre>
@ -108,7 +119,7 @@
<router-view class="view ma-3"></router-view>
</transition>
</v-content>
</main>
</v-app>
</template>
@ -118,7 +129,7 @@
q: "",
status: {},
drawer: true,
drawerRight: false,
showNotifications: false,
mini: false,
dark: false,
alert: {show:false,msg:"Hello"},
@ -224,9 +235,6 @@
},
favorite(){
alert("@TODO")
},
notifications(){
this.drawerRight=true
}
},