use localforage

This commit is contained in:
Andy Bunce 2017-06-16 23:15:01 +01:00
parent 18b2d52841
commit e608486453
17 changed files with 957 additions and 92 deletions

View file

@ -0,0 +1,6 @@
declare namespace fw="quodatum:collection.walker";
declare namespace c="http://www.w3.org/ns/xproc-step";
import module namespace tree="quodatum.data.tree" at "lib/tree.xqm";
let $paths:=uri-collection("/ALO")
return tree:build($paths)

View file

@ -0,0 +1,69 @@
<p:library
xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step"
xmlns:xpt="https://github.com/apb2006/xproc-enrich"
xmlns:xpdoc="http://xproc.org/xpdoc"
version="1.0">
<p:documentation>Convert xpl to standard format
taken from Phillip Fennel's xproc-plus-time
https://code.google.com/p/xproc-plus-time/
</p:documentation>
<p:declare-step type="xpt:parse">
<p:input port="source">
<p:documentation>
An xproc document
</p:documentation>
</p:input>
<p:output port="result">
<p:documentation xmlns="http://www.w3.org/1999/xhtml"><p>
Copy of the source in a standard format with
additional info
<ol>
<li>normalize : pipeline elements replaced with declare-step</li>
<li>augment: add missing (default) ports with @xml:id</li>
<li>connect: add @xpt:boundPorts showing links</li>
</ol>
</p></p:documentation>
</p:output>
<p:xslt>
<p:documentation>
Normalises XProc pipelines.
</p:documentation>
<p:input port="stylesheet">
<p:document href="etc/normalise-pipeline.xsl" />
</p:input>
<p:input port="parameters">
<p:empty />
</p:input>
</p:xslt>
<p:xslt name="augment-steps">
<p:documentation>
Adds missing 'implied' information.
</p:documentation>
<p:input port="stylesheet">
<p:document href="etc/augment-steps.xsl" />
</p:input>
<p:input port="parameters">
<p:empty />
</p:input>
</p:xslt>
<p:xslt name="connect-steps">
<p:documentation>
Makes step connections explicit.
</p:documentation>
<p:input port="stylesheet">
<p:document href="etc/connect-steps.xsl" />
</p:input>
<p:input port="parameters">
<p:empty />
</p:input>
</p:xslt>
</p:declare-step>
</p:library>

78
src/vue-poc/lib/tree.xqm Normal file
View file

@ -0,0 +1,78 @@
xquery version "3.1";
module namespace tree = 'quodatum.data.tree';
(:~
: convert path(s) to tree
:)
declare function tree:build($a as xs:string*)
{
fn:fold-right($a,
(),
function($a,$b){tree:merge(tree:tree($a),$b)}
)
};
declare function tree:w($this,$seen)
as element(*)
{
<directory name="{$this}">{$seen}</directory>
};
declare function tree:tree($path as xs:string)
as element(*)
{
let $parts:=fn:tokenize($path,"/")
return fn:fold-right(subsequence($parts,1,count($parts)-1),
<file name="{$parts[last()]}"/>,
tree:w#2
)
};
declare function tree:merge($a1 as element(*)?,$a2 as element(*)?)
as element(*)*
{
if($a1/@name=$a2/@name) then
let $n1:=$a1/*
let $n2:=$a2/*
let $t:=(
for $x in fn:distinct-values($n1/@name[.=$n2/@name]) (:both:)
return tree:merge($a1/*[@name=$x],$a2/*[@name=$x]),
for $x in fn:distinct-values($n1/@name[fn:not(.=$n2/@name)]) (:only $a1 :)
return $a1/*[@name=$x],
for $x in fn:distinct-values($n2/@name[fn:not(.=$n1/@name)]) (:only $a2 :)
return $a2/*[@name=$x]
)
return tree:w($a1/@name,for $x in $t order by $x/@name return $x)
else
($a1,$a2)
};
declare %unit:test
(:~
: smoke test
:)
function tree:test(){
let $a:=("/",
"/api/environment/",
"/api/execute/",
"/api/library/",
"/api/library/",
"/api/library/{$id}/",
"/api/library/{$id}/",
"/api/state/",
"/api/~testbed/",
"/api/state/",
"/api/state/",
"/api/suite/",
"/api/suite/{$suite}/",
"/api/execute/zz")
let $t:=tree:build($a)
return unit:assert(fn:true())
};

View file

@ -20,23 +20,21 @@ declare variable $vue-login:SESSION-VALUE := Session:get($vue-login:SESSION-KEY)
:)
declare
%rest:path("/vue-poc/api/login-check")
%rest:query-param("name", "{$name}")
%rest:query-param("pass", "{$pass}")
%rest:query-param("redirect", "{$path}")
%rest:form-param("username", "{$name}")
%rest:form-param("password", "{$pass}")
function vue-login:login(
$name as xs:string,
$pass as xs:string,
$path as xs:string?
$pass as xs:string
) as element(rest:response) {
try {
user:check($name, $pass),
if(false() and user:list-details($name)/@permission ) then (
vue-login:reject($name, 'Admin credentials required.', $path)
vue-login:reject($name, 'Admin credentials required.', "$path")
) else (
vue-login:accept($name, $pass, $path)
vue-login:accept($name, $pass, "$path")
)
} catch user:* {
vue-login:reject($name, 'Please check your login data.', $path)
vue-login:reject($name, 'Please check your login data.', "$path")
}
};

26
src/vue-poc/ping.xqm Normal file
View file

@ -0,0 +1,26 @@
module namespace ping = 'quodatum.test.ping';
declare variable $ping:db as xs:string:="doc-doc";
declare variable $ping:state as element(state):=db:open($ping:db,"/state.xml")/state;
(:~
: ping incr counter
:)
declare %updating
%rest:POST %rest:path("/vue-poc/api/ping")
%output:method("text")
function ping:dopost()
{
(replace value of node $ping:state/hits with 1+$ping:state/hits,
db:output(1+$ping:state/hits))
};
(:~
: ping incr counter
:)
declare
%output:method("text")
%rest:GET %rest:path("/vue-poc/api/ping")
function ping:dostate()
{
$ping:state/hits
};

View file

@ -1,4 +1,4 @@
// generated 2017-06-04T17:31:45.572+01:00
// generated 2017-06-16T23:13:22.444+01:00
const Edit=Vue.extend({template:`
<v-container fluid="">
<v-layout row="" wrap="">
@ -95,6 +95,11 @@
<v-list-tile-title @click="fetch('/vue-poc/static/app.html')">load html</v-list-tile-title>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile>
<v-list-tile-title @click="fetch('/vue-poc/static/app.css')">load css</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar-items>
@ -249,6 +254,48 @@
}
}
);
const Extension=Vue.extend({template:`
<v-container fluid="">
<v-layout>
<table>
<tbody><tr v-for="(item, row) in grid">
<td v-for="(cell,col) in item" style="width:3em;" @click="click(row,col)">{{cell}}</td>
</tr>
</tbody></table>
</v-layout>
<a href="http://homepages.cwi.nl/~steven/Talks/2017/06-10-iot/game-demo.html">demo</a>
</v-container>
`,
data: function(){
return {grid: [
[1,5,8,12],
[2,6,9,13],
[3,7,10,14],
[4,null,11,15]
],
empty:[3,1]
}
},
methods: {
click: function (row,col) {
var g=this.grid
var h=g[row][col]
g[row][col]=null
g[this.empty[0]][this.empty[1]]=h
var e=[row,col]
this.empty=e
this.grid= g
console.log("click",this.grid,e)
this.$forceUpdate()
}
}
}
);
const Files=Vue.extend({template:`
<v-container fluid="">
@ -280,7 +327,7 @@ const Files=Vue.extend({template:`
</v-list-tile-avatar>
<v-list-tile-content @click="folder(item.name)">
<v-list-tile-title>{{ item.name }}</v-list-tile-title>
<v-list-tile-sub-title>modified: {{ item.modified | formatDate}} size: {{ item.size | any}}</v-list-tile-sub-title>
<v-list-tile-sub-title>modified: {{ item.modified | formatDate}} size: {{ item.size | readablizeBytes}}</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-btn icon="" ripple="" @click.native="info(item.name)">
@ -404,6 +451,7 @@ const Home=Vue.extend({template:`
<li><a href="https://github.com/monterail/vue-multiselect">vue-multiselect</a></li>
<li><a href="https://github.com/sagalbot/vue-select"><s>vue-select</s></a></li>
<li><a href="https://github.com/beautify-web/js-beautify">js-beautify</a></li>
<li><a href="http://localhost:8984/doc/#/data/app/vue-poc">doc</a></li>
</ul>
</v-flex>
@ -430,7 +478,7 @@ const Login=Vue.extend({template:`
</v-card-row>
<v-card-row>
<v-text-field name="input-password" label="Enter your password" hint="Enter your password" v-model="password" :append-icon="e1 ? 'visibility' : 'visibility_off'" :append-icon-cb="() => (e1 = !e1)" :type="e1 ? 'password' : 'text'" required=""></v-text-field>
<v-text-field name="input-password" label="Enter your password" hint="Enter your password" v-model="password" :append-icon="hidepass ? 'visibility' : 'visibility_off'" :append-icon-cb="() => (hidepass = !hidepass)" :type="hidepass ? 'password' : 'text'" required=""></v-text-field>
</v-card-row>
<v-divider></v-divider>
@ -443,15 +491,27 @@ const Login=Vue.extend({template:`
data () {
return {
e1: true,
hidepass: true,
name:'',
password: ''
}
},
methods:{
go () {
HTTP.post("login-check",axios_json)
this.hidepass=true
var data=Qs.stringify(
{
username: this.name, //gave the values directly for testing
password: this.password,
client_id: 'user-client'
})
HTTP.post("login-check", data,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
.then(r=>{
console.log(r)
alert("loh")
}).catch(error=> {
alert("err")
@ -537,6 +597,131 @@ const People=Vue.extend({template:`
}
);
const Ping=Vue.extend({template:`
<v-container fluid="">
<p>Simple performance measure. Read or increment a database value.</p>
<h2>Counter:{{counter}}</h2>
<table class="table">
<thead>
<tr>
<th>Option</th>
<th>Repeat</th>
<th>Last</th>
<th>Count</th>
<th>Median</th>
<th>Avg</th>
<th>min</th>
<th>max</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<v-btn dark="" @click.native="get()">Get count</v-btn>
</td>
<td>
<v-checkbox v-model="repeat.get" dark=""></v-checkbox>
</td>
<td>
<span>{{getValues.last}}</span>
</td>
<td>
<span>{{getValues.count}}</span>
</td>
<td>
<span>{{getValues.median}}</span>
</td>
<td>
<span>{{getValues.avg | round(2)}}</span>
</td>
<td>
<span>{{getValues.min}}</span>
</td>
<td>
<span>{{getValues.max}}</span>
</td>
</tr>
<tr>
<td>
<v-btn dark="" @click.native="update()">Update count</v-btn>
</td>
<td>
<v-checkbox v-model="repeat.post" dark=""></v-checkbox>
</td>
<td class="col-md-1">
<span>{{postValues.last}}</span>
</td>
<td class="col-md-1">
<span>{{postValues.count}}</span>
</td>
<td class="col-md-1">
<span>{{postValues.median}}</span>
</td>
<td class="col-md-1">
<span>{{postValues.avg | round(2)}}</span>
</td>
<td class="col-md-1">
<span>{{postValues.min}}</span>
</td>
<td class="col-md-1">
<span>{{postValues.max}}</span>
</td>
</tr>
</tbody>
</table>
</v-container>
`,
data: function(){
return {
getValues: new perfStat(),
postValues: new perfStat(),
repeat:{get:false,post:false},
counter:0
}
},
methods:{
update () {
var _start = performance.now();
HTTP.post("ping",axios_json)
.then(r=>{
var elapsed=Math.floor(performance.now() - _start);
this.counter=r.data
Object.assign(this.postValues,this.postValues.log(elapsed))
if(this.repeat.post){
this.update(); //does this leak??
}
})
},
get(){
var _start = performance.now();
HTTP.get("ping",axios_json)
.then(r=>{
var elapsed=Math.floor(performance.now() - _start);
this.counter=r.data
Object.assign(this.getValues,this.getValues.log(elapsed))
this.$forceUpdate()
if(this.repeat.get){
this.get(); //does this leak??
}
})
}
},
computed: {
}
}
);
const Search=Vue.extend({template:`
<v-container fluid="">
@ -617,68 +802,100 @@ const Select=Vue.extend({template:`
);
const Stepper=Vue.extend({template:`
<v-container fluid="">
<v-stepper v-model="step" non-linear="">
<v-stepper-header>
<v-stepper-step step="1" :complete="step > 1">Select image location</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="2" :complete="step > 2">Set thumbnail details</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Result</v-stepper-step>
</v-stepper-header>
<v-stepper-content step="1" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
<v-text-field name="url" label="Image Url" hint="http:...??" v-model="image" required=""></v-text-field>
</v-card>
<v-btn primary="" @click.native="step = 2">Next</v-btn>
</v-stepper-content>
<v-stepper-content step="2" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
<vue-ace editor-id="editorA" :content="taskxml" mode="xml" wrap="true" v-on:change-content="onChange"></vue-ace>
</v-card>
<v-btn flat="" @click.native="step -= 1">Back</v-btn>
<v-btn primary="" @click.native="step = 3">Next</v-btn>
</v-stepper-content>
const Settings=Vue.extend({template:`
<v-layout row="">
<v-flex xs12="" sm6="" offset-sm3="">
<v-card>
<v-stepper-content step="3" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
output todo
</v-card>
<v-btn flat="" @click.native="step -= 1">Back</v-btn>
<v-btn primary="" @click.native="go()">go</v-btn>
</v-stepper-content>
</v-stepper>
</v-container>
<v-list two-line="" subheader="">
<v-subheader>Ace editor settings</v-subheader>
<v-list-item>
<v-list-tile avatar="">
<v-list-tile-action>
<v-checkbox v-model="ace.notifications"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Notifications</v-list-tile-title>
<v-list-tile-sub-title>Allow notifications</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar="">
<v-list-tile-action>
<v-checkbox v-model="ace.sound"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Sound</v-list-tile-title>
<v-list-tile-sub-title>Hangouts message</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar="">
<v-list-tile-action>
<v-checkbox v-model="ace.video"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Video sounds</v-list-tile-title>
<v-list-tile-sub-title>Hangouts vidoe call</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar="">
<v-list-tile-action>
<v-checkbox v-model="ace.invites"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Invites</v-list-tile-title>
<v-list-tile-sub-title>Notify when receiving invites</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</v-list>
</v-card>
</v-flex>
</v-layout>
`,
data(){
data () {
return {
image:"http://images.metmuseum.org/CRDImages/ep/original/DT46.jpg",
step: 0,
taskxml:"<task></task>"
}
ace: {
notifications: false,
sound: false,
video: false,
invites: false
}
}
},
methods:{
onChange (val) {
if (this.taskxml !== val) this.taskxml = val;
},
go(){
alert("post")
HTTP.post("thumbnail",Qs.stringify({task: this.taskxml,url:this.image}))
.then(function(r){
console.log(r)
alert("not yet:"+r);
})
}
created: function () {
// `this` points to the vm instance
console.log('created: ')
localforage.getItem('ace').then((value) => {
console.log('oh say can you see, ' + value);
this.ace=value || this.ace
}).catch((err) => {
console.log('the rockets red glare has blinded me');
});
},
updated: function () {
// `this` points to the vm instance
console.log('updated: ')
localforage.setItem('ace', this.ace).then((value) => {
console.log('woot! we saved ' + value);
}).catch((err) => {
console.log('he\'s dead, jim!');
});
},
methods: {
reverseMessage: function () {
alert("unused")
}
}
}
);
const Tabs=Vue.extend({template:`
<v-tabs id="mobile-tabs-6" scroll-bars="" light="">
@ -722,6 +939,73 @@ const Tabs=Vue.extend({template:`
}
}
);
const Thumbnail=Vue.extend({template:`
<v-container fluid="">
<v-stepper v-model="step" non-linear="">
<v-stepper-header>
<v-stepper-step step="1" :complete="step > 1">Select image location</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="2" :complete="step > 2">Set thumbnail details</v-stepper-step>
<v-divider></v-divider>
<v-stepper-step step="3">Result</v-stepper-step>
</v-stepper-header>
<v-stepper-content step="1" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
<v-text-field name="url" label="Image Url" hint="http:...??" v-model="image" required=""></v-text-field>
</v-card>
<v-btn primary="" @click.native="step = 2">Next</v-btn>
</v-stepper-content>
<v-stepper-content step="2" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
<vue-ace editor-id="editorA" :content="taskxml" mode="xml" wrap="true" v-on:change-content="onChange"></vue-ace>
</v-card>
<v-btn flat="" @click.native="step -= 1">Back</v-btn>
<v-btn primary="" @click.native="validate()">Validate</v-btn>
<v-btn primary="" @click.native="step = 3">Next</v-btn>
</v-stepper-content>
<v-stepper-content step="3" non-linear="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
output todo
</v-card>
<v-btn flat="" @click.native="step -= 1">Back</v-btn>
<v-btn primary="" @click.native="go()">go</v-btn>
</v-stepper-content>
</v-stepper>
</v-container>
`,
data(){
return {
image:"http://images.metmuseum.org/CRDImages/ep/original/DT46.jpg",
step: 0,
taskxml:"<task></task>"
}
},
methods:{
onChange (val) {
if (this.taskxml !== val) this.taskxml = val;
},
validate(){
alert
},
go(){
alert("post")
HTTP.post("thumbnail",Qs.stringify({task: this.taskxml,url:this.image}))
.then(function(r){
console.log(r)
alert("not yet:"+r);
})
}
}
}
);
// base -----------------------
localforage.config({
@ -736,10 +1020,12 @@ const HTTP = axios.create({
});
const axios_json={ headers: {accept: 'application/json'}};
// Filters:
//Define the date time format filter
Vue.filter("formatDate", function(date) {
return moment(date).format("MMMM D, YYYY")
});
Vue.filter('readablizeBytes', function (bytes,decimals) {
if(bytes == 0) return '0 Bytes';
var k = 1000,
@ -751,6 +1037,25 @@ Vue.filter('readablizeBytes', function (bytes,decimals) {
Vue.filter("any", function(any) {
return "ANY"
});
/**
* Vue filter to round the decimal to the given place.
* http://jsfiddle.net/bryan_k/3ova17y9/
*
* @param {String} value The value string.
* @param {Number} decimals The number of decimal places.
*/
Vue.filter('round', function(value, decimals) {
if(!value) {
value = 0;
}
if(!decimals) {
decimals = 0;
}
value = Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
return value;
});
Vue.config.errorHandler = function (err, vm, info) {
// handle error
@ -773,7 +1078,7 @@ const router = new VueRouter({
base:"/vue-poc/ui/",
mode: 'history',
routes: [
{ path: '/', component: Home },
{ path: '/', component: Home,meta:{title:"Home"} },
{ path: '/people', component: People ,meta:{title:"People"}},
{ path: '/options', component: Options,meta:{title:"Options"} },
{ path: '/select', component: Select,meta:{title:"Select"} },
@ -781,8 +1086,11 @@ const router = new VueRouter({
{ path: '/tabs', component: Tabs,meta:{title:"tab test",requiresAuth: true} },
{ path: '/login', component: Login,meta:{title:"login"} },
{ path: '/edit', component: Edit,meta:{title:"Ace editor"} },
{ path: '/stepper', component: Stepper,meta:{title:"Stepper"} },
{ path: '/files', component: Files,meta:{title:"Files"} }
{ path: '/thumbnail', component: Thumbnail,meta:{title:"Thumbnail generator"} },
{ path: '/files', component: Files,meta:{title:"Files"} },
{ path: '/ping', component: Ping,meta:{title:"Ping"} },
{ path: '/settings', component: Settings,meta:{title:"Settings"} },
{ path: '/extension', component: Extension,meta:{title:"Xform"} }
],
});
router.afterEach(function(route) {
@ -813,7 +1121,7 @@ const app = new Vue({
q:"",
status:{},
drawer:true,
title:"my title2",
title:"@TODO title",
mini: false,
items: [{
href: '/',
@ -861,10 +1169,25 @@ const app = new Vue({
title: 'login',
icon: 'account_balance'
}, {
href: 'stepper',
href: 'ping',
router: true,
title: 'stepper',
icon: 'touch_app'
title: 'ping',
icon: 'update'
},{
href: 'thumbnail',
router: true,
title: 'thumbnail',
icon: 'touch_app'
},{
href: 'settings',
router: true,
title: 'settings',
icon: 'settings'
},{
href: 'extension',
router: true,
title: 'extension',
icon: 'extension'
}]
}},

View file

@ -9,7 +9,7 @@
<title>Vue Router Test</title>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<link href="https://unpkg.com/vuetify@0.12.6/dist/vuetify.min.css" rel="stylesheet" type="text/css">
<link href="https://unpkg.com/vuetify@0.12.7/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="/vue-poc/ui/app.css" rel="stylesheet" type="text/css">
@ -19,7 +19,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.5.3/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/qs/6.4.0/qs.js"></script>
<script src="https://unpkg.com/vuetify@0.12.6/dist/vuetify.min.js"></script>
<script src="https://unpkg.com/vuetify@0.12.7/dist/vuetify.min.js"></script>
<script src="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ext-language_tools.js"></script>
@ -30,6 +30,8 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/localforage/1.5.0/localforage.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.js"></script>
<script src="/vue-poc/ui/perf-stat.js"></script>
<script src="/vue-poc/ui/vue-ace.js"></script>
</head>
<body>
@ -73,7 +75,7 @@
<v-toolbar class="blue" >
<v-toolbar-side-icon @click.native.stop="drawer = !drawer" ></v-toolbar-side-icon>
<v-toolbar-title class="hidden-sm-and-down">{{title}}</v-toolbar-title>
<v-toolbar-title class="hidden-sm-and-down">{{$route.meta.title}}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Search..." v-model="q"
hide-details single-line dark @keyup.native.enter="search"></v-text-field>

View file

@ -11,10 +11,12 @@ const HTTP = axios.create({
});
const axios_json={ headers: {accept: 'application/json'}};
// Filters:
//Define the date time format filter
Vue.filter("formatDate", function(date) {
return moment(date).format("MMMM D, YYYY")
});
Vue.filter('readablizeBytes', function (bytes,decimals) {
if(bytes == 0) return '0 Bytes';
var k = 1000,
@ -26,6 +28,25 @@ Vue.filter('readablizeBytes', function (bytes,decimals) {
Vue.filter("any", function(any) {
return "ANY"
});
/**
* Vue filter to round the decimal to the given place.
* http://jsfiddle.net/bryan_k/3ova17y9/
*
* @param {String} value The value string.
* @param {Number} decimals The number of decimal places.
*/
Vue.filter('round', function(value, decimals) {
if(!value) {
value = 0;
}
if(!decimals) {
decimals = 0;
}
value = Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
return value;
});
Vue.config.errorHandler = function (err, vm, info) {
// handle error
@ -48,7 +69,7 @@ const router = new VueRouter({
base:"/vue-poc/ui/",
mode: 'history',
routes: [
{ path: '/', component: Home },
{ path: '/', component: Home,meta:{title:"Home"} },
{ path: '/people', component: People ,meta:{title:"People"}},
{ path: '/options', component: Options,meta:{title:"Options"} },
{ path: '/select', component: Select,meta:{title:"Select"} },
@ -56,8 +77,11 @@ const router = new VueRouter({
{ path: '/tabs', component: Tabs,meta:{title:"tab test",requiresAuth: true} },
{ path: '/login', component: Login,meta:{title:"login"} },
{ path: '/edit', component: Edit,meta:{title:"Ace editor"} },
{ path: '/stepper', component: Stepper,meta:{title:"Stepper"} },
{ path: '/files', component: Files,meta:{title:"Files"} }
{ path: '/thumbnail', component: Thumbnail,meta:{title:"Thumbnail generator"} },
{ path: '/files', component: Files,meta:{title:"Files"} },
{ path: '/ping', component: Ping,meta:{title:"Ping"} },
{ path: '/settings', component: Settings,meta:{title:"Settings"} },
{ path: '/extension', component: Extension,meta:{title:"Xform"} }
],
});
router.afterEach(function(route) {
@ -88,7 +112,7 @@ const app = new Vue({
q:"",
status:{},
drawer:true,
title:"my title2",
title:"@TODO title",
mini: false,
items: [{
href: '/',
@ -136,10 +160,25 @@ const app = new Vue({
title: 'login',
icon: 'account_balance'
}, {
href: 'stepper',
href: 'ping',
router: true,
title: 'stepper',
icon: 'touch_app'
title: 'ping',
icon: 'update'
},{
href: 'thumbnail',
router: true,
title: 'thumbnail',
icon: 'touch_app'
},{
href: 'settings',
router: true,
title: 'settings',
icon: 'settings'
},{
href: 'extension',
router: true,
title: 'extension',
icon: 'extension'
}]
}},

View file

@ -0,0 +1,37 @@
// performance monitoring. of value stream
// stores max min etc
function perfStat() {
this.data={count:0,max:null,min:null,total:0,median:0,last:null};
// add a value return updated stats
this.log=function(val){
var data=this.data
data.last=val;
data.total+=val;
data.count+=1;
if(data.count==1){
data.max=val;
data.min=val;
data.median=val;
}else{
if(val<data.min)data.min=val;
if(val>data.max)data.max=val;
};
//https://jeremykun.com/2012/06/14/streaming-median/
if (data.median > val)
data.median-= 1
else if( data.median < val)
data.median += 1;
data.avg=data.total / data.count;
// console.log("stats",data);
return data;
};
// clear stats
this.clear=function(){
this.data={count:0,max:null,min:null,total:0};
};
// return values
this.values=function(){
return this.data;
};
}

View file

@ -97,6 +97,11 @@
<v-list-tile-title @click="fetch('/vue-poc/static/app.html')">load html</v-list-tile-title>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile>
<v-list-tile-title @click="fetch('/vue-poc/static/app.css')">load css</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar-items>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<template id="extension">
<v-container fluid>
<v-layout >
<table>
<tr v-for="(item, row) in grid">
<td v-for="(cell,col) in item" style="width:3em;" @click="click(row,col)">{{cell}}</td>
</tr>
</table>
</v-layout>
<a href="http://homepages.cwi.nl/~steven/Talks/2017/06-10-iot/game-demo.html">demo</a>
</v-container>
</template>
<script>{
data: function(){
return {grid: [
[1,5,8,12],
[2,6,9,13],
[3,7,10,14],
[4,null,11,15]
],
empty:[3,1]
}
},
methods: {
click: function (row,col) {
var g=this.grid
var h=g[row][col]
g[row][col]=null
g[this.empty[0]][this.empty[1]]=h
var e=[row,col]
this.empty=e
this.grid= g
console.log("click",this.grid,e)
this.$forceUpdate()
}
}
}
</script>

View file

@ -30,7 +30,7 @@
</v-list-tile-avatar>
<v-list-tile-content @click="folder(item.name)">
<v-list-tile-title>{{ item.name }}</v-list-tile-title>
<v-list-tile-sub-title>modified: {{ item.modified | formatDate}} size: {{ item.size | any}}</v-list-tile-sub-title>
<v-list-tile-sub-title>modified: {{ item.modified | formatDate}} size: {{ item.size | readablizeBytes}}</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-btn icon ripple @click.native="info(item.name)">

View file

@ -16,6 +16,7 @@
<li><a href="https://github.com/monterail/vue-multiselect">vue-multiselect</a></li>
<li><a href="https://github.com/sagalbot/vue-select"><s>vue-select</s></a></li>
<li><a href="https://github.com/beautify-web/js-beautify">js-beautify</a></li>
<li><a href="http://localhost:8984/doc/#/data/app/vue-poc">doc</a></li>
</ul>
</v-flex>

View file

@ -23,9 +23,9 @@
label="Enter your password"
hint="Enter your password"
v-model="password"
:append-icon="e1 ? 'visibility' : 'visibility_off'"
:append-icon-cb="() => (e1 = !e1)"
:type="e1 ? 'password' : 'text'"
:append-icon="hidepass ? 'visibility' : 'visibility_off'"
:append-icon-cb="() => (hidepass = !hidepass)"
:type="hidepass ? 'password' : 'text'"
required
></v-text-field>
</v-card-row>
@ -41,15 +41,27 @@
<script>{
data () {
return {
e1: true,
hidepass: true,
name:'',
password: ''
}
},
methods:{
go () {
HTTP.post("login-check",axios_json)
this.hidepass=true
var data=Qs.stringify(
{
username: this.name, //gave the values directly for testing
password: this.password,
client_id: 'user-client'
})
HTTP.post("login-check", data,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
.then(r=>{
console.log(r)
alert("loh")
}).catch(error=> {
alert("err")

View file

@ -0,0 +1,126 @@
<!DOCTYPE html>
<template id="ping">
<v-container fluid>
<p>Simple performance measure. Read or increment a database value.</p>
<h2>Counter:{{counter}}</h2>
<table class="table">
<thead>
<tr>
<th>Option</th>
<th >Repeat</th>
<th >Last</th>
<th >Count</th>
<th >Median</th>
<th >Avg</th>
<th >min</th>
<th >max</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<v-btn dark @click.native="get()" >Get count</v-btn>
</td>
<td>
<v-checkbox v-model="repeat.get" dark></v-checkbox>
</td>
<td>
<span >{{getValues.last}}</span>
</td>
<td>
<span >{{getValues.count}}</span>
</td>
<td>
<span >{{getValues.median}}</span>
</td>
<td>
<span >{{getValues.avg | round(2)}}</span>
</td>
<td>
<span >{{getValues.min}}</span>
</td>
<td>
<span >{{getValues.max}}</span>
</td>
</tr>
<tr>
<td>
<v-btn dark @click.native="update()" >Update count</v-btn>
</td>
<td>
<v-checkbox v-model="repeat.post" dark></v-checkbox>
</td>
<td class="col-md-1">
<span >{{postValues.last}}</span>
</td>
<td class="col-md-1">
<span >{{postValues.count}}</span>
</td >
<td class="col-md-1">
<span >{{postValues.median}}</span>
</td>
<td class="col-md-1">
<span >{{postValues.avg | round(2)}}</span>
</td>
<td class="col-md-1">
<span >{{postValues.min}}</span>
</td>
<td class="col-md-1">
<span >{{postValues.max}}</span>
</td>
</tr>
</tbody>
</table>
</v-container>
</template>
<script>{
data: function(){
return {
getValues: new perfStat(),
postValues: new perfStat(),
repeat:{get:false,post:false},
counter:0
}
},
methods:{
update () {
var _start = performance.now();
HTTP.post("ping",axios_json)
.then(r=>{
var elapsed=Math.floor(performance.now() - _start);
this.counter=r.data
Object.assign(this.postValues,this.postValues.log(elapsed))
if(this.repeat.post){
this.update(); //does this leak??
}
})
},
get(){
var _start = performance.now();
HTTP.get("ping",axios_json)
.then(r=>{
var elapsed=Math.floor(performance.now() - _start);
this.counter=r.data
Object.assign(this.getValues,this.getValues.log(elapsed))
this.$forceUpdate()
if(this.repeat.get){
this.get(); //does this leak??
}
})
}
},
computed: {
}
}
</script>

View file

@ -0,0 +1,96 @@
<!DOCTYPE html>
<template id="settings">
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<v-list two-line subheader>
<v-subheader>Ace editor settings</v-subheader>
<v-list-item>
<v-list-tile avatar>
<v-list-tile-action>
<v-checkbox v-model="ace.notifications"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Notifications</v-list-tile-title>
<v-list-tile-sub-title>Allow notifications</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar>
<v-list-tile-action>
<v-checkbox v-model="ace.sound"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Sound</v-list-tile-title>
<v-list-tile-sub-title>Hangouts message</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar>
<v-list-tile-action>
<v-checkbox v-model="ace.video"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Video sounds</v-list-tile-title>
<v-list-tile-sub-title>Hangouts vidoe call</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item>
<v-list-tile avatar>
<v-list-tile-action>
<v-checkbox v-model="ace.invites"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Invites</v-list-tile-title>
<v-list-tile-sub-title>Notify when receiving invites</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</v-list>
</v-card>
</v-flex>
</v-layout>
</template>
<script>{
data () {
return {
ace: {
notifications: false,
sound: false,
video: false,
invites: false
}
}
},
created: function () {
// `this` points to the vm instance
console.log('created: ')
localforage.getItem('ace').then((value) => {
console.log('oh say can you see, ' + value);
this.ace=value || this.ace
}).catch((err) => {
console.log('the rockets red glare has blinded me');
});
},
updated: function () {
// `this` points to the vm instance
console.log('updated: ')
localforage.setItem('ace', this.ace).then((value) => {
console.log('woot! we saved ' + value);
}).catch((err) => {
console.log('he\'s dead, jim!');
});
},
methods: {
reverseMessage: function () {
alert("unused")
}
}
}
</script>

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<template id="stepper">
<template id="thumbnail">
<v-container fluid>
<v-stepper v-model="step" non-linear>
<v-stepper-header>
@ -31,7 +31,8 @@
</v-card>
<v-btn flat @click.native="step -= 1">Back</v-btn>
<v-btn primary @click.native="step = 3">Next</v-btn>
<v-btn primary @click.native="validate()">Validate</v-btn>
<v-btn primary @click.native="step = 3">Next</v-btn>
</v-stepper-content>
<v-stepper-content step="3" non-linear>
@ -58,6 +59,9 @@
onChange (val) {
if (this.taskxml !== val) this.taskxml = val;
},
validate(){
alert
},
go(){
alert("post")
HTTP.post("thumbnail",Qs.stringify({task: this.taskxml,url:this.image}))