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 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= defaultVariables=
eclipse.preferences.version=1 eclipse.preferences.version=1
includeTeamPrivateFiles=false includeTeamPrivateFiles=false

View file

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

View file

@ -28,6 +28,19 @@ const Auth={
}; };
Vue.use(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 // Mimetype info
const MimeTypes={ const MimeTypes={
"text/xml":"xml", "text/xml":"xml",

View file

@ -22,6 +22,30 @@
</description> </description>
</namespace> </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"> <namespace uri="http://www.w3.org/2001/XMLSchema" prefix="xsd">
<description>XML Schema Part 1: Structures namespace. </description> <description>XML Schema Part 1: Structures namespace. </description>
</namespace> </namespace>
@ -38,6 +62,18 @@
</description> </description>
</namespace> </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"> <namespace uri="http://www.w3.org/2000/svg" prefix="svg">
<description>Scalable Vector Graphics namespace <description>Scalable Vector Graphics namespace
</description> </description>
@ -68,6 +104,11 @@
</description> </description>
</namespace> </namespace>
<namespace uri="http://www.opengis.net/gml" prefix="gml">
<description>GML
</description>
</namespace>
<namespace uri="http://www.w3.org/ns/xproc" prefix="xproc"> <namespace uri="http://www.w3.org/ns/xproc" prefix="xproc">
<description>XProc <description>XProc
</description> </description>
@ -77,8 +118,9 @@
</description> </description>
</namespace> </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>EXpath packaging
</description> </description>
</namespace> </namespace>
</namespaces> </namespaces>

View file

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

View file

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

View file

@ -2,44 +2,58 @@
<template id="eval"> <template id="eval">
<v-container fluid> <v-container fluid>
<v-card > <v-card >
<v-toolbar dense>
<v-toolbar>
<v-menu offset-x>
<v-menu offset-y> <v-btn slot="activator" flat icon color="pink">
<v-btn slot="activator"> <v-icon>label_outline</v-icon>
<v-icon>play_circle_outline</v-icon> </v-btn>
Run</v-btn> <v-card>
<v-list> <v-card-title>Outline here</v-card-title>
<v-list-tile @click="submit"> </v-card>
<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> </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> <v-icon>library_books</v-icon>
Imports</v-btn> Imports</v-btn>
<v-btn @click="namespaces"> <v-btn @click="namespaces">
<v-icon>label</v-icon> <v-icon>label</v-icon>
Namespaces</v-btn> Namespaces</v-btn>
<v-menu offset-y> </v-card>
<v-btn icon color="primary" slot="activator"> <v-icon>more_vert</v-icon></v-btn> </v-menu>
<v-list dense> <v-spacer></v-spacer>
<v-list-tile @click="plan">Show query plan</v-list-tile> <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> </v-menu>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-toolbar> </v-toolbar>
@ -53,7 +67,7 @@
<v-card-actions v-if="show" > <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-chip label class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar> <v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
@ -91,10 +105,11 @@
result:'', result:'',
elapsed: null, elapsed: null,
show: false, show: false,
showError: false, //unused showError: false,
showResult: false, // showResult: false, //
jobId: null, job: {}, // {id:"12",result:"job13"}
waiting: false, waiting: false,
destroyed: false,
start: null, start: null,
jobState: {}, jobState: {},
aceSettings:{} aceSettings:{}
@ -130,7 +145,7 @@
HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq})) HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq}))
.then(r=>{ .then(r=>{
this.elapsed=Math.floor(performance.now() - this.start); this.elapsed=Math.floor(performance.now() - this.start);
this.jobId=r.data.job this.job=r.data
this.show=true this.show=true
this.pollState() this.pollState()
@ -138,14 +153,15 @@
.catch(r=> { .catch(r=> {
alert("catch") alert("catch")
console.log("error",r) console.log("error",r)
this.jobId=r.response.job this.job=r.response.job
this.showError=true; this.showError=true;
}); });
}, },
pollState(){ pollState(){
if(this.destroyed)return;
this.waiting=true; this.waiting=true;
HTTP.get("job/"+this.jobId) HTTP.get("job/"+this.job.result)
.then(r=>{ .then(r=>{
this.jobState=r.data this.jobState=r.data
this.waiting=r.data.state!="cached"; this.waiting=r.data.state!="cached";
@ -159,7 +175,7 @@
}, },
getResult(){ getResult(){
this.awaitResult(true) this.awaitResult(true)
HTTPNE.post("eval/result/"+this.jobId) HTTPNE.post("eval/result/"+this.job.result)
.then(r=>{ .then(r=>{
this.result=r.data.result+" " this.result=r.data.result+" "
}).catch(r=> { }).catch(r=> {
@ -182,7 +198,7 @@
alert("@TODO namespaces") alert("@TODO namespaces")
}, },
plan(){ plan(){
this.awaitResult(false) this.awaitResult(true)
HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq})) HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{ .then(r=>{
this.result=r.data.result this.result=r.data.result
@ -212,7 +228,12 @@
})}) })})
}, },
created:function(){ created:function(){
console.log("eval: creatd");
localforage.getItem('eval/xq').then((value) => { this.xq=value || this.xq}); localforage.getItem('eval/xq').then((value) => { this.xq=value || this.xq});
} },
beforeDestroy:function(){
this.destroyed=true;
console.log("eval: before destroy");
}
} }
</script> </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 util = 'vue-poc/util' at "../../lib/util.xqm";
import module namespace ufile = 'vue-poc/file' at "../../lib/file.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 : eval
:) :)
declare declare
%updating
%rest:POST %rest:path("/vue-poc/api/eval/execute") %rest:POST %rest:path("/vue-poc/api/eval/execute")
%rest:form-param("xq", "{$xq}") %rest:form-param("xq", "{$xq}")
%output:method("json") %output:method("json")
function vue-api:eval($xq ) function vue-api:eval($xq )
{ {
let $x:=fn:trace($xq,"task: ")
let $r:=util:query($xq,()) let $r:=util:query($xq,())
return <json type="object" > return vue-api:response($r)
<result>{$r}</result>
</json>
}; };
(:~
: 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 : query plan
:) :)
@ -40,22 +76,6 @@ function vue-api:plan($xq )
</json> </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 : submit a simple job from path
@ -93,6 +113,9 @@ let $n:='import module namespace fw="quodatum:file.walker";'
</json> </json>
}; };
(:~
: get result for job with $id
:)
declare declare
%rest:POST %rest:path('/vue-poc/api/eval/result/{$id}') %rest:POST %rest:path('/vue-poc/api/eval/result/{$id}')
%output:method("json") %output:method("json")

View file

@ -6,7 +6,7 @@
<template id="images"> <template id="images">
<v-card> <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-btn @click.stop="showFilter = true" icon><v-icon>search</v-icon></v-btn>
<v-toolbar-title>{{ qtext }}</v-toolbar-title> <v-toolbar-title>{{ qtext }}</v-toolbar-title>
<v-tooltip top v-if="query.keyword || query.from || query.until"> <v-tooltip top v-if="query.keyword || query.from || query.until">
@ -15,19 +15,43 @@
<v-icon>clear</v-icon> <v-icon>clear</v-icon>
</v-btn> </v-btn>
<span>Clear search</span> <span>Clear search</span>
</v-tooltip> </v-tooltip>
<v-btn icon @click="getImages">
<v-avatar>
<v-icon >refresh</v-icon>
</v-avatar>
</v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<span v-if="!busy"> <span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip> <v-toolbar-items v-if="!selection.length">
<v-btn icon v-for="b in buttons" :key="b.icon" @click="action(b)">
Page:{{ query.page+1 }} <v-avatar>
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon color="primary"> <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-icon>arrow_back</v-icon>
</v-avatar>
</v-btn> </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-icon>arrow_forward</v-icon>
</v-avatar>
</v-btn> </v-btn>
</span> </v-toolbar-items>
</v-toolbar> </v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear> <v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-container v-if="!busy" fluid grid-list-md> <v-container v-if="!busy" fluid grid-list-md>
@ -37,32 +61,18 @@
v-for="image in images" v-for="image in images"
:key="image.name" :key="image.name"
> >
<v-card class="grey lighten-2 pt-1"> <v-card flat tile class="grey lighten-2 pa-1" >
<v-card-media :src="src(image)" @dblclick="go(image)" <v-card-media :src="src(image)" @dblclick="go(image)" @click.prevent.stop="image.selected =! image.selected "
height="80px" contain> 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-media>
<v-card-actions > <div v-if="image.selected" style="position:absolute;right:0;top:0" >
<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" >
<v-icon class="white primary--text">check_circle</v-icon> <v-icon class="white primary--text">check_circle</v-icon>
</div </div
</v-card> </v-card>
@ -70,7 +80,7 @@
</v-layout> </v-layout>
</v-container> </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-card>
<v-toolbar class="green white--text"> <v-toolbar class="green white--text">
<v-toolbar-title >Show images with...</v-toolbar-title> <v-toolbar-title >Show images with...</v-toolbar-title>
@ -162,14 +172,20 @@
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-navigation-drawer> </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-card>
<v-toolbar class="green white--text"> <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-spacer></v-spacer>
<v-btn flat icon @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn> <v-btn flat icon @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
</v-toolbar> </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-card>
</v-navigation-drawer> </v-navigation-drawer>
@ -177,8 +193,10 @@
</template> </template>
<script>{ <script>{
data: () => ({
data(){
return {
images:[], images:[],
query: {page:0, // current page query: {page:0, // current page
from:null, from:null,
@ -194,8 +212,18 @@
keywords: [], keywords: [],
showInfo: false, showInfo: false,
selitem: "TODO", 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:{ methods:{
src(item){ src(item){
return "data:image/jpeg;base64,"+item.data return "data:image/jpeg;base64,"+item.data
@ -212,19 +240,36 @@
this.total=r.data.total this.total=r.data.total
this.images=r.data.items this.images=r.data.items
var t1 = performance.now(); 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(){ clear(){
this.query.from=null; this.query.from=null;
this.query.until=null; this.query.until=null;
this.query.keyword=null; this.query.keyword=null;
this.query.page=0; this.query.page=0;
}, },
selectAll(){
this.images.forEach(item=>{item.selected=true})
},
selectNone(){
this.images.forEach(item=>{item.selected=false})
},
selected(image){ selected(image){
this.selitem=image; this.selitem=image;
this.showInfo=true; this.showInfo=true;
}, },
action(b){
b.method(b.icon)
},
share(){
alert("sHARE: "+ this.selection.length);
},
isChanged(vnew,vold){ isChanged(vnew,vold){
if(vnew.keyword != vold.keyword) return true if(vnew.keyword != vold.keyword) return true
if(vnew.from != vold.from) 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 k=this.query.keyword,f=this.query.from, u=this.query.until
var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"") var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"")
return t?t:"(All)" return t?t:"(All)"
},
selection(){
return this.images.filter(item=>{return item.selected} )
} }
}, },
watch:{ watch:{

View file

@ -25,6 +25,30 @@ function vue-api:id( $id as xs:integer)
{ vue-api:get-image($image) } { vue-api:get-image($image) }
</json> </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 : 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 $keywords:=$vue-api:entity?json?keywords($image)
let $thumb:= $cfg:THUMBDIR || $path let $thumb:= $cfg:THUMBDIR || $path
let $thumb:=if(file:exists($thumb)) then $thumb else $cfg:THUMBDIR || "missing.jpg" let $thumb:=if(file:exists($thumb)) then $thumb else $cfg:THUMBDIR || "missing.jpg"
return ( <id>{$id}</id> return (
<id>{$id}</id>
,<name>{$name}</name> ,<name>{$name}</name>
,<path>{$path}</path> ,<path>{$path}</path>
,$geo,$keywords ,$geo,$keywords
,<data>{fetch:binary($thumb)}</data> ,<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-spacer></v-spacer>
</v-toolbar> </v-toolbar>
<v-card-text> <v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
body <v-card-text v-if="!busy" v-html="report"></v-card-text>
</v-card-text>
</v-card> </v-card>
</v-container> </v-container>
</template> </template>
<script>{ <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> </script>

View file

@ -13,7 +13,9 @@
</v-card-title> </v-card-title>
<v-spacer></v-spacer> <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-toolbar>
<v-card-text> <v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear> <v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
@ -44,7 +46,8 @@
busy: false, busy: false,
total: 0, total: 0,
items: [], items: [],
elapsed: null elapsed: null,
q:""
}), }),
methods:{ methods:{
@ -62,6 +65,9 @@
}, },
show(keyword){ show(keyword){
this.$router.push({ name: 'images', query: { keyword: keyword.text }}) this.$router.push({ name: 'images', query: { keyword: keyword.text }})
},
setfilter(){
alert("not yet")
} }
}, },
created:function(){ created:function(){

View file

@ -1,7 +1,7 @@
(:~ (:~
: create xml file list by scanning $SRC and write to vue-poc : 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"; import module namespace fw="quodatum:file.walker";
declare namespace c="http://www.w3.org/ns/xproc-step"; declare namespace c="http://www.w3.org/ns/xproc-step";

View file

@ -3,7 +3,7 @@
: done in batches of 1000 : done in batches of 1000
: @return initial number of missing docs : @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" ; import module namespace imgmeta = "expkg-zone58:image.metadata" ;
declare namespace c="http://www.w3.org/ns/xproc-step"; declare namespace c="http://www.w3.org/ns/xproc-step";

View file

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

View file

@ -3,7 +3,7 @@
: @return initial number of missing docs : @return initial number of missing docs
:) :)
import module namespace t="expkg-zone58:image.thumbnailator"; 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 namespace c="http://www.w3.org/ns/xproc-step";
declare variable $CHUNK:=1000; declare variable $CHUNK:=1000;

View file

@ -1,5 +1,5 @@
(:~ set original:) (:~ 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 for $i in collection($cfg:DB-IMAGE || "/image")/image
where $i[file/@path=>contains('original')] where $i[file/@path=>contains('original')]

View file

@ -4,7 +4,7 @@
: <idref>14569796 14569818 </idref> : <idref>14569796 14569818 </idref>
: </keyword> : </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){ declare %updating function local:put($data,$path){
db:replace($cfg:DB-IMAGE,$path,$data) db:replace($cfg:DB-IMAGE,$path,$data)
}; };

View file

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

View file

@ -14,7 +14,8 @@
single-line single-line
hide-details hide-details
v-model="search" v-model="search"
></v-text-field> ></v-text-field>
<v-btn icon ><v-icon>add</v-icon></v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn

View file

@ -2,7 +2,7 @@
<template id="map"> <template id="map">
<v-container fluid> <v-container fluid>
<v-layout row wrap> <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-map :zoom="zoom" :center="center" >
<v-tilelayer :url="url" :attribution="attribution"></v-tilelayer> <v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
<v-marker :lat-lng="marker"></v-marker> <v-marker :lat-lng="marker"></v-marker>
@ -22,6 +22,15 @@
marker: L.latLng(54.320498718, -2.739663708) 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(){ created:function(){
console.log("map") console.log("map")
} }

View file

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

View file

@ -1,21 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<template id="tabs"> <template id="tabs">
<v-tabs scroll-bars > <v-tabs scroll-bars fixed>
<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-bar class="grey lighten-3" dense> <v-tabs-bar class="grey lighten-3" dense>
<v-tabs-item <v-tabs-item
@ -31,9 +17,26 @@
<v-icon>close</v-icon> <v-icon>close</v-icon>
</v-btn> </v-btn>
</v-tabs-item> </v-tabs-item>
<v-btn icon >
<v-icon>menu</v-icon>
</v-btn>
<v-tabs-slider class="primary"></v-tabs-slider> <v-tabs-slider class="primary"></v-tabs-slider>
</v-tabs-bar> </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-items>
<v-tabs-content v-for="i in 13" <v-tabs-content v-for="i in 13"
:key="i" :key="i"

View file

@ -33,7 +33,7 @@
</v-card> </v-card>
</v-menu> </v-menu>
</v-toolbar> </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-layout v-if="showOptions.includes('result')" style="height:100%" fill-height >
<v-flex > <v-flex >

View file

@ -16,7 +16,7 @@ as xs:string
let $file:=if(starts-with($file,"/")) then let $file:=if(starts-with($file,"/")) then
substring($file,2) substring($file,2)
else else
error(xs:QName('vue-api:badpath'),"leading slash") error(xs:QName('ufile:badpath'),"leading slash")
let $webroot:=db:system()/globaloptions/webpath/concat(.,"/") let $webroot:=db:system()/globaloptions/webpath/concat(.,"/")
return file:resolve-path($file,$webroot) return file:resolve-path($file,$webroot)
@ -25,7 +25,7 @@ as xs:string
declare function ufile:webfile($url as xs:string) declare function ufile:webfile($url as xs:string)
as element(c:directory) 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 return if( file:exists($path))then
fw:directory-list($path,map{"max-depth":1,"include-info":true()}) fw:directory-list($path,map{"max-depth":1,"include-info":true()})
else 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( declare %updating function util:update-query(
$query as xs:string? $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 :) (:~ CORS header with download option :)
declare function headers($attachment,$response){ declare function headers($attachment,$response){
(<restxq:response> (<rest:response>
<http:response> <http:response>
<http:header name="Access-Control-Allow-Origin" value="*"/> <http:header name="Access-Control-Allow-Origin" value="*"/>
{if($attachment) {if($attachment)
then <http:header name="Content-Disposition" value='attachment;filename="{$attachment}"'/> then <http:header name="Content-Disposition" value='attachment;filename="{$attachment}"'/>
else ()} else ()}
</http:response> </http:response>
</restxq:response>, $response) </rest:response>, $response)
}; };
(:~ download as zip file :) (:~ download as zip file :)
@ -71,24 +71,24 @@ declare function zip-download($zipname,$data){
(:~ headers for download :) (:~ headers for download :)
declare function method($method as xs:string){ declare function method($method as xs:string){
<restxq:response> <rest:response>
<output:serialization-parameters> <output:serialization-parameters>
<output:method value="{$method}"/> <output:method value="{$method}"/>
</output:serialization-parameters> </output:serialization-parameters>
</restxq:response> </rest:response>
}; };
(:~ headers for download :) (:~ headers for download :)
declare function download-response($method,$filename){ declare function download-response($method,$filename){
<restxq:response> <rest:response>
<output:serialization-parameters> <output:serialization-parameters>
<output:method value="{$method}"/> <output:method value="{$method}"/>
</output:serialization-parameters> </output:serialization-parameters>
<http:response> <http:response>
<http:header name="Content-Disposition" value='attachment;filename="{$filename}"'/> <http:header name="Content-Disposition" value='attachment;filename="{$filename}"'/>
</http:response> </http:response>
</restxq:response> </rest:response>
}; };
(:~ (:~

View file

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

View file

@ -89,11 +89,12 @@
<xsl:template match="doc:module"> <xsl:template match="doc:module">
<h1> <h1>
<xsl:value-of select="@type" />
module&#160;
<span class="namespace"> <span class="namespace">
<xsl:value-of select="doc:uri" /> <xsl:value-of select="doc:uri" />
</span> </span>
&#160;<xsl:value-of select="@type" />
module
</h1> </h1>
<dl> <dl>
<xsl:apply-templates select="doc:comment/doc:description" /> <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 : 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" : $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" : $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:mod-xslt external :="html-module.xsl";
declare variable $xqd:index-xslt external :="html-index.xsl"; declare variable $xqd:index-xslt external :="html-index.xsl";
(:~ save documentation for files to target
:
:)
declare function xqd:save-xq($files,$target) declare function xqd:save-xq($files,$target)
{ {
let $params:=map{ let $params:=map{
@ -21,7 +24,7 @@ let $params:=map{
let $f:= document{$files} transform with { delete node //c:directory[not(.//c:file)]} let $f:= document{$files} transform with { delete node //c:directory[not(.//c:file)]}
return ( 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:store($target || "/files.xml",$xqd:XML),
$f=>xqd:index-html($params)=>xqd:store($target || "/index.html",$xqd:HTML5), $f=>xqd:index-html($params)=>xqd:store($target || "/index.html",$xqd:HTML5),
xqd:export-resources($target) xqd:export-resources($target)
@ -32,10 +35,12 @@ return (
: save xqdoc and html for source file $f : save xqdoc and html for source file $f
: @param $f <c:file/> : @param $f <c:file/>
: @param $target destination folder : @param $target destination folder
: @params map : @param map
: @param
:) :)
declare function xqd:gendoc( declare function xqd:gendoc(
$f as element(c:file), $f as element(c:file),
$op as xs:string,
$target as xs:string, $target as xs:string,
$params as map(*) $params as map(*)
) )
@ -43,7 +48,6 @@ declare function xqd:gendoc(
let $_:= if(file:is-dir($target)) then () else file:create-dir($target) let $_:= if(file:is-dir($target)) then () else file:create-dir($target)
let $target:= file:path-to-native($target) let $target:= file:path-to-native($target)
let $ip:= $f/@name/resolve-uri(.,base-uri(.)) 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 $dest:= file:resolve-path($op,$target)
let $xqdoc:= xqd:xqdoc($ip,map{}) let $xqdoc:= xqd:xqdoc($ip,map{})

View file

@ -1,6 +1,18 @@
// vue-poc application routes
const router = new VueRouter({ const router = new VueRouter({
base:"/vue-poc/ui/", base:"/vue-poc/ui/",
mode: 'history', 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: [ routes: [
{ path: '/', component: Home, meta:{title:"Home"} }, { path: '/', component: Home, meta:{title:"Home"} },
{ path: '/session', component: Session ,meta: {title:"Session"}}, { path: '/session', component: Session ,meta: {title:"Session"}},

View file

@ -6275,24 +6275,14 @@ exports.StaticContext = function (parent, pos) {
type: 'module', type: 'module',
override: true 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'] = { namespaces['http://basex.org/modules/archive'] = {
prefixes: ['archive'], prefixes: ['archive'],
pos: emptyPos, pos: emptyPos,
type: 'module', type: 'module',
override: true override: true
}; };
namespaces['http://basex.org/modules/client'] = { namespaces['http://basex.org/modules/client'] = {
prefixes: ['client'], prefixes: ['client'],
pos: emptyPos, pos: emptyPos,
@ -6323,6 +6313,12 @@ exports.StaticContext = function (parent, pos) {
type: 'module', type: 'module',
override: true override: true
}; };
namespaces['http://basex.org/modules/db'] = {
prefixes: ['db'],
pos: emptyPos,
type: 'module',
override: true
};
namespaces['http://basex.org/modules/web'] = { namespaces['http://basex.org/modules/web'] = {
prefixes: ['web'], prefixes: ['web'],
pos: emptyPos, pos: emptyPos,
@ -6374,30 +6370,26 @@ exports.StaticContext = function (parent, pos) {
pos: emptyPos, pos: emptyPos,
type: 'declare' type: 'declare'
}; };
namespaces['http://zorba.io/annotations'] = { namespaces['http://expath.org/ns/file'] = {
prefixes: ['an'], prefixes: ['file'],
pos: emptyPos, pos: emptyPos,
type: 'declare', type: 'module',
override: true override: true
}; };
namespaces['http://www.28msec.com/annotations/rest'] = { namespaces['http://expath.org/ns/http-client'] = {
prefixes: ['rest'], prefixes: ['http'],
pos: emptyPos, pos: emptyPos,
type: 'declare', type: 'module',
override: true override: true
}; };
namespaces['http://www.w3.org/2005/xqt-errors'] = { namespaces['http://www.w3.org/2005/xqt-errors'] = {
prefixes: ['err'], prefixes: ['err'],
pos: emptyPos, pos: emptyPos,
type: 'declare', type: 'declare',
override: true override: true
}; };
namespaces['http://zorba.io/errors'] = {
prefixes: ['zerr'],
pos: emptyPos,
type: 'declare',
override: true
};
} }
var s = { 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:` Vue.component('qd-confirm',{template:`
<v-dialog v-model="value"> <v-dialog v-model="value">
<v-card> <v-card>
@ -625,7 +625,11 @@ Vue.filter('round', function(value, decimals) {
</v-layout> </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-card flat="" tile="">
<v-toolbar> <v-toolbar>
<v-card-title>{{ selection[0] &amp;&amp; selection[0].name }}</v-card-title> <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-actions>
</v-card> </v-card>
</v-navigation-drawer> </v-navigation-drawer>
</v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
</v-container> </v-container>
`, `,
@ -658,7 +660,6 @@ Vue.filter('round', function(value, decimals) {
buttons: [ buttons: [
{method: this.todo, icon: "view_quilt"}, {method: this.todo, icon: "view_quilt"},
{method: this.add, icon: "add"}, {method: this.add, icon: "add"},
{method: this.load, icon: "refresh"},
{method: this.todo, icon: "sort"}, {method: this.todo, icon: "sort"},
{method: this.selectAll, icon: "select_all"} {method: this.selectAll, icon: "select_all"}
], ],
@ -846,16 +847,15 @@ Vue.filter('round', function(value, decimals) {
</v-menu> </v-menu>
<span>{{ path.join('/') }}</span> <span>{{ path.join('/') }}</span>
</v-tooltip> </v-tooltip>
<v-toolbar-title>
<span>{{ name }}</span> <v-badge right="" v-model="dirty">
</v-toolbar-title> <span slot="badge">*</span>
<v-tooltip top=""> <v-toolbar-title>{{ name }}</v-toolbar-title>
<span slot="activator"> </v-badge>
<v-chip v-if="dirty" label="" small="" class="red white--text">*</v-chip> <v-btn v-if="dirty" icon="" @click="save()">
<v-chip v-if="!dirty" label="" small="" class="green white--text">.</v-chip> <v-icon>file_upload</v-icon>
</span> </v-btn>
<span>Changed?</span> <v-spacer></v-spacer>
</v-tooltip>
<v-menu left="" transition="v-fade-transition"> <v-menu left="" transition="v-fade-transition">
<v-chip label="" small="" slot="activator">{{ mode }}</v-chip> <v-chip label="" small="" slot="activator">{{ mode }}</v-chip>
@ -879,7 +879,7 @@ Vue.filter('round', function(value, decimals) {
</v-tooltip> </v-tooltip>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn icon="" @click="acecmd('outline')" title="outline -todo"> <v-btn icon="" @click="acecmd('outline')" title="outline -todo">
<v-icon>star</v-icon> <v-icon>label_outline</v-icon>
</v-btn> </v-btn>
@ -891,9 +891,7 @@ Vue.filter('round', function(value, decimals) {
<v-icon>wrap_text</v-icon> <v-icon>wrap_text</v-icon>
</v-btn> </v-btn>
<v-btn icon="" @click="save()">
<v-icon>file_upload</v-icon>
</v-btn>
<v-btn icon="" @click="beautify()"> <v-btn icon="" @click="beautify()">
<v-icon>format_align_center</v-icon> <v-icon>format_align_center</v-icon>
@ -901,35 +899,26 @@ Vue.filter('round', function(value, decimals) {
<v-btn icon="" @click="clearDialog = true"> <v-btn icon="" @click="clearDialog = true">
<v-icon>delete</v-icon> <v-icon>delete</v-icon>
</v-btn> </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-menu left="" transition="v-fade-transition">
<v-btn icon="" slot="activator"> <v-btn icon="" slot="activator">
<v-icon>more_vert</v-icon> <v-icon>more_vert</v-icon>
</v-btn> </v-btn>
<v-list dense=""> <v-list dense="">
<v-list-tile v-for="t in mimeTypes" :key="t"> <v-list-tile @click="acecmd('showSettingsMenu')" avatar="">
<v-list-tile-title v-text="t" @click="setMode(t)"></v-list-tile-title> <v-list-tile-avatar>
</v-list-tile> <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-list>
</v-menu> </v-menu>
@ -1129,44 +1118,58 @@ Entities
const Eval=Vue.extend({template:` const Eval=Vue.extend({template:`
<v-container fluid=""> <v-container fluid="">
<v-card> <v-card>
<v-toolbar dense="">
<v-toolbar>
<v-menu offset-x="">
<v-menu offset-y=""> <v-btn slot="activator" flat="" icon="" color="pink">
<v-btn slot="activator"> <v-icon>label_outline</v-icon>
<v-icon>play_circle_outline</v-icon> </v-btn>
Run</v-btn> <v-card>
<v-list> <v-card-title>Outline here</v-card-title>
<v-list-tile @click="submit"> </v-card>
<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> </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> <v-icon>library_books</v-icon>
Imports</v-btn> Imports</v-btn>
<v-btn @click="namespaces"> <v-btn @click="namespaces">
<v-icon>label</v-icon> <v-icon>label</v-icon>
Namespaces</v-btn> Namespaces</v-btn>
<v-menu offset-y=""> </v-card>
<v-btn icon="" color="primary" slot="activator"> <v-icon>more_vert</v-icon></v-btn> </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 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> </v-menu>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-toolbar> </v-toolbar>
@ -1178,7 +1181,7 @@ Entities
<v-card-actions v-if="show"> <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-chip label="" class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar> <v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
@ -1214,10 +1217,11 @@ Entities
result:'', result:'',
elapsed: null, elapsed: null,
show: false, show: false,
showError: false, //unused showError: false,
showResult: false, // showResult: false, //
jobId: null, job: {}, // {id:"12",result:"job13"}
waiting: false, waiting: false,
destroyed: false,
start: null, start: null,
jobState: {}, jobState: {},
aceSettings:{} aceSettings:{}
@ -1253,7 +1257,7 @@ Entities
HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq})) HTTPNE.post("eval/submit",Qs.stringify({xq:this.xq}))
.then(r=>{ .then(r=>{
this.elapsed=Math.floor(performance.now() - this.start); this.elapsed=Math.floor(performance.now() - this.start);
this.jobId=r.data.job this.job=r.data
this.show=true this.show=true
this.pollState() this.pollState()
@ -1261,14 +1265,15 @@ Entities
.catch(r=> { .catch(r=> {
alert("catch") alert("catch")
console.log("error",r) console.log("error",r)
this.jobId=r.response.job this.job=r.response.job
this.showError=true; this.showError=true;
}); });
}, },
pollState(){ pollState(){
if(this.destroyed)return;
this.waiting=true; this.waiting=true;
HTTP.get("job/"+this.jobId) HTTP.get("job/"+this.job.result)
.then(r=>{ .then(r=>{
this.jobState=r.data this.jobState=r.data
this.waiting=r.data.state!="cached"; this.waiting=r.data.state!="cached";
@ -1282,7 +1287,7 @@ Entities
}, },
getResult(){ getResult(){
this.awaitResult(true) this.awaitResult(true)
HTTPNE.post("eval/result/"+this.jobId) HTTPNE.post("eval/result/"+this.job.result)
.then(r=>{ .then(r=>{
this.result=r.data.result+" " this.result=r.data.result+" "
}).catch(r=> { }).catch(r=> {
@ -1305,7 +1310,7 @@ Entities
alert("@TODO namespaces") alert("@TODO namespaces")
}, },
plan(){ plan(){
this.awaitResult(false) this.awaitResult(true)
HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq})) HTTPNE.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{ .then(r=>{
this.result=r.data.result this.result=r.data.result
@ -1335,8 +1340,13 @@ Entities
})}) })})
}, },
created:function(){ created:function(){
console.log("eval: creatd");
localforage.getItem('eval/xq').then((value) => { this.xq=value || this.xq}); 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:` const Images=Vue.extend({template:`
<v-card> <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-btn @click.stop="showFilter = true" icon=""><v-icon>search</v-icon></v-btn>
<v-toolbar-title>{{ qtext }}</v-toolbar-title> <v-toolbar-title>{{ qtext }}</v-toolbar-title>
<v-tooltip top="" v-if="query.keyword || query.from || query.until"> <v-tooltip top="" v-if="query.keyword || query.from || query.until">
@ -1521,56 +1531,66 @@ Entities
<v-icon>clear</v-icon> <v-icon>clear</v-icon>
</v-btn> </v-btn>
<span>Clear search</span> <span>Clear search</span>
</v-tooltip> </v-tooltip>
<v-btn icon="" @click="getImages">
<v-avatar>
<v-icon>refresh</v-icon>
</v-avatar>
</v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<span v-if="!busy"> <span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip> <v-toolbar-items v-if="!selection.length">
<v-btn icon="" v-for="b in buttons" :key="b.icon" @click="action(b)">
Page:{{ query.page+1 }} <v-avatar>
<v-btn @click.stop="pageBack()" :disabled="query.page==0" icon="" color="primary"> <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-icon>arrow_back</v-icon>
</v-avatar>
</v-btn> </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-icon>arrow_forward</v-icon>
</v-avatar>
</v-btn> </v-btn>
</span> </v-toolbar-items>
</v-toolbar> </v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear> <v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
<v-container v-if="!busy" fluid="" grid-list-md=""> <v-container v-if="!busy" fluid="" grid-list-md="">
<v-layout row="" wrap="" v-touch="{ left: () => pageNext(), right: () => pageBack()}"> <v-layout row="" wrap="" v-touch="{ left: () => pageNext(), right: () => pageBack()}">
<v-flex height="80px" xs2="" v-for="image in images" :key="image.name"> <v-flex height="80px" xs2="" v-for="image in images" :key="image.name">
<v-card class="grey lighten-2 pt-1"> <v-card flat="" tile="" class="grey lighten-2 pa-1">
<v-card-media :src="src(image)" @dblclick="go(image)" height="80px" contain=""> <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-media>
<v-card-actions> <div v-if="image.selected" style="position:absolute;right:0;top:0">
<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">
<v-icon class="white primary--text">check_circle</v-icon> <v-icon class="white primary--text">check_circle</v-icon>
</div> </div>
</v-card></v-flex> </v-card></v-flex>
</v-layout> </v-layout>
</v-container> </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-card>
<v-toolbar class="green white--text"> <v-toolbar class="green white--text">
<v-toolbar-title>Show images with...</v-toolbar-title> <v-toolbar-title>Show images with...</v-toolbar-title>
@ -1627,22 +1647,30 @@ Entities
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-navigation-drawer> </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-card>
<v-toolbar class="green white--text"> <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-spacer></v-spacer>
<v-btn flat="" icon="" @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn> <v-btn flat="" icon="" @click="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
</v-toolbar> </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-card>
</v-navigation-drawer> </v-navigation-drawer>
</v-card> </v-card>
`, `,
data: () => ({
data(){
return {
images:[], images:[],
query: {page:0, // current page query: {page:0, // current page
from:null, from:null,
@ -1658,8 +1686,18 @@ Entities
keywords: [], keywords: [],
showInfo: false, showInfo: false,
selitem: "TODO", 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:{ methods:{
src(item){ src(item){
return "data:image/jpeg;base64,"+item.data return "data:image/jpeg;base64,"+item.data
@ -1676,19 +1714,36 @@ Entities
this.total=r.data.total this.total=r.data.total
this.images=r.data.items this.images=r.data.items
var t1 = performance.now(); 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(){ clear(){
this.query.from=null; this.query.from=null;
this.query.until=null; this.query.until=null;
this.query.keyword=null; this.query.keyword=null;
this.query.page=0; this.query.page=0;
}, },
selectAll(){
this.images.forEach(item=>{item.selected=true})
},
selectNone(){
this.images.forEach(item=>{item.selected=false})
},
selected(image){ selected(image){
this.selitem=image; this.selitem=image;
this.showInfo=true; this.showInfo=true;
}, },
action(b){
b.method(b.icon)
},
share(){
alert("sHARE: "+ this.selection.length);
},
isChanged(vnew,vold){ isChanged(vnew,vold){
if(vnew.keyword != vold.keyword) return true if(vnew.keyword != vold.keyword) return true
if(vnew.from != vold.from) 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 k=this.query.keyword,f=this.query.from, u=this.query.until
var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"") var t= (k?" keyword:'"+k+"'":"")+ (f?" from:" + f:"")+ (u?" until:" + u:"")
return t?t:"(All)" return t?t:"(All)"
},
selection(){
return this.images.filter(item=>{return item.selected} )
} }
}, },
watch:{ watch:{
@ -1765,14 +1823,34 @@ Entities
<v-spacer></v-spacer> <v-spacer></v-spacer>
</v-toolbar> </v-toolbar>
<v-card-text> <v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
body <v-card-text v-if="!busy" v-html="report"></v-card-text>
</v-card-text>
</v-card> </v-card>
</v-container> </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-card-title>
<v-spacer></v-spacer> <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-toolbar>
<v-card-text> <v-card-text>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear> <v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
@ -1812,7 +1890,8 @@ body
busy: false, busy: false,
total: 0, total: 0,
items: [], items: [],
elapsed: null elapsed: null,
q:""
}), }),
methods:{ methods:{
@ -1830,6 +1909,9 @@ body
}, },
show(keyword){ show(keyword){
this.$router.push({ name: 'images', query: { keyword: keyword.text }}) this.$router.push({ name: 'images', query: { keyword: keyword.text }})
},
setfilter(){
alert("not yet")
} }
}, },
created:function(){ created:function(){
@ -1945,7 +2027,8 @@ people
<v-btn @click="stop()" :disabled="noSelection">Stop</v-btn> <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-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-spacer></v-spacer>
<v-btn icon="" :loading="loading" @click="getJobs()" @dblclick="autorefresh = !autorefresh" :disabled="loading"> <v-btn icon="" :loading="loading" @click="getJobs()" @dblclick="autorefresh = !autorefresh" :disabled="loading">
@ -2089,7 +2172,7 @@ people
const Map=Vue.extend({template:` const Map=Vue.extend({template:`
<v-container fluid=""> <v-container fluid="">
<v-layout row="" wrap=""> <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-map :zoom="zoom" :center="center">
<v-tilelayer :url="url" :attribution="attribution"></v-tilelayer> <v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
<v-marker :lat-lng="marker"></v-marker> <v-marker :lat-lng="marker"></v-marker>
@ -2108,6 +2191,15 @@ people
marker: L.latLng(54.320498718, -2.739663708) 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(){ created:function(){
console.log("map") console.log("map")
} }
@ -2814,7 +2906,8 @@ namespaces
); );
const Svg=Vue.extend({template:` const Svg=Vue.extend({template:`
<v-container fluid=""> <v-container fluid="">
svg <div id="canvasqPWKOg" class="canvas"></div>
<button id="resetButtonqPWKOg">Reset</button>
</v-container> </v-container>
`, `,
@ -2830,8 +2923,25 @@ svg
); );
const Tabs=Vue.extend({template:` const Tabs=Vue.extend({template:`
<v-tabs scroll-bars=""> <v-tabs scroll-bars="" fixed="">
<v-card>
<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-card-actions>
<v-btn icon=""> <v-btn icon="">
<v-icon>menu</v-icon> <v-icon>menu</v-icon>
@ -2846,20 +2956,6 @@ svg
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-card> </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-items>
<v-tabs-content v-for="i in 13" :key="i" :id="'mobile-tabs-6-' + i"> <v-tabs-content v-for="i in 13" :key="i" :id="'mobile-tabs-6-' + i">
<v-card flat=""> <v-card flat="">
@ -3397,7 +3493,7 @@ created(){
</v-card> </v-card>
</v-menu> </v-menu>
</v-toolbar> </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-layout v-if="showOptions.includes('result')" style="height:100%" fill-height="">
<v-flex> <v-flex>
@ -3490,9 +3586,21 @@ created(){
} }
); );
const router = new VueRouter({ // vue-poc application routes
const router = new VueRouter({
base:"/vue-poc/ui/", base:"/vue-poc/ui/",
mode: 'history', 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: [ routes: [
{ path: '/', component: Home, meta:{title:"Home"} }, { path: '/', component: Home, meta:{title:"Home"} },
{ path: '/session', component: Session ,meta: {title:"Session"}}, { path: '/session', component: Session ,meta: {title:"Session"}},
@ -3560,19 +3668,23 @@ router.beforeEach((to, from, next) => {
} }
});const Vuepoc=Vue.extend({template:` });const Vuepoc=Vue.extend({template:`
<v-app id="app" :dark="dark"> <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-card>
<v-toolbar class="teal white--text"> <v-toolbar class="teal white--text">
<v-toolbar-title>Notifications</v-toolbar-title> <v-toolbar-title>Notifications </v-toolbar-title>
<v-spacer></v-spacer> <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-toolbar>
<v-card-text> <v-card-text>
TODO <ul>
<li v-for="msg in $notification.messages" :key="msg.index">
{{msg.text}}
</li>
</ul>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-navigation-drawer> </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 class="pa-0">
<v-list-tile avatar="" tag="div"> <v-list-tile avatar="" tag="div">
@ -3598,11 +3710,12 @@ router.beforeEach((to, from, next) => {
<v-toolbar class="indigo" app="" dark=""> <v-toolbar class="indigo" app="" dark="">
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon> <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-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-icon>star_border</v-icon>
</v-btn> </v-btn>
<v-dialog v-model="frmFav">
<v-card> <v-card style="width:400px;">
<v-toolbar class="amber"> <v-toolbar class="amber">
<v-card-title> <v-card-title>
Bookmark this page 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-select v-model="tags" label="tags" chips="" tags="" :items="taglist"></v-select>
</v-card-text> </v-card-text>
<v-card-actions> <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="frmFav=false">Cancel</v-btn>
<v-btn color="primary" flat="" @click.stop="favorite();frmFav=false">Save</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-menu>
<v-spacer></v-spacer> <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-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> <v-spacer></v-spacer>
@ -3639,11 +3753,11 @@ router.beforeEach((to, from, next) => {
</v-list> </v-list>
</v-menu> </v-menu>
<qd-fullscreen></qd-fullscreen> <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-icon>notifications</v-icon>
</v-btn> </v-btn>
</v-toolbar> </v-toolbar>
<main>
<v-content> <v-content>
<v-alert color="error" value="true" dismissible="" v-model="alert.show"> <v-alert color="error" value="true" dismissible="" v-model="alert.show">
<pre style="overflow:auto;">{{ alert.msg }}</pre> <pre style="overflow:auto;">{{ alert.msg }}</pre>
@ -3652,7 +3766,7 @@ router.beforeEach((to, from, next) => {
<router-view class="view ma-3"></router-view> <router-view class="view ma-3"></router-view>
</transition> </transition>
</v-content> </v-content>
</main>
</v-app> </v-app>
`, `,
@ -3661,7 +3775,7 @@ router.beforeEach((to, from, next) => {
q: "", q: "",
status: {}, status: {},
drawer: true, drawer: true,
drawerRight: false, showNotifications: false,
mini: false, mini: false,
dark: false, dark: false,
alert: {show:false,msg:"Hello"}, alert: {show:false,msg:"Hello"},
@ -3767,9 +3881,6 @@ router.beforeEach((to, from, next) => {
}, },
favorite(){ favorite(){
alert("@TODO") alert("@TODO")
},
notifications(){
this.drawerRight=true
} }
}, },
@ -3844,6 +3955,19 @@ const Auth={
}; };
Vue.use(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 // Mimetype info
const MimeTypes={ const MimeTypes={
"text/xml":"xml", "text/xml":"xml",

View file

@ -123,4 +123,35 @@ height: 100%;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; 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="description" content="Vue poc" />
<meta name="author" content="andy bunce." /> <meta name="author" content="andy bunce." />
<title>Vue Router Test</title> <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/css?family=Roboto:300,400,500,700,400italic"/>
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons"> <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/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 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" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ==" integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
crossorigin=""/> crossorigin=""/>
<link href="/vue-poc/ui/app.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 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="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" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.20.1/vis-timeline-graph2d.min.css" />
</head> </head>
<body> <body>
<div id="app"> <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="spinner">
<div class="rect1"></div> <div class="rect1"></div>
@ -37,26 +34,27 @@
</div> </div>
</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/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://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://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/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ext-language_tools.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.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-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/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/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/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://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" <script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log==" integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
crossorigin=""></script> crossorigin=""></script>
<script src="https://unpkg.com/vue2-leaflet@0.0.55/dist/vue2-leaflet.js"></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/perf-stat.js"></script>
<script src="/vue-poc/ui/app-gen.js"></script> <script src="/vue-poc/ui/app-gen.js"></script>
</body> </body>

View file

@ -1,13 +1,5 @@
html, body {
font-family: Arial, sans-serif;
}
.title {
font-size: 12px;
}
.canvas { .canvas {
overflow: hidden; overflow: hidden;
fill: #808040;
} }
.canvas .wrapper.outer > .background { .canvas .wrapper.outer > .background {
fill: #000000; fill: #000000;
@ -25,12 +17,15 @@ html, body {
cursor: move; cursor: move;
} }
.canvas .minimap .frame {
pointer-events: all;
}
.canvas .minimap .frame .background { .canvas .minimap .frame .background {
stroke: #111111; stroke: #111111;
stroke-width: 4px; stroke-width: 4px;
fill-opacity: 0.4; fill-opacity: 0.1;
fill: #000000; fill: #000000;
fill: url(#minimapGradient_qwpyza); fill: url(#minimapGradient_qwpyza);
xfilter: url(#minimapDropShadow_qwpyza); filter: url(#minimapDropShadow_qwpyza);
cursor: move; 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 = {}; d3.demo = {};
/** CANVAS **/ /** CANVAS **/
d3.demo.canvas = function() { d3.demo.canvas = function() {
"use strict"; "use strict";
var width = 500, var width = 500,
height = 500, height = 500,
zoomEnabled = true, base = null,
dragEnabled = true, wrapperBorder = 0,
scale = 1, minimap = null,
translation = [0,0], minimapPadding = 10,
base = null, minimapScale = 0.25;
wrapperBorder = 2,
minimap = null,
minimapPadding = 20,
minimapScale = 0.25;
function canvas(selection) { function canvas(selection) {
base = selection; base = selection;
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 xScale = d3.scale.linear() var svgDefs = svg.append("defs");
.domain([-width / 2, width / 2]) svgDefs.append("clipPath")
.range([0, width]); .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 yScale = d3.scale.linear() var filter = svgDefs.append("svg:filter")
.domain([-height / 2, height / 2]) .attr("id", "minimapDropShadow_qwpyza")
.range([height, 0]); .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 zoomHandler = function(newScale) { var minimapRadialFill = svgDefs.append("radialGradient")
if (!zoomEnabled) { return; } .attr('id', "minimapGradient")
if (d3.event) { .attr('gradientUnits', "userSpaceOnUse")
scale = d3.event.scale; .attr('cx', "500")
} else { .attr('cy', "500")
scale = newScale; .attr('r', "400")
} .attr('fx', "500")
if (dragEnabled) { .attr('fy', "500");
var tbound = -height * scale, minimapRadialFill.append("stop")
bbound = height * scale, .attr("offset", "0%")
lbound = -width * scale, .attr("stop-color", "#FFFFFF");
rbound = width * scale; minimapRadialFill.append("stop")
// limit translation to thresholds .attr("offset", "40%")
translation = d3.event ? d3.event.translate : [0, 0]; .attr("stop-color", "#EEEEEE")
translation = [ minimapRadialFill.append("stop")
Math.max(Math.min(translation[0], rbound), lbound), .attr("offset", "100%")
Math.max(Math.min(translation[1], bbound), tbound) .attr("stop-color", "#E0E0E0");
];
}
d3.select(".panCanvas, .panCanvas .bg") var outerWrapper = svg.append("g")
.attr("transform", "translate(" + translation + ")" + " scale(" + scale + ")"); .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 innerWrapper = outerWrapper.append("g")
.attr("class", "wrapper inner")
.attr("clip-path", "url(#wrapperClipPath_qwpyza)")
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")");
minimap.scale(scale).render(); innerWrapper.append("rect")
}; // startoff zoomed in a bit to show pan/zoom rectangle .attr("class", "background")
.attr("width", width)
.attr("height", height);
var zoom = d3.behavior.zoom() var panCanvas = innerWrapper.append("g")
.x(xScale) .attr("class", "panCanvas")
.y(yScale) .attr("width", width)
.scaleExtent([0.1, 10]) .attr("height", height)
.on("zoom.canvas", zoomHandler); .attr("transform", "translate(0,0)");
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 svgDefs = svg.append("defs"); panCanvas.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var zoom = d3.zoom()
.scaleExtent([0.5, 5]);
svgDefs.append("clipPath") // updates the zoom boundaries based on the current size and scale
.attr("id", "wrapperClipPath_qwpyza") var updateCanvasZoomExtents = function() {
.attr("class", "wrapper clipPath") var scale = innerWrapper.property("__zoom").k;
.append("rect") var targetWidth = svgWidth;
.attr("class", "background") 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("width", width)
.attr("height", height); .attr("height", height);
svgDefs.append("clipPath") svg
.attr("id", "minimapClipPath_qwpyza") .attr("width", width + (wrapperBorder*2) + minimapPadding*2 + (width*minimapScale))
.attr("class", "minimap clipPath") .attr("height", height + (wrapperBorder*2));
.attr("width", width)
.attr("height", height)
//.attr("transform", "translate(" + (width + minimapPadding) + "," + (minimapPadding/2) + ")")
.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height);
var filter = svgDefs.append("svg:filter") outerWrapper
.attr("id", "minimapDropShadow_qwpyza") .select(".background")
.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")
.attr("width", width + wrapperBorder*2) .attr("width", width + wrapperBorder*2)
.attr("height", height + wrapperBorder*2); .attr("height", height + wrapperBorder*2);
var innerWrapper = outerWrapper.append("g") innerWrapper
.attr("class", "wrapper inner")
.attr("clip-path", "url(#wrapperClipPath_qwpyza)")
.attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")") .attr("transform", "translate(" + (wrapperBorder) + "," + (wrapperBorder) + ")")
.call(zoom); .select(".background")
innerWrapper.append("rect")
.attr("class", "background")
.attr("width", width) .attr("width", width)
.attr("height", height); .attr("height", height);
var panCanvas = innerWrapper.append("g") panCanvas
.attr("class", "panCanvas")
.attr("width", width) .attr("width", width)
.attr("height", height) .attr("height", height)
.attr("transform", "translate(0,0)"); .select(".background")
panCanvas.append("rect")
.attr("class", "background")
.attr("width", width) .attr("width", width)
.attr("height", height); .attr("height", height);
minimap = d3.demo.minimap() minimap
.zoom(zoom)
.target(panCanvas)
.minimapScale(minimapScale)
.x(width + minimapPadding) .x(width + minimapPadding)
.y(minimapPadding); .y(minimapPadding)
.render();
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;
}; };
canvas.height = function(value) { canvas.reset = function() {
if (!arguments.length) return height; //svg.call(zoom.event);
height = parseInt(value, 10); //svg.transition().duration(750).call(zoom.event);
return this; zoom.transform(panCanvas, d3.zoomIdentity);
svg.property("__zoom", d3.zoomIdentity);
minimap.update(d3.zoomIdentity);
}; };
canvas.scale = function(value) { canvas.update = function(minimapZoomTransform) {
if (!arguments.length) { return scale; } zoom.transform(panCanvas, minimapZoomTransform);
scale = value; // update the '__zoom' property with the new transform on the rootGroup which is where the zoomBehavior stores it since it was the
return this; // call target during initialization
innerWrapper.property("__zoom", minimapZoomTransform);
updateCanvasZoomExtents();
}; };
updateCanvasZoomExtents();
}
return canvas;
//============================================================
// 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, "use strict";
scale = 1,
zoom = null,
base = null,
target = null,
width = 0,
height = 0,
x = 0,
y = 0,
frameX = 0,
frameY = 0;
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") base = selection;
.attr("class", "minimap")
.call(zoom); var zoom = d3.zoom()
.scaleExtent([0.5, 5]);
zoom.on("zoom.minimap", function() { // updates the zoom boundaries based on the current size and scale
scale = d3.event.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);
minimap.node = container.node(); var container = selection.append("g")
.attr("class", "minimap");
var frame = container.append("g") container.call(zoom);
.attr("class", "frame")
frame.append("rect") minimap.node = container.node();
.attr("class", "background")
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.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);
updateMinimapZoomExtents();
};
/** 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("width", width)
.attr("height", height) .attr("height", height);
.attr("filter", "url(#minimapDropShadow_qwpyza)"); frame.node().parentNode.appendChild(frame.node());
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;
}; };
updateMinimapZoomExtents();
minimap.height = function(value) { }
if (!arguments.length) return height;
height = parseInt(value, 10);
return this;
};
minimap.x = function(value) { //============================================================
if (!arguments.length) return x; // Accessors
x = parseInt(value, 10); //============================================================
return this;
};
minimap.y = function(value) { minimap.width = function(value) {
if (!arguments.length) return y; if (!arguments.length) return width;
y = parseInt(value, 10); width = parseInt(value, 10);
return this; 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;
}; };
/** UTILS **/ minimap.height = function(value) {
d3.demo.util = {}; if (!arguments.length) return height;
d3.demo.util.getXYFromTranslate = function(translateString) { height = parseInt(value, 10);
var currentTransform = d3.transform(translateString); return this;
currentX = currentTransform.translate[0];
currentY = currentTransform.translate[1];
return [currentX, currentY];
}; };
/** 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"> <template id="vuepoc">
<v-app id="app" :dark="dark" > <v-app id="app" :dark="dark" >
<v-navigation-drawer <v-navigation-drawer
persistent absolute
v-model="drawerRight" v-model="showNotifications"
right right
clipped clipped
:disable-route-watcher="true" :disable-route-watcher="true"
app app
> >
<v-card> <v-card>
<v-toolbar class="teal white--text"> <v-toolbar class="teal white--text">
<v-toolbar-title >Notifications</v-toolbar-title> <v-toolbar-title >Notifications </v-toolbar-title>
<v-spacer></v-spacer> <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-toolbar>
<v-card-text> <v-card-text>
TODO <ul>
<li v-for="msg in $notification.messages" :key="msg.index">
{{msg.text}}
</li>
</ul>
</v-card-text> </v-card-text>
</v-card> </v-card>
</v-navigation-drawer> </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"> :disable-route-watcher="true" :enable-resize-watcher="true">
<v-list class="pa-0"> <v-list class="pa-0">
@ -47,11 +51,17 @@
<v-toolbar class="indigo" app dark > <v-toolbar class="indigo" app dark >
<v-toolbar-side-icon @click.stop="drawer = !drawer" ></v-toolbar-side-icon> <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-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-icon>star_border</v-icon>
</v-btn> </v-btn>
<v-dialog v-model="frmFav">
<v-card> <v-card style="width:400px;">
<v-toolbar class="amber"> <v-toolbar class="amber">
<v-card-title> <v-card-title>
Bookmark this page Bookmark this page
@ -68,11 +78,12 @@
></v-select> ></v-select>
</v-card-text> </v-card-text>
<v-card-actions> <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="frmFav=false">Cancel</v-btn>
<v-btn color="primary" flat @click.stop="favorite();frmFav=false">Save</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-menu>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Search..." v-model="q" <v-text-field prepend-icon="search" label="Search..." v-model="q"
hide-details single-line dark @keyup.enter="search"></v-text-field> hide-details single-line dark @keyup.enter="search"></v-text-field>
@ -95,11 +106,11 @@
</v-list> </v-list>
</v-menu> </v-menu>
<qd-fullscreen></qd-fullscreen> <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-icon>notifications</v-icon>
</v-btn> </v-btn>
</v-toolbar> </v-toolbar>
<main>
<v-content> <v-content>
<v-alert color="error" value="true" dismissible v-model="alert.show"> <v-alert color="error" value="true" dismissible v-model="alert.show">
<pre style="overflow:auto;">{{ alert.msg }}</pre> <pre style="overflow:auto;">{{ alert.msg }}</pre>
@ -108,7 +119,7 @@
<router-view class="view ma-3"></router-view> <router-view class="view ma-3"></router-view>
</transition> </transition>
</v-content> </v-content>
</main>
</v-app> </v-app>
</template> </template>
@ -118,7 +129,7 @@
q: "", q: "",
status: {}, status: {},
drawer: true, drawer: true,
drawerRight: false, showNotifications: false,
mini: false, mini: false,
dark: false, dark: false,
alert: {show:false,msg:"Hello"}, alert: {show:false,msg:"Hello"},
@ -224,9 +235,6 @@
}, },
favorite(){ favorite(){
alert("@TODO") alert("@TODO")
},
notifications(){
this.drawerRight=true
} }
}, },