Compare commits

...

23 commits

Author SHA1 Message Date
Henry Jameson
f246611aa2 Merge remote-tracking branch 'origin/develop' into shigusegubu-themes3 2025-01-19 18:27:09 +02:00
Henry Jameson
19277f6cd5 Merge remote-tracking branch 'origin/develop' into shigusegubu-themes3 2025-01-19 18:26:50 +02:00
Henry Jameson
2b4052a2c8 Merge branch 'customizable-post-actions' into shigusegubu-themes3 2025-01-19 18:26:46 +02:00
HJ
60897ebbda Merge branch 'update-vue35' into 'develop'
Update Vue to 3.5

See merge request pleroma/pleroma-fe!1993
2025-01-19 16:23:22 +00:00
Henry Jameson
84b2a55424 fix tests 2025-01-19 18:22:30 +02:00
Henry Jameson
97aaa71bd6 changelog 2025-01-19 17:59:29 +02:00
Henry Jameson
97a944c690 $listeners is now part of $attrs 2025-01-19 17:58:08 +02:00
Henry Jameson
fc10e7cc1a update vue to v3.5 2025-01-19 17:54:35 +02:00
HJ
df100989ed Merge branch 'renovate/vue-test-utils-2.x' into 'develop'
Update dependency @vue/test-utils to v2.4.6

See merge request pleroma/pleroma-fe!1986
2025-01-19 15:38:37 +00:00
HJ
626066944e Merge branch 'renovate/babel-loader-9.x' into 'develop'
Update dependency babel-loader to v9.2.1

See merge request pleroma/pleroma-fe!1987
2025-01-19 15:38:22 +00:00
HJ
bd45a0d17b Merge branch 'renovate/chai-4.x' into 'develop'
Update dependency chai to v4.5.0

See merge request pleroma/pleroma-fe!1989
2025-01-19 15:38:07 +00:00
HJ
e4e6dc30b2 Merge branch 'renovate/cropperjs-1.x' into 'develop'
Update dependency cropperjs to v1.6.2

See merge request pleroma/pleroma-fe!1990
2025-01-19 15:37:57 +00:00
HJ
868187479b Merge branch 'renovate/css-loader-6.x' into 'develop'
Update dependency css-loader to v6.11.0

See merge request pleroma/pleroma-fe!1991
2025-01-19 15:37:48 +00:00
HJ
7586b75e1c Merge branch 'renovate/eslint-monorepo' into 'develop'
Update dependency eslint to v8.57.1

See merge request pleroma/pleroma-fe!1992
2025-01-19 15:37:38 +00:00
HJ
24699536c6 Merge branch 'client-side-resize' into 'develop'
MediaUpload: Resize images / convert to jpg/webp

See merge request pleroma/pleroma-fe!1988
2025-01-19 14:38:19 +00:00
Pleroma Renovate Bot
a1ddd01291 Update dependency eslint to v8.57.1 2025-01-19 09:05:07 +00:00
Pleroma Renovate Bot
518ca4a26c Update dependency css-loader to v6.11.0 2025-01-19 09:05:00 +00:00
Pleroma Renovate Bot
5cd7d3cd03 Update dependency cropperjs to v1.6.2 2025-01-18 08:51:47 +00:00
Pleroma Renovate Bot
8739bc7002 Update dependency chai to v4.5.0 2025-01-18 08:51:34 +00:00
Lain Soykaf
a2dca331e2 Add changelog 2025-01-18 10:33:06 +04:00
Lain Soykaf
8a40afa174 MediaUpload: Resize images / convert to jpg/webp 2025-01-17 16:33:26 +04:00
Pleroma Renovate Bot
bc79c1c901 Update dependency babel-loader to v9.2.1 2025-01-17 08:51:51 +00:00
Pleroma Renovate Bot
1b14b0cca7 Update dependency @vue/test-utils to v2.4.6 2025-01-17 08:51:39 +00:00
8 changed files with 544 additions and 349 deletions

View file

@ -0,0 +1 @@
Resize most kinds of images on upload.

1
changelog.d/vue.change Normal file
View file

@ -0,0 +1 @@
Upgraded Vue to version 3.5

View file

@ -30,7 +30,7 @@
"body-scroll-lock": "3.1.5", "body-scroll-lock": "3.1.5",
"chromatism": "3.0.0", "chromatism": "3.0.0",
"click-outside-vue3": "4.0.1", "click-outside-vue3": "4.0.1",
"cropperjs": "1.5.13", "cropperjs": "1.6.2",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
@ -43,10 +43,9 @@
"querystring-es3": "0.2.1", "querystring-es3": "0.2.1",
"url": "0.11.4", "url": "0.11.4",
"utf8": "3.0.0", "utf8": "3.0.0",
"vue": "3.2.45", "vue": "3.5.13",
"vue-i18n": "10", "vue-i18n": "10",
"vue-router": "4.1.6", "vue-router": "4.5.0",
"vue-template-compiler": "2.7.14",
"vue-virtual-scroller": "^2.0.0-beta.7", "vue-virtual-scroller": "^2.0.0-beta.7",
"vuex": "4.1.0" "vuex": "4.1.0"
}, },
@ -60,21 +59,21 @@
"@ungap/event-target": "0.2.4", "@ungap/event-target": "0.2.4",
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0", "@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
"@vue/babel-plugin-jsx": "1.2.5", "@vue/babel-plugin-jsx": "1.2.5",
"@vue/compiler-sfc": "3.2.45", "@vue/compiler-sfc": "3.5.13",
"@vue/test-utils": "2.2.8", "@vue/test-utils": "2.4.6",
"autoprefixer": "10.4.20", "autoprefixer": "10.4.20",
"babel-loader": "9.1.3", "babel-loader": "9.2.1",
"babel-plugin-lodash": "3.3.4", "babel-plugin-lodash": "3.3.4",
"chai": "4.3.7", "chai": "4.5.0",
"chalk": "1.1.3", "chalk": "1.1.3",
"chromedriver": "108.0.0", "chromedriver": "108.0.0",
"connect-history-api-fallback": "2.0.0", "connect-history-api-fallback": "2.0.0",
"copy-webpack-plugin": "11.0.0", "copy-webpack-plugin": "11.0.0",
"cross-spawn": "7.0.6", "cross-spawn": "7.0.6",
"css-loader": "6.10.0", "css-loader": "6.11.0",
"css-minimizer-webpack-plugin": "4.2.2", "css-minimizer-webpack-plugin": "4.2.2",
"custom-event-polyfill": "1.0.7", "custom-event-polyfill": "1.0.7",
"eslint": "8.33.0", "eslint": "8.57.1",
"eslint-config-standard": "17.0.0", "eslint-config-standard": "17.0.0",
"eslint-formatter-friendly": "7.0.0", "eslint-formatter-friendly": "7.0.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",

View file

@ -28,7 +28,81 @@ const mediaUpload = {
this.$refs.input.click() this.$refs.input.click()
} }
}, },
uploadFile (file) { async resizeImage (file) {
// Skip if not an image or if it's a GIF
if (!file.type.startsWith('image/') || file.type === 'image/gif') {
return file
}
// For PNGs, check if animated
if (file.type === 'image/png') {
const isAnimated = await this.isAnimatedPng(file)
if (isAnimated) {
return file
}
}
return new Promise((resolve) => {
const img = new Image()
img.onload = () => {
// Calculate new dimensions
let width = img.width
let height = img.height
const maxSize = 2048
if (width > maxSize || height > maxSize) {
if (width > height) {
height = Math.round((height * maxSize) / width)
width = maxSize
} else {
width = Math.round((width * maxSize) / height)
height = maxSize
}
}
// Create canvas and resize
const canvas = document.createElement('canvas')
canvas.width = width
canvas.height = height
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, width, height)
// Check WebP support by trying to create a WebP canvas
const testCanvas = document.createElement('canvas')
const supportsWebP = testCanvas.toDataURL('image/webp').startsWith('data:image/webp')
// Convert to WebP if supported, otherwise JPEG
const type = supportsWebP ? 'image/webp' : 'image/jpeg'
const extension = supportsWebP ? '.webp' : '.jpg'
// Remove the original extension and add new one
const newFileName = file.name.replace(/\.[^/.]+$/, '') + extension
canvas.toBlob((blob) => {
resolve(new File([blob], newFileName, {
type: type,
lastModified: Date.now()
}))
}, type, 0.85)
}
img.src = URL.createObjectURL(file)
})
},
async isAnimatedPng (file) {
const buffer = await file.arrayBuffer()
const view = new Uint8Array(buffer)
// Look for animated PNG chunks (acTL)
for (let i = 0; i < view.length - 8; i++) {
if (view[i] === 0x61 && // a
view[i + 1] === 0x63 && // c
view[i + 2] === 0x54 && // T
view[i + 3] === 0x4C) { // L
return true
}
}
return false
},
async uploadFile (file) {
const self = this const self = this
const store = this.$store const store = this.$store
if (file.size > store.state.instance.uploadlimit) { if (file.size > store.state.instance.uploadlimit) {
@ -37,8 +111,11 @@ const mediaUpload = {
self.$emit('upload-failed', 'file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit }) self.$emit('upload-failed', 'file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit })
return return
} }
// Resize image if needed
const processedFile = await this.resizeImage(file)
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', processedFile)
self.$emit('uploading') self.$emit('uploading')
self.uploadCount++ self.uploadCount++

View file

@ -2,7 +2,6 @@
<pinch-zoom <pinch-zoom
class="pinch-zoom-parent" class="pinch-zoom-parent"
v-bind="$attrs" v-bind="$attrs"
v-on="$listeners"
> >
<slot /> <slot />
</pinch-zoom> </pinch-zoom>

View file

@ -89,7 +89,7 @@ const _verifyPrefs = (state) => {
}) })
} }
export const _getRecentData = (cache, live) => { export const _getRecentData = (cache, live, isTest) => {
const result = { recent: null, stale: null, needUpload: false } const result = { recent: null, stale: null, needUpload: false }
const cacheValid = _checkValidity(cache || {}) const cacheValid = _checkValidity(cache || {})
const liveValid = _checkValidity(live || {}) const liveValid = _checkValidity(live || {})
@ -124,6 +124,8 @@ export const _getRecentData = (cache, live) => {
} }
const merge = (a, b) => ({ const merge = (a, b) => ({
_version: a._version ?? b._version,
_timestamp: a._timestamp ?? b._timestamp,
needUpload: b.needUpload ?? a.needUpload, needUpload: b.needUpload ?? a.needUpload,
prefsStorage: { prefsStorage: {
...a.prefsStorage, ...a.prefsStorage,
@ -134,8 +136,8 @@ export const _getRecentData = (cache, live) => {
...b.flagStorage ...b.flagStorage
} }
}) })
result.recent = result.recent && merge(defaultState, result.recent) result.recent = isTest ? result.recent : (result.recent && merge(defaultState, result.recent))
result.stale = result.stale && merge(defaultState, result.stale) result.stale = isTest ? result.stale : (result.stale && merge(defaultState, result.stale))
return result return result
} }
@ -308,7 +310,7 @@ export const mutations = {
clearServerSideStorage (state, userData) { clearServerSideStorage (state, userData) {
state = { ...cloneDeep(defaultState) } state = { ...cloneDeep(defaultState) }
}, },
setServerSideStorage (state, userData) { setServerSideStorage (state, userData, test) {
const live = userData.storage const live = userData.storage
state.raw = live state.raw = live
let cache = state.cache let cache = state.cache

View file

@ -74,7 +74,7 @@ describe('The serverSideStorage module', () => {
}) })
}) })
it('should reset local timestamp to remote if contents are the same', () => { it.only('should reset local timestamp to remote if contents are the same', () => {
const state = { const state = {
...cloneDeep(defaultState), ...cloneDeep(defaultState),
cache: null cache: null
@ -176,33 +176,33 @@ describe('The serverSideStorage module', () => {
}) })
describe('_getRecentData', () => { describe('_getRecentData', () => {
it('should handle nulls correctly', () => { it('should handle nulls correctly', () => {
expect(_getRecentData(null, null)).to.eql({ recent: null, stale: null, needUpload: true }) expect(_getRecentData(null, null, true)).to.eql({ recent: null, stale: null, needUpload: true })
}) })
it('doesn\'t choke on invalid data', () => { it('doesn\'t choke on invalid data', () => {
expect(_getRecentData({ a: 1 }, { b: 2 })).to.eql({ recent: null, stale: null, needUpload: true }) expect(_getRecentData({ a: 1 }, { b: 2 }, true)).to.eql({ recent: null, stale: null, needUpload: true })
}) })
it('should prefer the valid non-null correctly, needUpload works properly', () => { it('should prefer the valid non-null correctly, needUpload works properly', () => {
const nonNull = { _version: VERSION, _timestamp: 1 } const nonNull = { _version: VERSION, _timestamp: 1 }
expect(_getRecentData(nonNull, null)).to.eql({ recent: nonNull, stale: null, needUpload: true }) expect(_getRecentData(nonNull, null, true)).to.eql({ recent: nonNull, stale: null, needUpload: true })
expect(_getRecentData(null, nonNull)).to.eql({ recent: nonNull, stale: null, needUpload: false }) expect(_getRecentData(null, nonNull, true)).to.eql({ recent: nonNull, stale: null, needUpload: false })
}) })
it('should prefer the one with higher timestamp', () => { it('should prefer the one with higher timestamp', () => {
const a = { _version: VERSION, _timestamp: 1 } const a = { _version: VERSION, _timestamp: 1 }
const b = { _version: VERSION, _timestamp: 2 } const b = { _version: VERSION, _timestamp: 2 }
expect(_getRecentData(a, b)).to.eql({ recent: b, stale: a, needUpload: false }) expect(_getRecentData(a, b, true)).to.eql({ recent: b, stale: a, needUpload: false })
expect(_getRecentData(b, a)).to.eql({ recent: b, stale: a, needUpload: false }) expect(_getRecentData(b, a, true)).to.eql({ recent: b, stale: a, needUpload: false })
}) })
it('case where both are same', () => { it('case where both are same', () => {
const a = { _version: VERSION, _timestamp: 3 } const a = { _version: VERSION, _timestamp: 3 }
const b = { _version: VERSION, _timestamp: 3 } const b = { _version: VERSION, _timestamp: 3 }
expect(_getRecentData(a, b)).to.eql({ recent: b, stale: a, needUpload: false }) expect(_getRecentData(a, b, true)).to.eql({ recent: b, stale: a, needUpload: false })
expect(_getRecentData(b, a)).to.eql({ recent: b, stale: a, needUpload: false }) expect(_getRecentData(b, a, true)).to.eql({ recent: b, stale: a, needUpload: false })
}) })
}) })

762
yarn.lock

File diff suppressed because it is too large Load diff