Bug fixes to data layer.
Paste input now support images. New static time stamp control. Some more utility functions for converting data types. New control for showing raw HTML data. New control to show tags, to be expanded latter.
This commit is contained in:
parent
c617c63510
commit
11b15e1b9b
11723
package-lock.json
generated
11723
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -30,16 +30,17 @@
|
|||||||
"@riotjs/parcel-transformer-riot": "^7.0.3",
|
"@riotjs/parcel-transformer-riot": "^7.0.3",
|
||||||
"electron": "^16.0.7",
|
"electron": "^16.0.7",
|
||||||
"jest": "^27.4.7",
|
"jest": "^27.4.7",
|
||||||
"parcel": "^2.2.1"
|
"parcel": "^2",
|
||||||
|
"electron-rebuild": "^3.2.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@yaireo/tagify": "^4.9.5",
|
"@yaireo/tagify": "^4.9.5",
|
||||||
"better-sqlite3": "^7.5.0",
|
"better-sqlite3": "^7.5.0",
|
||||||
"conf": "^10.1.1",
|
"conf": "^10.1.1",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"electron-rebuild": "^3.2.7",
|
|
||||||
"empty-lite": "^1.2.0",
|
"empty-lite": "^1.2.0",
|
||||||
"es6-interface": "^3.2.1",
|
"es6-interface": "^3.2.1",
|
||||||
|
"hash.js": "^1.1.7",
|
||||||
"nanoid": "^3.2.0",
|
"nanoid": "^3.2.0",
|
||||||
"pubsub-js": "^1.9.4",
|
"pubsub-js": "^1.9.4",
|
||||||
"riot": "^6.1.2",
|
"riot": "^6.1.2",
|
||||||
|
|||||||
@ -15,8 +15,8 @@ const DB = ConnectToDatabase(DBPath);
|
|||||||
|
|
||||||
const DbRecord = new TimeChainDataSqliteRecord();
|
const DbRecord = new TimeChainDataSqliteRecord();
|
||||||
const DbFile = new TimeChainDataSqliteFile();
|
const DbFile = new TimeChainDataSqliteFile();
|
||||||
const dbTag = new TimeChainDataSqliteTag();
|
const DbTag = new TimeChainDataSqliteTag();
|
||||||
const dbTagLink = new TimeChainDataSqliteTagLink();
|
const DbTagLink = new TimeChainDataSqliteTagLink();
|
||||||
//const configDir = app.getPath('userData');
|
//const configDir = app.getPath('userData');
|
||||||
//const appPath = app.getPath('exe');
|
//const appPath = app.getPath('exe');
|
||||||
|
|
||||||
|
|||||||
@ -60,9 +60,15 @@ class TimeChainDataSqliteTag extends Interface(InterfaceTag) {
|
|||||||
|
|
||||||
add(tag){
|
add(tag){
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve=>{
|
||||||
const dt = Math.floor(Date.now());
|
this.has(tag).then(cnt=>{
|
||||||
const res = this.table_add.run(tag,dt,dt);
|
if(cnt){
|
||||||
return resolve(res?.changes);
|
return resolve(1);
|
||||||
|
}else{
|
||||||
|
const dt = Math.floor(Date.now());
|
||||||
|
const res = this.table_add.run(tag,dt,dt);
|
||||||
|
return resolve(res?.changes);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,6 +386,21 @@ class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
|||||||
return this._table_fine_one;
|
return this._table_fine_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get table_find(){
|
||||||
|
if(!this._table_find){
|
||||||
|
this._table_find = db.prepare(`
|
||||||
|
select records.*, GROUP_CONCAT(taglink.tag,',') AS tags
|
||||||
|
from records
|
||||||
|
left join taglink on (taglink.uuid = records.uuid)
|
||||||
|
group by records.uuid
|
||||||
|
order by records.timestamp DESC
|
||||||
|
limit ? offset ?
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._table_find;
|
||||||
|
}
|
||||||
|
|
||||||
add(uuid,timestamp,content,mime,hash){
|
add(uuid,timestamp,content,mime,hash){
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve=>{
|
||||||
const dt = Math.floor(Date.now());
|
const dt = Math.floor(Date.now());
|
||||||
@ -398,13 +419,12 @@ class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
|||||||
find(search,sort=null,limit=undefined,offset=0){
|
find(search,sort=null,limit=undefined,offset=0){
|
||||||
//TODO: add logic for seach and sort (Currently does nothing)
|
//TODO: add logic for seach and sort (Currently does nothing)
|
||||||
return new Promise(resolve=>{
|
return new Promise(resolve=>{
|
||||||
const rescount = this.db.prepare("SELECT count(*) as cnt FROM records").get();
|
const prepare = this.table_find;
|
||||||
|
|
||||||
if(limit){
|
const res = prepare.all(100,0);
|
||||||
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC LIMIT ? OFFSET ?").all(limit,offset);
|
|
||||||
}else{
|
//TODO: add count here
|
||||||
const res = this.db.prepare("SELECT * FROM records ORDER BY timestamp DESC").all();
|
const rescount = {cnt:100};
|
||||||
}
|
|
||||||
|
|
||||||
return resolve({
|
return resolve({
|
||||||
data: res,
|
data: res,
|
||||||
@ -413,7 +433,7 @@ class TimeChainDataSqliteRecord extends Interface(InterfaceRecord) {
|
|||||||
offset: offset
|
offset: offset
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(uuid){
|
delete(uuid){
|
||||||
|
|||||||
21
src/lib/blobconvert.js
Normal file
21
src/lib/blobconvert.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//**dataURL to blob**
|
||||||
|
function dataURLtoBlob(dataurl) {
|
||||||
|
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
||||||
|
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
||||||
|
while(n--){
|
||||||
|
u8arr[n] = bstr.charCodeAt(n);
|
||||||
|
}
|
||||||
|
return new Blob([u8arr], {type:mime});
|
||||||
|
}
|
||||||
|
|
||||||
|
//**blob to dataURL**
|
||||||
|
function blobToDataURL(blob, callback) {
|
||||||
|
var a = new FileReader();
|
||||||
|
a.onload = function(e) {callback(e.target.result);}
|
||||||
|
a.readAsDataURL(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
dataURLtoBlob,
|
||||||
|
blobToDataURL
|
||||||
|
}
|
||||||
15
src/ui/raw.riot
Normal file
15
src/ui/raw.riot
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<raw>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
setInnerHTML() {
|
||||||
|
this.root.innerHTML = this.props.html
|
||||||
|
},
|
||||||
|
onMounted() {
|
||||||
|
this.setInnerHTML()
|
||||||
|
},
|
||||||
|
onUpdated() {
|
||||||
|
this.setInnerHTML()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</raw>
|
||||||
@ -1,16 +1,25 @@
|
|||||||
<timechain-input>
|
<timechain-input>
|
||||||
|
|
||||||
<div class="timechain-input-tempate" if={state.show_tagging}>
|
<div class="timechain-input-tempate" if={state.show_tagging}>
|
||||||
<timechain-tag if={state.show_tagging} onchange="{onTags}"/>
|
<timechain-tag if={state.show_tagging} ontag="{onTags}" />
|
||||||
<timechain-input-buttons if={state.show_tagging} onsave="{onSave}" />
|
<timechain-input-buttons if={state.show_tagging} onsave="{onSave}" oncancel={onCancel} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="pasteme" ondblclick="{onSwap}">
|
<div id="pasteme" ondblclick="{onSwap}" >
|
||||||
<p>{state.message}</p>
|
<p>{state.message}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- textarea id="pasteme" ondblclick="{onSwap}" if="{content_mime == 'text/plain'}">
|
||||||
|
{state.message}
|
||||||
|
</textarea -->
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
|
textarea#pasteme {
|
||||||
|
width:100%;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
.paste-html {
|
.paste-html {
|
||||||
background: white !important;
|
background: white !important;
|
||||||
color: black !important;
|
color: black !important;
|
||||||
@ -38,11 +47,20 @@
|
|||||||
|
|
||||||
const pubsub = require('pubsub-js');
|
const pubsub = require('pubsub-js');
|
||||||
const empty = require('empty-lite');
|
const empty = require('empty-lite');
|
||||||
|
const hash = require('hash.js');
|
||||||
|
|
||||||
|
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
import sanitizeHtml from 'sanitize-html';
|
import sanitizeHtml from 'sanitize-html';
|
||||||
import TimechainTag from './timechain-tag.riot'
|
import TimechainTag from './timechain-tag.riot'
|
||||||
import TimechainInputButtons from './timechain-input-buttons.riot';
|
import TimechainInputButtons from './timechain-input-buttons.riot';
|
||||||
|
import {blobToDataURL} from '../lib/blobconvert';
|
||||||
|
|
||||||
const {TimeChainDataSqliteRecord} = require('../data/sqlite-client');
|
const {
|
||||||
|
TimeChainDataSqliteRecord,
|
||||||
|
TimeChainDataSqliteTag,
|
||||||
|
TimeChainDataSqliteTagLink
|
||||||
|
} = require('../data/sqlite-client');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
@ -53,38 +71,140 @@
|
|||||||
TimechainTag,
|
TimechainTag,
|
||||||
TimechainInputButtons
|
TimechainInputButtons
|
||||||
},
|
},
|
||||||
|
onBeforeMount(){
|
||||||
|
this.tc = 0;
|
||||||
|
this.clean_props = ['timestamp','content_text','content_mime','content_type','content_swap','content_tags'];
|
||||||
|
},
|
||||||
onMounted(){
|
onMounted(){
|
||||||
document.addEventListener('paste', this.pasteEvent.bind(this));
|
document.addEventListener('paste', this.pasteEvent.bind(this));
|
||||||
},
|
},
|
||||||
|
cleanFields(){
|
||||||
|
this.clean_props.forEach(f=>{
|
||||||
|
this[f]=null;
|
||||||
|
});
|
||||||
|
const el = this.$('#pasteme');
|
||||||
|
el.innerHTML = `<p>${this.state.message}</p>`;
|
||||||
|
el.classList.remove('paste-html');
|
||||||
|
pubsub.publish('tag.clean');
|
||||||
|
this.update({show_tagging:false});
|
||||||
|
pubsub.publish('timestamp-resume',true);
|
||||||
|
},
|
||||||
pasteEvent(e){
|
pasteEvent(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
console.log("Bla");
|
console.log("Paste Event");
|
||||||
console.log(e.clipboardData.items[0]);
|
console.log("Item 1", e.clipboardData.items[0]);
|
||||||
console.log(e.clipboardData.items[1]);
|
console.log("Item 2", e.clipboardData.items[1]);
|
||||||
|
|
||||||
if (e.clipboardData.types.indexOf('text/html') > -1) {
|
let known_type = true;
|
||||||
const newData = e.clipboardData.getData('text/html');
|
let isFile = false;
|
||||||
const newDataText = e.clipboardData.getData('text/plain');
|
const types = e.clipboardData.types;
|
||||||
const el = this.$('#pasteme');
|
|
||||||
pubsub.publish('timestamp-puase',true);
|
|
||||||
this.timestamp = Math.floor(new Date().getTime());
|
|
||||||
pubsub.publish('timestamp-settime',this.timestamp);
|
|
||||||
el.innerHTML = this.content = newData;
|
|
||||||
this.content_text = e.clipboardData.getData('text/plain');
|
|
||||||
this.content_mime = 'text/html';
|
|
||||||
el.classList.add('paste-html');
|
|
||||||
|
|
||||||
this.content_type = "html";
|
console.log("types",types);
|
||||||
this.content_swap = 0;
|
|
||||||
this.content_orig = this.content;
|
if(types.indexOf('Files') > -1){
|
||||||
|
|
||||||
|
|
||||||
|
const c = e.clipboardData.items.length;
|
||||||
|
|
||||||
|
console.log("FILES!!", c);
|
||||||
|
|
||||||
|
for(let i=0; i < c ; i++){
|
||||||
|
console.log(i);
|
||||||
|
const t = e.clipboardData.items[i].type;
|
||||||
|
console.log("Clip Data", e.clipboardData.items[i]);
|
||||||
|
|
||||||
|
if(t == 'image/jpeg'){
|
||||||
|
isFile = true;
|
||||||
|
this.isIMAGE(e.clipboardData.items[i], 'image/jpeg');
|
||||||
|
break;
|
||||||
|
}else if(t == 'image/png'){
|
||||||
|
isFile = true;
|
||||||
|
this.isIMAGE(e.clipboardData.items[i], 'image/png')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if (types.indexOf('text/html') > -1) {
|
||||||
|
//this.content_mime = 'text/html';
|
||||||
|
//this.update();
|
||||||
|
this.isHTML(e);
|
||||||
|
}else if(types.indexOf('text/plain') > -1){
|
||||||
|
//this.content_mime = 'text/plain';
|
||||||
|
//this.update();
|
||||||
|
this.isTEXT(e);
|
||||||
|
}else{
|
||||||
|
known_type = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty(this.content)){
|
console.log(known_type,this.content,isFile || empty(this.content));
|
||||||
|
if(known_type && (isFile || !empty(this.content)) ){
|
||||||
this.update({show_tagging:true});
|
this.update({show_tagging:true});
|
||||||
|
}else{
|
||||||
|
console.log("No reason to show tagging");
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
isHTML(e){
|
||||||
|
console.log("Handling HTML");
|
||||||
|
const newData = e.clipboardData.getData('text/html');
|
||||||
|
const newDataText = e.clipboardData.getData('text/plain');
|
||||||
|
|
||||||
|
const el = this.$('#pasteme');
|
||||||
|
this.pauseTime();
|
||||||
|
|
||||||
|
el.innerHTML = this.content = newData;
|
||||||
|
this.content_text = newDataText;
|
||||||
|
this.content_mime = 'text/html';
|
||||||
|
|
||||||
|
el.classList.add('paste-html');
|
||||||
|
|
||||||
|
this.content_type = "html";
|
||||||
|
this.content_swap = 0;
|
||||||
|
this.content_orig = this.content;
|
||||||
|
|
||||||
|
},
|
||||||
|
isTEXT(e){
|
||||||
|
console.log("Handling TEXT");
|
||||||
|
const data = e.clipboardData.getData('text/plain');
|
||||||
|
|
||||||
|
const el = this.$('#pasteme');
|
||||||
|
|
||||||
|
pubsub.publish('timestamp-puase',true);
|
||||||
|
this.pauseTime();
|
||||||
|
|
||||||
|
el.innerText = this.content = data;
|
||||||
|
//el.value = this.content = data;
|
||||||
|
this.content_mime = 'text/plain';
|
||||||
|
|
||||||
|
el.classList.add('paste-html');
|
||||||
|
|
||||||
|
this.content_type = "text";
|
||||||
|
this.content_swap = false;
|
||||||
|
this.content_orig = this.content;
|
||||||
|
},
|
||||||
|
isIMAGE(e, mime){
|
||||||
|
const el = this.$('#pasteme');
|
||||||
|
const f = e.getAsFile();
|
||||||
|
|
||||||
|
this.content_orig = this.content = f;
|
||||||
|
this.content_mime = mime;
|
||||||
|
this.content_type = "image";
|
||||||
|
this.content_swap = false;
|
||||||
|
|
||||||
|
blobToDataURL(f,data=>{
|
||||||
|
this.content = data;
|
||||||
|
el.innerHTML = "<img src='" + data + "' style='max-width:100%'>";
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
pauseTime(){
|
||||||
|
pubsub.publish('timestamp-puase',true);
|
||||||
|
this.timestamp = Math.floor(new Date().getTime());
|
||||||
|
pubsub.publish('timestamp-settime',this.timestamp);
|
||||||
|
},
|
||||||
onSwap(){
|
onSwap(){
|
||||||
console.log("Here we can swap to text");
|
console.log("Here we can swap to text");
|
||||||
|
|
||||||
@ -117,16 +237,60 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
onTags(tags){
|
onTags(tags){
|
||||||
console.log(tags);
|
console.log(++this.tc,tags);
|
||||||
this.tags = tags;
|
this.content_tags = tags;
|
||||||
|
},
|
||||||
|
onCancel(){
|
||||||
|
this.cleanFields();
|
||||||
},
|
},
|
||||||
onSave(){
|
onSave(){
|
||||||
console.log("Save button pressed");
|
console.log("Save button pressed");
|
||||||
const TR = new TimeChainDataSqliteRecord();
|
const TR = new TimeChainDataSqliteRecord();
|
||||||
|
|
||||||
TR.add("iueyriweusdfsd8w",Math.floor(new Date().getTime()),this.content,this.content_mime,"Comming SOon").then(res=>{
|
const ts = Math.floor(new Date().getTime());
|
||||||
console.log(res);
|
const id = nanoid();
|
||||||
})
|
const hs = hash.sha256().update(this.content).digest('hex');
|
||||||
|
const tags = JSON.parse(this.content_tags);
|
||||||
|
|
||||||
|
console.log("tags:",tags);
|
||||||
|
|
||||||
|
TR.add(id,ts,this.content,this.content_mime,hs).then(res=>{
|
||||||
|
if(res != 1){
|
||||||
|
throw new Error("Not about to save record");
|
||||||
|
}
|
||||||
|
}).then(()=>{
|
||||||
|
if(!tags) return false;
|
||||||
|
const TG = new TimeChainDataSqliteTag();
|
||||||
|
const tasks = tags.map(t=>{
|
||||||
|
return TG.add(t.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(tasks).then(res=>{
|
||||||
|
console.log(res);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}).then(()=>{
|
||||||
|
if(!tags) return false;
|
||||||
|
const TL = new TimeChainDataSqliteTagLink();
|
||||||
|
const tasks = tags.map(t=>{
|
||||||
|
return TL.add(id,t.value);
|
||||||
|
});
|
||||||
|
return Promise.all(tasks).then(res=>{
|
||||||
|
console.log(res);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}).then(()=>{
|
||||||
|
this.cleanFields();
|
||||||
|
}).then(()=>{
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
pubsub.publish('timechain-list-update', true);
|
||||||
|
},100);
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
alert("Error saving data!");
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,107 @@
|
|||||||
<timechain-list>
|
<timechain-list>
|
||||||
|
|
||||||
<div class="timechain-list-title">
|
|
||||||
List of shit
|
|
||||||
<hr>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timechain-list">
|
<div class="timechain-list">
|
||||||
bla bla
|
|
||||||
|
<div class="timechange-item" each="{r in state.records}">
|
||||||
|
|
||||||
|
<div class="timechain-timestamp">
|
||||||
|
<timestamp-static time={r.timestamp} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timechain-tag-list">
|
||||||
|
<timechain-tag-list tags="{r.tags}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timechain-item-text" if="{r.mime == 'text/plain'}">
|
||||||
|
{r.content}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timechain-item-text" if="{r.mime == 'text/html'}">
|
||||||
|
<raw html="{r.content}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timechain-item-image" if="{r.imageURL}">
|
||||||
|
<img src="{r.imageURL}" style="max-width:100%">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.timechain-list {
|
||||||
|
padding: 0 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timechain-list .timechange-item {
|
||||||
|
border: 1px dashed whitesmoke;
|
||||||
|
padding: 0 1em 1em 1em;
|
||||||
|
margin: 1em 0;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
color: #333;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import Raw from './raw.riot'
|
||||||
|
import TimestampStatic from './timestamp-static.riot'
|
||||||
|
import TimechainTagList from './timechain-tag-list.riot'
|
||||||
|
import pubsub from 'pubsub-js'
|
||||||
|
|
||||||
|
const {
|
||||||
|
TimeChainDataSqliteRecord
|
||||||
|
} = require('../data/sqlite-client');
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
records: []
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Raw,
|
||||||
|
TimestampStatic,
|
||||||
|
TimechainTagList
|
||||||
|
},
|
||||||
|
onMounted(){
|
||||||
|
console.log("List mounted");
|
||||||
|
this.loadRecords();
|
||||||
|
|
||||||
|
this.event_load = pubsub.subscribe('timechain-list-update', this.loadRecords.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnmounted(){
|
||||||
|
pubsub.unsubscribe(this.event_load);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadRecords(){
|
||||||
|
const TR = new TimeChainDataSqliteRecord();
|
||||||
|
|
||||||
|
TR.find({},null,100,0).then(records=>{
|
||||||
|
console.log("Records", records);
|
||||||
|
this.update({records:records.data});
|
||||||
|
}).then(()=>{
|
||||||
|
this.processImages();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
processImages(){
|
||||||
|
var URLObj = window.URL || window.webkitURL;
|
||||||
|
this.state.records.forEach(r=>{
|
||||||
|
if(r.mime == "image/jpeg" || r.mime == "image/png"){
|
||||||
|
r.imageURL = r.content;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</timechain-list>
|
</timechain-list>
|
||||||
44
src/ui/timechain-tag-list.riot
Normal file
44
src/ui/timechain-tag-list.riot
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<timechain-tag-list>
|
||||||
|
|
||||||
|
<div class="timechain-tags">
|
||||||
|
<span class="timechain-tag" each="{t in state.tags}">{t}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.timechain-tags {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timechain-tags .timechain-tag {
|
||||||
|
padding: 0.3em;
|
||||||
|
margin: 0em 0.2em;
|
||||||
|
color: white;
|
||||||
|
background-color: #333;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
tags: []
|
||||||
|
},
|
||||||
|
onMounted: function(props){
|
||||||
|
if(!props.tags) return;
|
||||||
|
this.update({
|
||||||
|
tags: props.tags.split(',')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</timechain-tag-list>
|
||||||
@ -17,15 +17,23 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Tagify from '@yaireo/tagify'
|
import Tagify from '@yaireo/tagify'
|
||||||
|
const pubsub = require('pubsub-js');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onMounted(){
|
onMounted(){
|
||||||
const inputElm = this.$('#tagging');
|
const inputElm = this.$('#tagging');
|
||||||
this.tagify = new Tagify(inputElm);
|
this.tagify = new Tagify(inputElm);
|
||||||
inputElm.addEventListener('change', this.onChange.bind(this));
|
inputElm.addEventListener('change', this.onChange.bind(this));
|
||||||
|
this.event_clean = pubsub.subscribe('tag.clean', this.onClean.bind(this));
|
||||||
|
},
|
||||||
|
onUnmounted(){
|
||||||
|
pubsub.unsubscribe(this.event_clean);
|
||||||
},
|
},
|
||||||
onChange(e){
|
onChange(e){
|
||||||
this.props.onchange(e.target.value);
|
this.props?.ontag(e.target.value);
|
||||||
|
},
|
||||||
|
onClean(){
|
||||||
|
this.tagify.removeAllTags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
51
src/ui/timestamp-static.riot
Normal file
51
src/ui/timestamp-static.riot
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<timestamp-static>
|
||||||
|
|
||||||
|
<div class="timestamp-static">
|
||||||
|
<div class="timestamp-text">
|
||||||
|
<span class="timestamp-date">{state.time_date}</span>
|
||||||
|
<span class="timestamp-time">{state.time_time}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.timestamp-static .timestamp-text {
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
margin: 0.5em 0.5em 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp-static .timestamp-text .timestamp-date {
|
||||||
|
font-weight: bold;
|
||||||
|
padding-right: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp-static .timestamp-text .timestamp-time {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const dayjs = require('dayjs');
|
||||||
|
export default {
|
||||||
|
state: {
|
||||||
|
time_date: 'Unknown',
|
||||||
|
time_time: '',
|
||||||
|
time_orig: null
|
||||||
|
},
|
||||||
|
onMounted(props){
|
||||||
|
this.update({
|
||||||
|
time_date: this.format(props.time, true),
|
||||||
|
time_time: this.format(props.time, false),
|
||||||
|
time_orig: props.time
|
||||||
|
});
|
||||||
|
},
|
||||||
|
format(time, format_date){
|
||||||
|
return format_date ? dayjs(new Date(time)).format("MMMM D, YYYY") : dayjs(new Date(time)).format("h:mm:ss A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</timestamp-static>
|
||||||
@ -27,7 +27,12 @@
|
|||||||
|
|
||||||
pubsub.subscribe("timestamp-settime",(event,arg)=>{
|
pubsub.subscribe("timestamp-settime",(event,arg)=>{
|
||||||
this.update({time_text:dayjs(new Date(arg)).format("MMMM D, YYYY h:mm:ss A")});
|
this.update({time_text:dayjs(new Date(arg)).format("MMMM D, YYYY h:mm:ss A")});
|
||||||
})
|
});
|
||||||
|
|
||||||
|
pubsub.subscribe("timestamp-resume", (event)=>{
|
||||||
|
this.$('.timestamp-text').classList.remove('timestamp-puase');
|
||||||
|
this.start();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
start(){
|
start(){
|
||||||
this.event_handle = setTimeout(()=>{
|
this.event_handle = setTimeout(()=>{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user