basic eval

This commit is contained in:
Andy Bunce 2017-06-24 12:18:53 +01:00
parent c747404055
commit 81b53aea83
25 changed files with 1036 additions and 196 deletions

87
src/vue-poc/lib/cons.xqm Normal file
View file

@ -0,0 +1,87 @@
(:~
: Global constants and functions.
:
: @author Christian Grün, BaseX Team, 2014-16
:)
module namespace cons = 'vue-poc/cons';
import module namespace Request = 'http://exquery.org/ns/request';
import module namespace Session = 'http://basex.org/modules/session';
(:~ Session key. :)
declare variable $cons:SESSION-KEY := "vue-poc";
(:~ Current session. :)
declare variable $cons:SESSION-VALUE := Session:get($cons:SESSION-KEY);
(:~ Directory for DBA files. :)
declare variable $cons:DBA-DIR := file:temp-dir() || 'vue-poc/';
(:~ Configuration file. :)
declare variable $cons:DBA-SETTINGS-FILE := $cons:DBA-DIR || 'poc-settings.xml';
(:~ Permissions. :)
declare variable $cons:PERMISSIONS := ('none', 'read', 'write', 'create', 'admin');
(:~ Maximum length of XML characters. :)
declare variable $cons:K-MAXCHARS := 'maxchars';
(:~ Maximum number of table entries. :)
declare variable $cons:K-MAXROWS := 'maxrows';
(:~ Query timeout. :)
declare variable $cons:K-TIMEOUT := 'timeout';
(:~ Maximal memory consumption. :)
declare variable $cons:K-MEMORY := 'memory';
(:~ Permission when running queries. :)
declare variable $cons:K-PERMISSION := 'permission';
(:~ Configuration. :)
declare variable $cons:OPTION :=
let $defaults := map {
'maxchars': 100000,
'maxrows': 100,
'timeout': 10,
'memory': 500,
'permission': 'admin'
}
return if(file:exists($cons:DBA-SETTINGS-FILE)) then (
try {
(: merge defaults with options from settings file :)
let $configs := fetch:xml($cons:DBA-SETTINGS-FILE)/config
return map:merge(
map:for-each($defaults, function($key, $value) {
map:entry($key,
let $config := $configs/*[name() = $key]
return if($config) then (
if($value instance of xs:numeric) then xs:integer($config) else xs:string($config)
) else (
$value
)
)
})
)
} catch * {
(: use defaults if an error occurs while parsing the configuration file :)
$defaults
}
) else (
$defaults
);
(:~
: Checks if the current client is logged in. If not, raises an error.
:)
declare function cons:check(
) as empty-sequence() {
if($cons:SESSION-VALUE) then () else
error(xs:QName('basex:login'), 'Please log in again.', Request:path())
};
(:~
: Convenience function for redirecting to another page from update operations.
: @param $url URL
: @param $params query parameters
:)
declare %updating function cons:redirect(
$url as xs:string,
$params as map(*)
) as empty-sequence() {
db:output(web:redirect($url, $params))
};

122
src/vue-poc/lib/util.xqm Normal file
View file

@ -0,0 +1,122 @@
(:~
: Utility functions.
:
: @author Christian Grün, BaseX Team, 2014-16
:)
module namespace util = 'vue-poc/util';
import module namespace cons = 'vue-poc/cons' at 'cons.xqm';
(:~
: Evaluates a query and returns the result.
: @param $query query string
: @param $context initial context value
: @return serialized result of query
:)
declare function util:query(
$query as xs:string?,
$context as item()*
) as xs:string {
let $limit := $cons:OPTION($cons:K-MAXCHARS)
let $result := xquery:eval($query, map { '': $context }, util:query-options())
(: serialize more characters than requested, because limit represents number of bytes :)
return util:chop(serialize($result, map { 'limit': $limit * 2 + 1, 'method': 'basex' }), $limit)
};
(:~
: Runs an updating query.
: @param $query query string
: @return empty sequence
:)
declare %updating function util:update-query(
$query as xs:string?
) {
xquery:update($query, map { }, util:query-options())
};
(:~
: Returns the options for evaluating a query.
: @return options
:)
declare %private function util:query-options() as map(*) {
map {
'timeout' : $cons:OPTION($cons:K-TIMEOUT),
'memory' : $cons:OPTION($cons:K-MEMORY),
'permission': $cons:OPTION($cons:K-PERMISSION)
}
};
(:~
: Checks if the specified binary input can be converted to an XML string.
: @param $input input
: @return XML string
:)
declare function util:to-xml-string(
$input as xs:base64Binary
) as xs:string {
let $string :=
try {
convert:binary-to-string($input)
} catch * {
error((), "Input is no valid UTF8 string.")
}
return
try {
(: tries to convert the input to XML, but discards the results :)
prof:void(parse-xml($string)),
$string
} catch * {
error((), "Input is no well-formed XML.")
}
};
(:~
: Returns the index of the first result to generate.
: @param $page current page
: @param $sort sort key
: @return last result
:)
declare function util:start(
$page as xs:integer,
$sort as xs:string
) as xs:integer {
if($page and not($sort)) then (
($page - 1) * $cons:OPTION($cons:K-MAXROWS) + 1
) else (
1
)
};
(:~
: Returns the index of the last result to generate.
: @param $page current page
: @param $sort sort key
: @return last result
:)
declare function util:end(
$page as xs:integer,
$sort as xs:string
) as xs:integer {
if($page and not($sort)) then (
$page * $cons:OPTION($cons:K-MAXROWS)
) else (
999999999
)
};
(:~
: Chops a string result to the maximum number of allowed characters.
: @param $string string
: @param $max maximum number of characters
: @return string
:)
declare function util:chop(
$string as xs:string,
$max as xs:integer
) {
if(string-length($string) > $max) then (
substring($string, 1, $max) || '...'
) else (
$string
)
};

View file

@ -3,38 +3,43 @@
:
:)
module namespace vue-login = 'vue-poc/login';
import module namespace session = "http://basex.org/modules/session";
import module namespace Session = 'http://basex.org/modules/session';
(:~ Session key. :)
declare variable $vue-login:SESSION-KEY := "vue-poc";
(:~ Current session. :)
declare variable $vue-login:SESSION-VALUE := Session:get($vue-login:SESSION-KEY);
declare variable $vue-login:SESSION-VALUE := session:get($vue-login:SESSION-KEY);
(:~
: Checks the user input and redirects to the main page, or back to the login page.
: @param $name user name
: @param $pass password
: @param $path path to redirect to (optional)
: @return redirect
: @return true/false
:)
declare
%rest:path("/vue-poc/api/login-check")
%rest:form-param("username", "{$name}")
%rest:form-param("password", "{$pass}")
%rest:form-param("redirect", "{$path}")
%rest:produces("application/json")
%output:method("json")
function vue-login:login(
$name as xs:string,
$pass as xs:string
) as element(rest:response) {
$pass as xs:string,
$path as xs:string?)
as element(json)
{
try {
user:check($name, $pass),
if(false() and user:list-details($name)/@permission ) then (
vue-login:reject($name, 'Admin credentials required.', "$path")
if( user:list-details($name)/@permission ne "admin") then (
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)
}
};
@ -48,23 +53,24 @@ function vue-login:logout(
) as element(rest:response) {
admin:write-log('vue-poc user was logged out: ' || $vue-login:SESSION-VALUE),
web:redirect("/vue-poc/login", map { 'name': $vue-login:SESSION-VALUE }),
Session:delete($vue-login:SESSION-KEY)
session:delete($vue-login:SESSION-KEY)
};
(:~
: Accepts a user and redirects to the main page.
: @param $name entered user name
: @param $path path to redirect to
: @return redirect
:)
declare %private function vue-login:accept(
$name as xs:string,
$pass as xs:string,
$path as xs:string?
) {
Session:set($vue-login:SESSION-KEY, $name),
session:set($vue-login:SESSION-KEY, $name),
admin:write-log('VUEPOC user was logged in: ' || $name),
web:redirect(if($path) then $path else "/")
<json type="object">
<status type="boolean">true</status>
</json>
};
(:~
@ -72,13 +78,16 @@ declare %private function vue-login:accept(
: @param $name entered user name
: @param $message error message
: @param $path path to redirect to
: @return redirect
: @return json
:)
declare %private function vue-login:reject(
$name as xs:string,
$message as xs:string,
$path as xs:string?
) as element(rest:response) {
admin:write-log('DBA login was denied: ' || $name),
web:redirect("login", map { 'name': $name, 'error': $message, 'path': $path })
$path as xs:string?)
as element(json) {
admin:write-log('VUE login was denied: ' || $name),
<json type="object">
<status type="boolean">false</status>
<message>{$message}</message>
</json>
};

View file

@ -1,4 +1,4 @@
// generated 2017-06-21T16:59:58.292+01:00
// generated 2017-06-24T12:17:19.685+01:00
/**
* vue filters
*/
@ -78,7 +78,7 @@ const Edit=Vue.extend({template:`
<span>{{ name }}</span>
</v-toolbar-title>
<v-toolbar-items>
<span v-tooltip:top="{ html: 'Change' }">
<span v-tooltip:top="{ html: 'Changed?' }">
<v-chip v-if="dirty" label="" small="" class="red white--text">*</v-chip>
<v-chip v-if="!dirty" label="" small="" class="green white--text">.</v-chip>
</span>
@ -153,28 +153,30 @@ const Edit=Vue.extend({template:`
</v-list>
</v-menu>
</v-toolbar-items>
<v-dialog v-model="clearDialog">
<v-card>
<v-card-row>
<v-card-title>Clear?</v-card-title>
</v-card-row>
<v-card-row>
<v-card-text>clear text.</v-card-text>
</v-card-row>
<v-card-row actions="">
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(false)">Cancel</v-btn>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(true)">Ok</v-btn>
</v-card-row>
</v-card>
</v-dialog>
</v-app-bar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
<v-flex xs12="" style="height:70vh" v-if="!busy" fill-height="">
<vue-ace editor-id="editorA" :content="contentA" :mode="mode" :wrap="wrap" v-on:change-content="changeContentA" v-on:annotation="annotation"></vue-ace>
<v-dialog v-model="clearDialog">
<v-card-row>
<v-card-title>Clear?</v-card-title>
</v-card-row>
<v-card-row>
<v-card-text>clear text.</v-card-text>
</v-card-row>
<v-card-row actions="">
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(false)">Cancel</v-btn>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(true)">Ok</v-btn>
</v-card-row>
</v-dialog></v-flex></v-card>
<vue-ace :content="contentA" :mode="mode" :wrap="wrap" v-on:change-content="changeContentA" v-on:annotation="annotation"></vue-ace>
</v-flex>
</v-card>
</v-container>
`,
@ -203,6 +205,7 @@ const Edit=Vue.extend({template:`
"text/ecmascript":"javascript",
"application/sparql-query":"sparql",
"text/html":"html",
"text/turtle":"turtle",
"text/css":"css"
}
}
@ -252,7 +255,17 @@ const Edit=Vue.extend({template:`
Events.$emit('eventFired',"foldall");
},
save(){
alert("TODO save: "+this.path.join("/"));
alert("TODO save: "+this.url);
var data=Qs.stringify(
{
url: this.url, //gave the values directly for testing
data: this.contentA
})
HTTP.post("edit", data,{
headers: { "Content-Type": "application/x-www-form-urlencoded"}
}).then(r=>{
alert("AAA")
})
},
showfiles(){
router.push({ path: 'files', query: { url: this.path.join("/") }})
@ -312,20 +325,59 @@ const Edit=Vue.extend({template:`
);
const Eval=Vue.extend({template:`
<v-container fluid="">
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px">
<vue-ace editor-id="editorA" :content="xq" mode="xquery" wrap="true" v-on:change-content="onChange"></vue-ace>
<v-card class="grey lighten-1 z-depth-1 mb-5">
<v-card-row>
<v-btn @click.native="run()">Run</v-btn>
<v-btn @click.native="submit()">Submit</v-btn>
</v-card-row>
<v-card-row height="200px">
<vue-ace :content="xq" mode="xquery" wrap="true" v-on:change-content="onChange"></vue-ace>
</v-card-row>
</v-card>
<v-alert error="" v-bind:value="showError">
{{result}}
</v-alert>
<v-card v-if="show">
<v-card-row height="200px">
<vue-ace :content="result" mode="text" wrap="true" read-only="true"></vue-ace>
</v-card-row>
</v-card>
</v-container>
`,
data: function(){
return {
xq: '(:~ do something :)'
xq: '(: type your XQuery :)\n',
result:'',
elapsed:null,
show:false,
showError:false
}
},
methods:{
onChange(){
console.log("go")
onChange(val){
if (this.xq !== val) {
this.xq = val
}
},
run(){
var data={xq:this.xq}
this.showError=this.show=false
HTTP.post("eval/execute",Qs.stringify(data))
.then(r=>{
this.result=r.data.result
this.show=true
})
.catch(r=> {
console.log("error",r)
this.result=r.response.data
this.showError=true;
});
},
submit(){
alert("submit")
}
},
created:function(){
@ -339,17 +391,18 @@ const Files=Vue.extend({template:`
<v-card>
<v-app-bar>
<v-menu offset-y="">
<v-btn icon="" dark="" slot="activator"><v-icon>folder</v-icon></v-btn>
<v-list>
<v-list-item v-for="item in crumbs" :key="item">
<v-list-tile>
<v-list-tile-title @click="root()">{{ item }}</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
<v-menu>
<v-btn icon="" dark="" slot="activator"><v-icon>folder</v-icon></v-btn>
<v-list>
<v-list-item v-for="item in crumbs" :key="item">
<v-list-tile>
<v-list-tile-title @click="root()">{{ item }}</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
<v-toolbar-title>{{ url }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search" hide-details="" single-line="" dark="" @keyup.native.enter="filter"></v-text-field>
<v-icon>view_module</v-icon>
@ -535,7 +588,7 @@ const Home=Vue.extend({template:`
<v-flex xs4="">
<p>This is a experiment in using <code>vue.js</code>.</p>
<ul>
<li><a href="https://vuetifyjs.com/" target="new">vuetifyjs</a></li>
<li><a href="https://vuetifyjs.com/vuetify/quick-start" target="new">vuetifyjs</a></li>
<li><a href="https://github.com/monterail/vue-multiselect" target="new">vue-multiselect</a></li>
<li><a href="https://github.com/sagalbot/vue-select" target="new"><s>vue-select</s></a></li>
<li><a href="https://github.com/beautify-web/js-beautify" target="new">js-beautify</a></li>
@ -546,21 +599,64 @@ const Home=Vue.extend({template:`
<v-btn floating="floating">
<v-icon>add</v-icon>
</v-btn>
<my-component>REPLACED</my-component>
<my-component href="/dba">REPLACED</my-component>
</v-layout>
`,
}
);
const Job=Vue.extend({template:`
<v-container fluid="">
<h1>JOBS</h1>
<nav-apb :items="items"></nav-apb>
</v-container>
`,
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q,
items:[
{href: '/',text: 'Home', icon: 'home' },
{href: 'files', text: 'File system',icon: 'folder' },
{href: 'edit',text: 'edit',icon: 'mode_edit'},
{href: 'history',text: 'history',icon: 'history'},
{href: 'eval',text: 'Evaluate',icon: 'cake'},
{href: 'tasks',text: 'Tasks',icon: 'build'},
{href: 'jobs',text: 'Jobs',icon: 'print'},
{href: 'logs',text: 'Server logs',icon: 'dns'},
{href: 'people',text: 'People',icon: 'person'},
{href: 'select',text: 'select',icon: 'extension'},
{href: 'puzzle',text: 'Puzzle',icon: 'extension'},
{href: 'options',text: 'options',icon: 'domain'},
{href: 'tabs',text: 'tabs',icon: 'switch_camera'},
{href: 'ping',text: 'ping',icon: 'update'},
{href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'},
{href: 'settings',text: 'settings',icon: 'settings' }
]
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
);
const Login=Vue.extend({template:`
<v-card class="grey lighten-4 elevation-0">
<v-card-row class="green darken-1">
<v-card-title>
<span class="white--text">Login</span>
</v-card-title>
</v-card-row>
<v-alert error="" v-bind:value="showMessage">
{{message}}
</v-alert>
<v-card-row>
<v-text-field name="input-name" label="Enter your name" hint="name??" v-model="name" required=""></v-text-field>
</v-card-row>
@ -581,33 +677,57 @@ const Login=Vue.extend({template:`
return {
hidepass: true,
name:'',
password: ''
password: '',
redirect: this.$route.query.redirect,
message:"",
showMessage:false
}
},
methods:{
go () {
this.hidepass=true
this.showMessage=false
var data=Qs.stringify(
{
username: this.name, //gave the values directly for testing
password: this.password,
client_id: 'user-client'
redirect: this.redirect
})
HTTP.post("login-check", data,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
HTTP.post("login-check", data)
.then(r=>{
console.log(r)
alert("loh")
console.log("login",r.data)
if(r.data.status){
this.$auth.role="admin"
this.$router.replace(this.redirect)
}else{
this.message=r.data.message
this.showMessage=true;
}
}).catch(error=> {
alert("err")
alert("err login")
})
}
}
}
);
const Log=Vue.extend({template:`
<v-container fluid="">
<h1>LOGS</h1>
</v-container> `,
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
);
const Options=Vue.extend({template:`
<v-layout>
@ -668,7 +788,7 @@ const People=Vue.extend({template:`
<v-card-row img="resources/music.jpg" height="300px"></v-card-row>
</v-flex>
<v-flex xs1="">
<v-card-row img="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" height="60px"></v-card-row>
<v-card-row :img="img" height="60px"></v-card-row>
</v-flex>
</v-layout>
</v-container>
@ -823,7 +943,19 @@ const Puzzle=Vue.extend({template:`
<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>
<td v-for="(cell,col) in item" style="width:3em;">
<v-btn @click.native="click(row,col)" :disabled="disabled(row,col)">{{cell}}</v-btn>
</td>
</tr>
</tbody></table>
<br>
<table>
<tbody><tr v-for="(item, row) in grid">
<td v-for="(cell,col) in item" style="width:50px;height:50px;">
<v-btn @click.native="click(row,col)" :disabled="disabled(row,col)">
<img :src="src(row,col)" style="width:50px;height:50px;">
</v-btn>
</td>
</tr>
</tbody></table>
</v-layout>
@ -837,11 +969,12 @@ const Puzzle=Vue.extend({template:`
[3,7,10,14],
[4,null,11,15]
],
empty:[3,1]
empty:[3,1],
tiles:[{data:""}]
}
},
methods: {
click: function (row,col) {
click(row,col) {
var g=this.grid
var h=g[row][col]
g[row][col]=null
@ -851,7 +984,31 @@ const Puzzle=Vue.extend({template:`
this.grid= g
console.log("click",this.grid,e)
this.$forceUpdate()
},
disabled(row,col){
var ok=(row==this.empty[0]) && (col==this.empty[1]-1 ||col==this.empty[1]+1)
ok=ok || (col==this.empty[1]) && (row==this.empty[0]-1 ||row==this.empty[0]+1);
return !ok
},
gettiles(){
HTTP.get("thumbnail/images")
.then(r=>{
this.tiles=r.data.items
this.$forceUpdate()
})
},
src(row,col){
var v=this.grid[row][col]
var d=""
if(typeof this.tiles[v] !== 'undefined') d=this.tiles[v].data
return "data:image/jpeg;base64,"+d
}
},
created(){
this.gettiles()
}
}
@ -1062,6 +1219,24 @@ const Tabs=Vue.extend({template:`
}
}
);
const Task=Vue.extend({template:`
<v-container fluid="">
<h1>Tasks</h1>
</v-container>
`,
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
);
const Thumbnail=Vue.extend({template:`
<v-container fluid="">
@ -1115,7 +1290,9 @@ const Thumbnail=Vue.extend({template:`
if (this.taskxml !== val) this.taskxml = val;
},
validate(){
alert
alert("validate")
HTTP.post("thumbnail/validate",Qs.stringify({task: this.taskxml}))
.then(r=>{alert("gg")})
},
go(){
alert("post")
@ -1143,8 +1320,15 @@ const HTTP = axios.create({
});
const axios_json={ headers: {accept: 'application/json'}};
const Auth={
name:"guest",
role:null,
install: function(Vue){
Object.defineProperty(Vue.prototype, '$auth', {
get () { return Auth }
}) }
};
Vue.use(Auth);
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` is a Vue-specific error info, e.g. which lifecycle hook
@ -1153,12 +1337,83 @@ Vue.config.errorHandler = function (err, vm, info) {
};
Vue.component('my-component', {
template: '<div>A custom <v-chip>component!</v-chip></div>',
props: ['href'],
template: '<a :href="href" :target="href" > {{href}}<v-icon>link</v-icon></a>',
created:function(){
console.log("my-component");
},
});
Vue.component('nav-apb', {
props: ['items'],
template:`
<v-list dense>
<template v-for="(item, i) in items">
<v-layout
row
v-if="item.heading"
align-center
:key="i"
>
<v-flex xs6>
<v-subheader v-if="item.heading">
{{ item.heading }}
</v-subheader>
</v-flex>
<v-flex xs6 class="text-xs-center">
<a href="#!" class="body-2 black--text">EDIT</a>
</v-flex>
</v-layout>
<v-list-group v-else-if="item.children" v-model="item.model" no-action>
<v-list-item slot="item">
<v-list-tile :href="item.href" router ripple>
<v-list-tile-action>
<v-icon>{{ item.model ? item.icon : item['icon-alt'] }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item
v-for="(child, i) in item.children"
:key="i"
>
<v-list-tile>
<v-list-tile-action v-if="child.icon">
<v-icon>{{ child.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ child.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</v-list-group>
<v-list-item v-else>
<v-list-tile :href="item.href" router ripple>
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</template>
</v-list>`,
created:function(){
console.log("my-component");
}
});
var Events = new Vue({});
@ -1182,6 +1437,9 @@ const router = new VueRouter({
{ path: '/history', component: History,meta:{title:"File History"} },
{ path: '/puzzle', component: Puzzle,meta:{title:"Jigsaw"} },
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
],
});
@ -1193,7 +1451,7 @@ router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (true) {
if ("admin"==Auth.role) {
next({
path: '/login',
query: { redirect: to.fullPath }
@ -1216,10 +1474,16 @@ const app = new Vue({
mini: false,
items: [
{href: '/',title: 'Home', icon: 'home' },
{href: 'files', title: 'File system',icon: 'folder' },
{href: 'edit',title: 'edit',icon: 'mode_edit'},
{href: 'history',title: 'history',icon: 'history'},
{href: 'eval',title: 'Evaluate',icon: 'cake'},
{href: 'tasks',title: 'Tasks',icon: 'build'},
{href: 'jobs',title: 'Jobs',icon: 'print'},
{href: 'logs',title: 'Server logs',icon: 'dns'},
{href: 'people',title: 'People',icon: 'person'},
{href: 'select',title: 'select',icon: 'extension'},
{href: 'puzzle',title: 'Puzzle',icon: 'extension'},
@ -1242,7 +1506,8 @@ const app = new Vue({
HTTP.get("status")
.then(r=>{
console.log("status",r)
this.status=r.data
this.$auth.name=r.data.user
this.$forceUpdate()
})
},
beforeDestroy(){

View file

@ -80,7 +80,7 @@
<v-text-field prepend-icon="search" label="Search..." v-model="q"
hide-details single-line dark @keyup.native.enter="search"></v-text-field>
<v-avatar>
{{status.user}}
{{$auth.name}}
</v-avatar>
</v-toolbar>
<main>

View file

@ -11,8 +11,15 @@ const HTTP = axios.create({
});
const axios_json={ headers: {accept: 'application/json'}};
const Auth={
name:"guest",
role:null,
install: function(Vue){
Object.defineProperty(Vue.prototype, '$auth', {
get () { return Auth }
}) }
};
Vue.use(Auth);
Vue.config.errorHandler = function (err, vm, info) {
// handle error
// `info` is a Vue-specific error info, e.g. which lifecycle hook
@ -21,12 +28,83 @@ Vue.config.errorHandler = function (err, vm, info) {
};
Vue.component('my-component', {
template: '<div>A custom <v-chip>component!</v-chip></div>',
props: ['href'],
template: '<a :href="href" :target="href" > {{href}}<v-icon>link</v-icon></a>',
created:function(){
console.log("my-component");
},
});
Vue.component('nav-apb', {
props: ['items'],
template:`
<v-list dense>
<template v-for="(item, i) in items">
<v-layout
row
v-if="item.heading"
align-center
:key="i"
>
<v-flex xs6>
<v-subheader v-if="item.heading">
{{ item.heading }}
</v-subheader>
</v-flex>
<v-flex xs6 class="text-xs-center">
<a href="#!" class="body-2 black--text">EDIT</a>
</v-flex>
</v-layout>
<v-list-group v-else-if="item.children" v-model="item.model" no-action>
<v-list-item slot="item">
<v-list-tile :href="item.href" router ripple>
<v-list-tile-action>
<v-icon>{{ item.model ? item.icon : item['icon-alt'] }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
<v-list-item
v-for="(child, i) in item.children"
:key="i"
>
<v-list-tile>
<v-list-tile-action v-if="child.icon">
<v-icon>{{ child.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ child.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</v-list-group>
<v-list-item v-else>
<v-list-tile :href="item.href" router ripple>
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>
{{ item.text }}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-item>
</template>
</v-list>`,
created:function(){
console.log("my-component");
}
});
var Events = new Vue({});
@ -50,6 +128,9 @@ const router = new VueRouter({
{ path: '/history', component: History,meta:{title:"File History"} },
{ path: '/puzzle', component: Puzzle,meta:{title:"Jigsaw"} },
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
],
});
@ -61,7 +142,7 @@ router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (true) {
if ("admin"==Auth.role) {
next({
path: '/login',
query: { redirect: to.fullPath }
@ -84,10 +165,16 @@ const app = new Vue({
mini: false,
items: [
{href: '/',title: 'Home', icon: 'home' },
{href: 'files', title: 'File system',icon: 'folder' },
{href: 'edit',title: 'edit',icon: 'mode_edit'},
{href: 'history',title: 'history',icon: 'history'},
{href: 'eval',title: 'Evaluate',icon: 'cake'},
{href: 'tasks',title: 'Tasks',icon: 'build'},
{href: 'jobs',title: 'Jobs',icon: 'print'},
{href: 'logs',title: 'Server logs',icon: 'dns'},
{href: 'people',title: 'People',icon: 'person'},
{href: 'select',title: 'select',icon: 'extension'},
{href: 'puzzle',title: 'Puzzle',icon: 'extension'},
@ -110,7 +197,8 @@ const app = new Vue({
HTTP.get("status")
.then(r=>{
console.log("status",r)
this.status=r.data
this.$auth.name=r.data.user
this.$forceUpdate()
})
},
beforeDestroy(){

View file

@ -1,9 +1,8 @@
// ace editor for vue.js
//https://jsfiddle.net/bc_rikko/gbpw2q9x/3/
Vue.component('vue-ace', {
template: '<div :id="editorId" style="width: 100%; height: 100%;"></div>',
props: ['editorId',
'content',
template: '<div style="width: 100%; height: 100%;"></div>',
props: [ 'content',
'mode',
'theme',
'wrap',
@ -65,7 +64,7 @@ Vue.component('vue-ace', {
const readOnly = this.readOnly || false
ace.config.set("workerPath", "/vue-poc/ui/ace-workers")
this.editor = window.ace.edit(this.editorId)
this.editor = window.ace.edit(this.$el)
this.editor.$blockScrolling = Infinity
this.editor.setValue(this.content, 1)

View file

@ -100,29 +100,31 @@
</v-list>
</v-menu>
</v-toolbar-items>
<v-dialog v-model="clearDialog" >
<v-card>
<v-card-row>
<v-card-title>Clear?</v-card-title>
</v-card-row>
<v-card-row>
<v-card-text>clear text.</v-card-text>
</v-card-row>
<v-card-row actions>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(false)">Cancel</v-btn>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(true)">Ok</v-btn>
</v-card-row>
</v-card>
</v-dialog>
</v-app-bar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-flex xs12 style="height:70vh" v-if="!busy" fill-height>
<vue-ace editor-id="editorA" :content="contentA" :mode="mode" :wrap="wrap"
<vue-ace :content="contentA" :mode="mode" :wrap="wrap"
v-on:change-content="changeContentA"
v-on:annotation="annotation"></vue-ace>
</v-flex>
<v-dialog v-model="clearDialog" >
<v-card-row>
<v-card-title>Clear?</v-card-title>
</v-card-row>
<v-card-row>
<v-card-text>clear text.</v-card-text>
</v-card-row>
<v-card-row actions>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(false)">Cancel</v-btn>
<v-btn class="green--text darken-1" flat="flat" @click.native="reset(true)">Ok</v-btn>
</v-card-row>
</v-card>
</v-dialog>
</v-card>
</v-container>
@ -153,6 +155,7 @@ v-on:annotation="annotation"></vue-ace>
"text/ecmascript":"javascript",
"application/sparql-query":"sparql",
"text/html":"html",
"text/turtle":"turtle",
"text/css":"css"
}
}
@ -202,7 +205,17 @@ v-on:annotation="annotation"></vue-ace>
Events.$emit('eventFired',"foldall");
},
save(){
alert("TODO save: "+this.path.join("/"));
alert("TODO save: "+this.url);
var data=Qs.stringify(
{
url: this.url, //gave the values directly for testing
data: this.contentA
})
HTTP.post("edit", data,{
headers: { "Content-Type": "application/x-www-form-urlencoded"}
}).then(r=>{
alert("AAA")
})
},
showfiles(){
router.push({ path: 'files', query: { url: this.path.join("/") }})

View file

@ -1,27 +0,0 @@
<!DOCTYPE html>
<template id="eval">
<v-container fluid>
<v-card class="grey lighten-1 z-depth-1 mb-5" height="200px" >
<vue-ace editor-id="editorA" :content="xq" mode="xquery" wrap="true"
v-on:change-content="onChange"
></vue-ace>
</v-card>
</v-container>
</template>
<script>{
data: function(){
return {
xq: '(:~ do something :)'
}
},
methods:{
onChange(){
console.log("go")
}
},
created:function(){
console.log("notfound",this.$route.query.q)
}
}
</script>

View file

@ -0,0 +1,67 @@
<!DOCTYPE html>
<template id="eval">
<v-container fluid>
<v-card class="grey lighten-1 z-depth-1 mb-5">
<v-card-row>
<v-btn @click.native="run()">Run</v-btn>
<v-btn @click.native="submit()">Submit</v-btn>
</v-card-row>
<v-card-row height="200px" >
<vue-ace :content="xq" mode="xquery" wrap="true"
v-on:change-content="onChange"
></vue-ace>
</v-card-row>
</v-card>
<v-alert error v-bind:value="showError">
{{result}}
</v-alert>
<v-card v-if="show">
<v-card-row height="200px">
<vue-ace :content="result" mode="text" wrap="true" read-only="true"
></vue-ace>
</v-card-row>
</v-card>
</v-container>
</template>
<script>{
data: function(){
return {
xq: '(: type your XQuery :)\n',
result:'',
elapsed:null,
show:false,
showError:false
}
},
methods:{
onChange(val){
if (this.xq !== val) {
this.xq = val
}
},
run(){
var data={xq:this.xq}
this.showError=this.show=false
HTTP.post("eval/execute",Qs.stringify(data))
.then(r=>{
this.result=r.data.result
this.show=true
})
.catch(r=> {
console.log("error",r)
this.result=r.response.data
this.showError=true;
});
},
submit(){
alert("submit")
}
},
created:function(){
console.log("notfound",this.$route.query.q)
}
}
</script>

View file

@ -0,0 +1,26 @@
(:~
: vue-poc thumbnail api.
:
: @author Andy Bunce may-2017
:)
module namespace vue-api = 'quodatum:vue.api.eval';
import module namespace rest = "http://exquery.org/ns/restxq";
import module namespace util = 'vue-poc/util' at "../../lib/util.xqm";
(:~
: eval
:)
declare
%rest:POST %rest:path("/vue-poc/api/eval/execute")
%rest:form-param("xq", "{$xq}")
%output:method("json")
function vue-api:eval($xq )
{
let $x:=fn:trace($xq,"task: ")
let $r:=util:query($xq,())
return <json type="object" >
<result>{$r}</result>
</json>
};

View file

@ -4,17 +4,18 @@
<v-card>
<v-app-bar>
<v-menu offset-y>
<v-btn icon dark slot="activator"><v-icon >folder</v-icon></v-btn>
<v-list>
<v-list-item v-for="item in crumbs" :key="item">
<v-list-tile>
<v-list-tile-title @click="root()">{{ item }}</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
<v-menu >
<v-btn icon dark slot="activator"><v-icon >folder</v-icon></v-btn>
<v-list>
<v-list-item v-for="item in crumbs" :key="item">
<v-list-tile>
<v-list-tile-title @click="root()">{{ item }}</v-list-tile-title>
</v-list-tile>
</v-list-item>
</v-list>
</v-menu>
<v-toolbar-title>{{ url }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search"
hide-details single-line dark @keyup.native.enter="filter"></v-text-field>

View file

@ -12,7 +12,7 @@
<v-flex xs4>
<p>This is a experiment in using <code>vue.js</code>.</p>
<ul>
<li><a href="https://vuetifyjs.com/" target="new">vuetifyjs</a></li>
<li><a href="https://vuetifyjs.com/vuetify/quick-start" target="new">vuetifyjs</a></li>
<li><a href="https://github.com/monterail/vue-multiselect" target="new">vue-multiselect</a></li>
<li><a href="https://github.com/sagalbot/vue-select" target="new"><s>vue-select</s></a></li>
<li><a href="https://github.com/beautify-web/js-beautify" target="new">js-beautify</a></li>
@ -23,7 +23,7 @@
<v-btn floating="floating">
<v-icon>add</v-icon>
</v-btn>
<my-component>REPLACED</my-component>
<my-component href="/dba">REPLACED</my-component>
</v-layout>
</template>
<script>{

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<template id="job">
<v-container fluid>
<h1>JOBS</h1>
<nav-apb :items="items"></nav-apb>
</v-container>
</template>
<script>{
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q,
items:[
{href: '/',text: 'Home', icon: 'home' },
{href: 'files', text: 'File system',icon: 'folder' },
{href: 'edit',text: 'edit',icon: 'mode_edit'},
{href: 'history',text: 'history',icon: 'history'},
{href: 'eval',text: 'Evaluate',icon: 'cake'},
{href: 'tasks',text: 'Tasks',icon: 'build'},
{href: 'jobs',text: 'Jobs',icon: 'print'},
{href: 'logs',text: 'Server logs',icon: 'dns'},
{href: 'people',text: 'People',icon: 'person'},
{href: 'select',text: 'select',icon: 'extension'},
{href: 'puzzle',text: 'Puzzle',icon: 'extension'},
{href: 'options',text: 'options',icon: 'domain'},
{href: 'tabs',text: 'tabs',icon: 'switch_camera'},
{href: 'ping',text: 'ping',icon: 'update'},
{href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'},
{href: 'settings',text: 'settings',icon: 'settings' }
]
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
</script>

View file

@ -1,12 +1,15 @@
<!DOCTYPE html>
<template id="login">
<v-card class="grey lighten-4 elevation-0">
<v-card-row class="green darken-1">
<v-card-title>
<span class="white--text">Login</span>
</v-card-title>
</v-card-row>
<v-alert error v-bind:value="showMessage">
{{message}}
</v-alert>
<v-card-row>
<v-text-field
name="input-name"
@ -43,28 +46,35 @@
return {
hidepass: true,
name:'',
password: ''
password: '',
redirect: this.$route.query.redirect,
message:"",
showMessage:false
}
},
methods:{
go () {
this.hidepass=true
this.showMessage=false
var data=Qs.stringify(
{
username: this.name, //gave the values directly for testing
password: this.password,
client_id: 'user-client'
redirect: this.redirect
})
HTTP.post("login-check", data,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}})
HTTP.post("login-check", data)
.then(r=>{
console.log(r)
alert("loh")
console.log("login",r.data)
if(r.data.status){
this.$auth.role="admin"
this.$router.replace(this.redirect)
}else{
this.message=r.data.message
this.showMessage=true;
}
}).catch(error=> {
alert("err")
alert("err login")
})
}
}

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<template id="log">
<v-container fluid>
<h1>LOGS</h1>
</template>
<script>{
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
</script>

View file

@ -11,7 +11,7 @@
<v-card-row img="resources/music.jpg" height="300px"></v-card-row>
</v-flex>
<v-flex xs1>
<v-card-row img="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" height="60px"></v-card-row>
<v-card-row :img="img" height="60px"></v-card-row>
</v-flex>
</v-layout>
</v-container>

View file

@ -6,7 +6,19 @@
<table>
<tr v-for="(item, row) in grid">
<td v-for="(cell,col) in item" style="width:3em;" @click="click(row,col)">{{cell}}</td>
<td v-for="(cell,col) in item" style="width:3em;" >
<v-btn @click.native="click(row,col)" :disabled="disabled(row,col)">{{cell}}</v-btn>
</td>
</tr>
</table>
<br/>
<table>
<tr v-for="(item, row) in grid">
<td v-for="(cell,col) in item" style="width:50px;height:50px;" >
<v-btn @click.native="click(row,col)" :disabled="disabled(row,col)">
<img :src="src(row,col)" style="width:50px;height:50px;"/>
</v-btn>
</td>
</tr>
</table>
</v-layout>
@ -21,11 +33,12 @@
[3,7,10,14],
[4,null,11,15]
],
empty:[3,1]
empty:[3,1],
tiles:[{data:""}]
}
},
methods: {
click: function (row,col) {
click(row,col) {
var g=this.grid
var h=g[row][col]
g[row][col]=null
@ -35,7 +48,31 @@
this.grid= g
console.log("click",this.grid,e)
this.$forceUpdate()
},
disabled(row,col){
var ok=(row==this.empty[0]) && (col==this.empty[1]-1 ||col==this.empty[1]+1)
ok=ok || (col==this.empty[1]) && (row==this.empty[0]-1 ||row==this.empty[0]+1);
return !ok
},
gettiles(){
HTTP.get("thumbnail/images")
.then(r=>{
this.tiles=r.data.items
this.$forceUpdate()
})
},
src(row,col){
var v=this.grid[row][col]
var d=""
if(typeof this.tiles[v] !== 'undefined') d=this.tiles[v].data
return "data:image/jpeg;base64,"+d
}
},
created(){
this.gettiles()
}
}

View file

@ -1,19 +0,0 @@
<template >
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data () {
return {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
font-weight: bold;
}
</style>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<template id="task">
<v-container fluid>
<h1>Tasks</h1>
</v-container>
</template>
<script>{
data: function(){
return {
message: 'Hello Vue.js!',
q:this.$route.query.q
}
},
created:function(){
console.log("Serch",this.$route.query.q)
}
}
</script>

View file

@ -60,7 +60,9 @@
if (this.taskxml !== val) this.taskxml = val;
},
validate(){
alert
alert("validate")
HTTP.post("thumbnail/validate",Qs.stringify({task: this.taskxml}))
.then(r=>{alert("gg")})
},
go(){
alert("post")

View file

@ -0,0 +1,97 @@
(:~
: vue-poc thumbnail api.
:
: @author Andy Bunce may-2017
:)
module namespace vue-api = 'quodatum:vue.api.thumbnail';
import module namespace rest = "http://exquery.org/ns/restxq";
(:~
: do a thumbnail
:)
declare
%rest:POST %rest:path("/vue-poc/api/thumbnail")
%rest:form-param("url", "{$url}")
%rest:form-param("task", "{$task}")
%rest:produces("application/json")
%output:method("json")
function vue-api:thumbnail($url,$task )
{
let $x:=fn:parse-xml($task)=>fn:trace("task: ")
return <json type="object" >
<items type="array">
{(1 to 100)!(<_>A{.}</_>)}
</items>
</json>
};
(:~
: do a thumbnail
:)
declare
%rest:POST %rest:path("/vue-poc/api/thumbnail/validate")
%rest:form-param("task", "{$task}")
%rest:produces("application/json")
%output:method("json")
function vue-api:thumbnail-validate($task )
{
let $x:=fn:parse-xml($task)=>fn:trace("task: ")
return <json type="object" >
<items type="array">
{(1 to 100)!(<_>A{.}</_>)}
</items>
</json>
};
(:~
: return set of images as base64
:)
declare
%rest:GET %rest:path("/vue-poc/api/thumbnail/images")
%rest:produces("application/json")
%output:method("json")
function vue-api:thumbnail-images( )
{
let $p:="/vue-poc/static/resources/tiles/"=>vue-api:web()
let $x:=$p=>file:list()
return <json type="object" >
<items type="array">
{for $item in $x
let $m:=vue-api:get-image($item,$p)
return <_ type="object">
<name>{$m?name}</name>
<data>{$m?data}</data>
<mime>{$m?mime}</mime>
</_>}
</items>
</json>
};
declare function vue-api:get-image($name as xs:string,$path as xs:string)
as map(*)
{
let $f:=file:resolve-path($name,$path)
return map{
"name":$name,
"data":fetch:binary($f),
"mime":fetch:content-type($f)
}
};
(:~
: resolve path relative to basex webpath
: file("/fred")=>C:\Program Files (x86)\BaseX\webapp\fred
:)
declare function vue-api:web($file as xs:string)
as xs:string
{
let $file:=if(starts-with($file,"/")) then
substring($file,2)
else
error(xs:QName('vue-api:badpath'),"leading slash")
let $webroot:=db:system()/globaloptions/webpath/concat(.,"/")
return file:resolve-path($file,$webroot)
};

View file

@ -5,13 +5,13 @@
:)
module namespace vue-api = 'quodatum:vue.api';
import module namespace rest = "http://exquery.org/ns/restxq";
import module namespace session = "http://basex.org/modules/session";
import module namespace fw="quodatum:file.walker";
import module namespace mt = 'quodatum.data.mimetype' at "lib/mimetype.xqm";
declare namespace c="http://www.w3.org/ns/xproc-step";
declare namespace wadl="http://wadl.dev.java.net/2009/02";
declare variable $vue-api:index:=file:base-dir() || 'static/' || "app.html";
(:~
@ -45,27 +45,11 @@ let $detail:=user:list-details($user)
return <json type="object" >
<user>{$user}</user>
<permission>{$detail/@permission/string()}</permission>
<session>{session:id()}</session>
<created>{session:created()}</created>
</json>
};
(:~
: do a thumbnail
:)
declare
%rest:POST %rest:path("/vue-poc/api/thumbnail")
%rest:form-param("url", "{$url}")
%rest:form-param("task", "{$task}")
%rest:produces("application/json")
%output:method("json")
function vue-api:thumbnail($url,$task )
{
let $x:=fn:parse-xml($task)=>fn:trace("task: ")
return <json type="object" >
<items type="array">
{(1 to 100)!(<_>A{.}</_>)}
</items>
</json>
};
(:~
: history list
@ -138,6 +122,7 @@ declare
function vue-api:edit-post($url as xs:string,$data)
{
let $path := vue-api:web( $url)=>trace("path ")
let $data:=trace($data)
return if( file:exists($path))then
let $type:=mt:type($path)
let $fetch:=mt:fetch-fn($type("treat-as"))