+
@@ -74,6 +76,7 @@ import SwitchButton from './buttons/SwitchView'
import MoveButton from './buttons/Move'
import CopyButton from './buttons/Copy'
import ScheduleButton from './buttons/Schedule'
+import ShareButton from './buttons/Share'
import {mapGetters, mapState} from 'vuex'
import * as api from '@/utils/api'
import buttons from '@/utils/buttons'
@@ -84,6 +87,7 @@ export default {
Search,
InfoButton,
DeleteButton,
+ ShareButton,
RenameButton,
DownloadButton,
CopyButton,
diff --git a/assets/src/components/Search.vue b/assets/src/components/Search.vue
index baf854aa..b5b434f3 100644
--- a/assets/src/components/Search.vue
+++ b/assets/src/components/Search.vue
@@ -82,7 +82,7 @@
diff --git a/assets/src/components/files/Editor.vue b/assets/src/components/files/Editor.vue
index dadbf9d6..49207996 100644
--- a/assets/src/components/files/Editor.vue
+++ b/assets/src/components/files/Editor.vue
@@ -11,7 +11,7 @@
+
diff --git a/assets/src/css/mobile.css b/assets/src/css/mobile.css
index 5fd57a8d..05d4d46b 100644
--- a/assets/src/css/mobile.css
+++ b/assets/src/css/mobile.css
@@ -61,7 +61,7 @@
background: #fff;
box-shadow: rgba(0, 0, 0, 0.06) 0px 1px 3px, rgba(0, 0, 0, 0.12) 0px 1px 2px;
width: 95%;
- max-width: 18em;
+ max-width: 20em;
}
#file-selection .action {
border-radius: 50%;
diff --git a/assets/src/css/prompts.css b/assets/src/css/prompts.css
index 01c3802d..b1a7fbe6 100644
--- a/assets/src/css/prompts.css
+++ b/assets/src/css/prompts.css
@@ -177,3 +177,32 @@
opacity: 1;
}
}
+
+.prompt#share ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.prompt#share ul li {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.prompt#share ul li a {
+ color: #2196F3;
+ cursor: pointer;
+ margin-right: auto;
+}
+
+.prompt#share ul li .action i {
+ font-size: 1em;
+}
+
+.prompt#share ul li input,
+.prompt#share ul li select {
+ padding: .2em;
+ margin-right: .5em;
+ border: 1px solid #dadada;
+}
diff --git a/assets/src/i18n/en.yaml b/assets/src/i18n/en.yaml
index d09adc71..309be326 100644
--- a/assets/src/i18n/en.yaml
+++ b/assets/src/i18n/en.yaml
@@ -1,8 +1,10 @@
+permanent: Permanent
buttons:
cancel: Cancel
close: Close
copy: Copy
copyFile: Copy file
+ copyToClipboard: Copy to clipboard
create: Create
delete: Delete
download: Download
@@ -20,6 +22,7 @@ buttons:
save: Save
search: Search
select: Select
+ share: Share
publish: Publish
selectMultiple: Select multiple
schedule: Schedule
@@ -27,6 +30,7 @@ buttons:
toggleSidebar: Toggle sidebar
update: Update
upload: Upload
+ permalink: Get Permanent Link
errors:
forbidden: You're not welcome here.
internal: Something really went wrong.
@@ -183,3 +187,9 @@ languages:
en: English
pt: Portuguese
zhCN: Chinese (Simplified)
+time:
+ unit: Time Unit
+ seconds: Seconds
+ minutes: Minutes
+ hours: Hours
+ days: Days
diff --git a/assets/src/i18n/pt.yaml b/assets/src/i18n/pt.yaml
index 1444f450..9f2f982c 100644
--- a/assets/src/i18n/pt.yaml
+++ b/assets/src/i18n/pt.yaml
@@ -1,8 +1,10 @@
+permanent: Permanente
buttons:
cancel: Cancelar
close: Fechar
copy: Copiar
copyFile: Copiar ficheiro
+ copyToClipboard: Copiar
create: Criar
delete: Eliminar
download: Descarregar
@@ -19,6 +21,7 @@ buttons:
replace: Substituir
reportIssue: Reportar Erro
save: Guardar
+ share: Partilhar
schedule: Agendar
search: Pesquisar
select: Selecionar
@@ -27,6 +30,7 @@ buttons:
toggleSidebar: Alternar barra lateral
update: Atualizar
upload: Enviar
+ permalink: Obter link permanente
errors:
forbidden: Tu não és bem-vindo aqui.
internal: Algo correu bastante mal.
@@ -186,3 +190,9 @@ sidebar:
servedWith: Servido com
settings: Configurações
siteSettings: Configurações do Site
+time:
+ unit: Unidades de Tempo
+ seconds: Segundos
+ minutes: Minutos
+ hours: Horas
+ days: Dias
diff --git a/assets/src/store/mutations.js b/assets/src/store/mutations.js
index 0de28923..965bebef 100644
--- a/assets/src/store/mutations.js
+++ b/assets/src/store/mutations.js
@@ -1,4 +1,5 @@
import i18n from '@/i18n'
+import moment from 'moment'
const mutations = {
closeHovers: state => {
@@ -26,6 +27,7 @@ const mutations = {
setLoading: (state, value) => { state.loading = value },
setReload: (state, value) => { state.reload = value },
setUser: (state, value) => {
+ moment.locale(value.locale)
i18n.locale = value.locale
state.user = value
},
diff --git a/assets/src/utils/api.js b/assets/src/utils/api.js
index a91a9fc6..dc2029fa 100644
--- a/assets/src/utils/api.js
+++ b/assets/src/utils/api.js
@@ -35,7 +35,7 @@ export function fetch (url) {
})
}
-export function rm (url) {
+export function remove (url) {
url = removePrefix(url)
return new Promise((resolve, reject) => {
@@ -383,25 +383,69 @@ export function deleteUser (id) {
})
}
-export default {
- removePrefix,
- delete: rm,
- fetch,
- checksum,
- move,
- put,
- copy,
- post,
- command,
- search,
- download,
- // other things
- getSettings,
- updateSettings,
- // User things
- newUser,
- getUser,
- getUsers,
- updateUser,
- deleteUser
+// SHARE
+
+export function getShare (url) {
+ url = removePrefix(url)
+
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('GET', `${store.state.baseURL}/api/share${url}`, true)
+ request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
+
+ request.onload = () => {
+ if (request.status === 200) {
+ resolve(JSON.parse(request.responseText))
+ } else {
+ reject(request.status)
+ }
+ }
+
+ request.onerror = (error) => reject(error)
+ request.send()
+ })
+}
+
+export function deleteShare (hash) {
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('DELETE', `${store.state.baseURL}/api/share/${hash}`, true)
+ request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
+
+ request.onload = () => {
+ if (request.status === 200) {
+ resolve()
+ } else {
+ reject(request.status)
+ }
+ }
+
+ request.onerror = (error) => reject(error)
+ request.send()
+ })
+}
+
+export function share (url, expires = '', unit = 'hours') {
+ url = removePrefix(url)
+ url = `${store.state.baseURL}/api/share${url}`
+ if (expires !== '') {
+ url += `?expires=${expires}&unit=${unit}`
+ }
+
+ return new Promise((resolve, reject) => {
+ let request = new window.XMLHttpRequest()
+ request.open('POST', url, true)
+ request.setRequestHeader('Authorization', `Bearer ${store.state.jwt}`)
+
+ request.onload = () => {
+ if (request.status === 200) {
+ resolve(JSON.parse(request.responseText))
+ } else {
+ reject(request.responseStatus)
+ }
+ }
+
+ request.onerror = (error) => reject(error)
+ request.send()
+ })
}
diff --git a/assets/src/utils/buttons.js b/assets/src/utils/buttons.js
index bf083ece..0d266e2b 100644
--- a/assets/src/utils/buttons.js
+++ b/assets/src/utils/buttons.js
@@ -16,7 +16,7 @@ function loading (button) {
}, 100)
}
-function done (button, success = true) {
+function done (button) {
let el = document.querySelector(`#${button}-button > i`)
if (el === undefined || el === null) {
@@ -33,7 +33,34 @@ function done (button, success = true) {
}, 100)
}
+function success (button) {
+ let el = document.querySelector(`#${button}-button > i`)
+
+ if (el === undefined || el === null) {
+ console.log('Error getting button ' + button)
+ return
+ }
+
+ el.style.opacity = 0
+
+ setTimeout(() => {
+ el.classList.remove('spin')
+ el.innerHTML = 'done'
+ el.style.opacity = 1
+
+ setTimeout(() => {
+ el.style.opacity = 0
+
+ setTimeout(() => {
+ el.innerHTML = el.dataset.icon
+ el.style.opacity = 1
+ }, 100)
+ }, 500)
+ }, 100)
+}
+
export default {
loading,
- done
+ done,
+ success
}
diff --git a/assets/src/views/Files.vue b/assets/src/views/Files.vue
index 5492823c..8d8b3a16 100644
--- a/assets/src/views/Files.vue
+++ b/assets/src/views/Files.vue
@@ -33,7 +33,7 @@ import InternalError from './errors/500'
import Preview from '@/components/files/Preview'
import Listing from '@/components/files/Listing'
import Editor from '@/components/files/Editor'
-import api from '@/utils/api'
+import * as api from '@/utils/api'
import { mapGetters, mapState, mapMutations } from 'vuex'
export default {
diff --git a/assets/src/views/Users.vue b/assets/src/views/Users.vue
index 6c172f6d..0808d6b8 100644
--- a/assets/src/views/Users.vue
+++ b/assets/src/views/Users.vue
@@ -31,7 +31,7 @@