Skip to content

Commit d82b195

Browse files
committed
fix: Create new files on public pages for 31+
Signed-off-by: Julius Knorr <jus@bitgrid.net>
1 parent 6e43e3b commit d82b195

4 files changed

Lines changed: 137 additions & 164 deletions

File tree

src/helpers/types.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ const getFileTypes = () => {
4949
}
5050

5151
const getFileType = (document) => {
52-
return getFileTypes()[document]
52+
return {
53+
...getFileTypes()[document],
54+
name: document,
55+
}
5356
}
5457

5558
export default {

src/public.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ import {
1010
isDownloadHidden,
1111
} from './helpers/index.js'
1212
import { getCapabilities } from './services/capabilities.ts'
13-
import NewFileMenu from './view/NewFileMenu.js'
13+
import { registerNewFileMenuEntries } from './view/NewFileMenu.js'
1414

1515
document.addEventListener('DOMContentLoaded', () => {
1616
if (!isPublicShare() || !OCA.Viewer) {
1717
return
1818
}
1919

20-
if (OCA.Files && OCA.Files.fileActions) {
21-
OC.Plugins.register('OCA.Files.NewFileMenu', NewFileMenu)
22-
}
20+
registerNewFileMenuEntries()
2321

2422
const isEnabledFilesPdfViewer = getCapabilities().mimetypesNoDefaultOpen.includes('application/pdf')
2523

src/services/api.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66
import axios from '@nextcloud/axios'
77
import { generateOcsUrl, generateFilePath } from '@nextcloud/router'
88
import { getSharingToken } from '@nextcloud/sharing/public'
9-
import { getCurrentDirectory } from '../helpers/filesApp.js'
109

11-
export const createEmptyFile = async (mimeType, fileName, templateId = null) => {
10+
export const createEmptyFile = async (context, mimeType, fileName, templateId = null) => {
1211
const shareToken = getSharingToken()
13-
const directoryPath = getCurrentDirectory()
1412

1513
const response = await axios.post(generateOcsUrl('apps/richdocuments/api/v1/file', 2), {
1614
mimeType,
1715
fileName,
18-
directoryPath,
16+
directoryPath: context.dirname,
1917
shareToken,
2018
templateId,
2119
})

src/view/NewFileMenu.js

Lines changed: 129 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -4,174 +4,148 @@
44
*/
55

66
import axios from '@nextcloud/axios'
7-
import { getCurrentDirectory } from '../helpers/filesApp.js'
7+
import { emit } from '@nextcloud/event-bus'
88
import Types from '../helpers/types.js'
99
import { createEmptyFile } from '../services/api.js'
1010
import { generateUrl, generateFilePath, generateOcsUrl } from '@nextcloud/router'
1111
import { showError } from '@nextcloud/dialogs'
1212
import { getCapabilities } from '../services/capabilities.ts'
13-
14-
/** @type OC.Plugin */
15-
const NewFileMenu = {
16-
attach(newFileMenu) {
17-
const self = this
18-
const document = Types.getFileType('document')
19-
const spreadsheet = Types.getFileType('spreadsheet')
20-
const presentation = Types.getFileType('presentation')
21-
const drawing = Types.getFileType('drawing')
22-
23-
newFileMenu.addMenuEntry({
24-
id: 'add-' + document.extension,
25-
displayName: t('richdocuments', 'New document'),
26-
templateName: t('richdocuments', 'New document') + '.' + document.extension,
27-
iconClass: 'icon-filetype-document',
28-
fileType: 'x-office-document',
29-
actionHandler(filename) {
30-
if (getCapabilities().templates) {
31-
self._openTemplatePicker('document', document.mime, filename)
32-
} else {
33-
self._createDocument(document.mime, filename)
34-
}
35-
},
36-
})
37-
38-
newFileMenu.addMenuEntry({
39-
id: 'add-' + spreadsheet.extension,
40-
displayName: t('richdocuments', 'New spreadsheet'),
41-
templateName: t('richdocuments', 'New spreadsheet') + '.' + spreadsheet.extension,
42-
iconClass: 'icon-filetype-spreadsheet',
43-
fileType: 'x-office-spreadsheet',
44-
actionHandler(filename) {
45-
if (getCapabilities().templates) {
46-
self._openTemplatePicker('spreadsheet', spreadsheet.mime, filename)
47-
} else {
48-
self._createDocument(spreadsheet.mime, filename)
49-
}
50-
},
51-
})
52-
53-
newFileMenu.addMenuEntry({
54-
id: 'add-' + presentation.extension,
55-
displayName: t('richdocuments', 'New presentation'),
56-
templateName: t('richdocuments', 'New presentation') + '.' + presentation.extension,
57-
iconClass: 'icon-filetype-presentation',
58-
fileType: 'x-office-presentation',
59-
actionHandler(filename) {
60-
if (getCapabilities().templates) {
61-
self._openTemplatePicker('presentation', presentation.mime, filename)
62-
} else {
63-
self._createDocument(presentation.mime, filename)
64-
}
65-
},
66-
})
67-
68-
newFileMenu.addMenuEntry({
69-
id: 'add-' + drawing.extension,
70-
displayName: t('richdocuments', 'New drawing'),
71-
templateName: t('richdocuments', 'New drawing') + '.' + drawing.extension,
72-
iconClass: 'icon-filetype-draw',
73-
fileType: 'x-office-drawing',
74-
actionHandler(filename) {
75-
if (getCapabilities().templates) {
76-
self._openTemplatePicker('drawing', drawing.mime, filename)
77-
} else {
78-
self._createDocument(drawing.mime, filename)
79-
}
80-
},
81-
})
13+
import { File, addNewFileMenuEntry, isFilenameValid, getUniqueName } from '@nextcloud/files'
14+
15+
const createFileTypeEntry = (type, displayName, iconClass, index) => ({
16+
id: 'add-' + type.extension,
17+
displayName: t('richdocuments', displayName),
18+
iconClass,
19+
order: 10 + index,
20+
async handler(context, content) {
21+
const filename = t('richdocuments', displayName) + '.' + type.extension
22+
if (getCapabilities().templates) {
23+
await openTemplatePicker(context, type.name, type.mime, filename, content)
24+
} else {
25+
await createDocument(context, type.mime, filename, null, content)
26+
}
8227
},
28+
})
29+
30+
export const registerNewFileMenuEntries = () => {
31+
const fileTypes = [
32+
{ type: Types.getFileType('document'), displayName: 'New document', iconClass: 'icon-filetype-document' },
33+
{ type: Types.getFileType('spreadsheet'), displayName: 'New spreadsheet', iconClass: 'icon-filetype-spreadsheet' },
34+
{ type: Types.getFileType('presentation'), displayName: 'New presentation', iconClass: 'icon-filetype-presentation' },
35+
{ type: Types.getFileType('drawing'), displayName: 'New drawing', iconClass: 'icon-filetype-draw' },
36+
]
37+
38+
fileTypes.forEach(({ type, displayName, iconClass }, index) => {
39+
addNewFileMenuEntry(createFileTypeEntry(type, displayName, iconClass, index))
40+
})
41+
}
8342

84-
_createDocument(mimetype, filename, templateId = null) {
85-
OCA.Files.Files.isFileNameValid(filename)
86-
filename = FileList.getUniqueName(filename)
87-
88-
createEmptyFile(mimetype, filename, templateId).then((response) => {
89-
if (response && response.status === 'success') {
90-
FileList.add(response.data, { animate: true, scrollTo: true })
91-
const fileModel = FileList.getModelForFile(filename)
92-
const fileAction = OCA.Files.fileActions.getDefaultFileAction(fileModel.get('mimetype'), 'file', OC.PERMISSION_ALL)
93-
fileAction.action(filename, {
94-
$file: null,
95-
fileId: fileModel.id,
96-
dir: getCurrentDirectory(),
97-
fileList: FileList,
98-
fileActions: FileList.fileActions,
99-
})
100-
} else {
101-
showError(t('core', 'Could not create file') + ': ' + response.data.message)
102-
}
43+
const createDocument = async (context, mimetype, filename, templateId = null, content = []) => {
44+
if (!isFilenameValid(filename)) {
45+
return
46+
}
47+
48+
filename = getUniqueName(
49+
filename,
50+
content.map((n) => n.basename),
51+
)
52+
53+
try {
54+
const response = await createEmptyFile(context, mimetype, filename, templateId)
55+
const { data } = response
56+
57+
const file = new File({
58+
source: context.source + '/' + filename,
59+
basename: filename,
60+
id: data.id,
61+
mtime: new Date(data.mtime),
62+
mime: data.mimetype,
63+
owner: null,
64+
permissions: data.permissions,
65+
root: context?.root,
10366
})
104-
},
67+
emit('files:node:created', file)
10568

106-
_openTemplatePicker(type, mimetype, filename) {
107-
axios.get(generateOcsUrl(`apps/richdocuments/api/v1/templates/${type}`, 2)).then(({ data: response }) => {
108-
if (response.ocs.data.length === 1) {
109-
const { id } = response.ocs.data[0]
110-
this._createDocument(mimetype, filename, id)
111-
return
112-
}
113-
this._buildTemplatePicker(response.ocs.data)
114-
.then(() => {
115-
const self = this
116-
const buttonlist = [{
117-
text: t('core', 'Cancel'),
118-
classes: 'cancel',
119-
click() {
120-
$(this).ocdialog('close')
121-
},
122-
}, {
123-
text: t('richdocuments', 'Create'),
124-
classes: 'primary',
125-
click() {
126-
const templateId = this.dataset.templateId
127-
self._createDocument(mimetype, filename, templateId)
128-
$(this).ocdialog('close')
129-
},
130-
}]
131-
132-
$('#template-picker').ocdialog({
133-
closeOnEscape: true,
134-
modal: true,
135-
buttons: buttonlist,
136-
})
137-
})
138-
})
139-
},
69+
if (response && response.status === 'success') {
70+
OCA.Viewer.open({ path: context.dirname + '/' + filename })
71+
} else {
72+
showError(t('core', 'Could not create file') + ': ' + response.data.message)
73+
}
74+
} catch (error) {
75+
console.error(error)
76+
showError(t('core', 'Could not create file'))
77+
}
78+
}
14079

141-
_buildTemplatePicker(data) {
142-
return axios.get(generateFilePath('richdocuments', 'templates', 'templatePicker.html')).then(({ data: tmpl }) => {
143-
const $tmpl = $(tmpl).eq(2)
144-
// init template picker
145-
const $dlg = $tmpl.octemplate({
146-
dialog_name: 'template-picker',
147-
dialog_title: t('richdocuments', 'Select template'),
148-
})
149-
150-
// create templates list
151-
const templates = Object.values(data)
152-
templates.forEach((template) => {
153-
this._appendTemplateFromData($dlg[0], template)
154-
})
155-
156-
$('body').append($dlg)
157-
})
158-
},
80+
const openTemplatePicker = async (context, type, mimetype, filename, content = []) => {
81+
try {
82+
const { data: response } = await axios.get(generateOcsUrl(`apps/richdocuments/api/v1/templates/${type}`, 2))
83+
const templates = response.ocs.data
15984

160-
_appendTemplateFromData(dlg, data) {
161-
const template = dlg.querySelector('.template-model').cloneNode(true)
162-
template.className = ''
163-
template.querySelector('img').src = generateUrl('apps/richdocuments/template/preview/' + data.id)
164-
template.querySelector('h2').textContent = data.name
165-
template.onclick = function(e) {
166-
e.preventDefault()
167-
dlg.dataset.templateId = data.id
85+
if (templates.length === 1) {
86+
await createDocument(context, mimetype, filename, templates[0].id, content)
87+
return
16888
}
169-
if (!dlg.dataset.templateId) {
170-
dlg.dataset.templateId = data.id
89+
90+
await showTemplatePickerDialog(context, type, mimetype, filename, templates, content)
91+
} catch (error) {
92+
console.error(error)
93+
showError(t('core', 'Could not load templates'))
94+
}
95+
}
96+
97+
const showTemplatePickerDialog = async (context, type, mimetype, filename, templates, content) => {
98+
const { data: tmpl } = await axios.get(generateFilePath('richdocuments', 'templates', 'templatePicker.html'))
99+
const $tmpl = $(tmpl).eq(2)
100+
const $dlg = $tmpl.octemplate({
101+
dialog_name: 'template-picker',
102+
dialog_title: t('richdocuments', 'Select template'),
103+
})
104+
105+
templates.forEach((template) => {
106+
appendTemplateFromData($dlg[0], template)
107+
})
108+
109+
$('body').append($dlg)
110+
111+
const buttonlist = [
112+
{
113+
text: t('core', 'Cancel'),
114+
classes: 'cancel',
115+
click() {
116+
$(this).ocdialog('close')
117+
},
118+
},
119+
{
120+
text: t('richdocuments', 'Create'),
121+
classes: 'primary',
122+
click() {
123+
const templateId = this.dataset.templateId
124+
createDocument(context, mimetype, filename, templateId, content)
125+
$(this).ocdialog('close')
126+
},
171127
}
128+
]
172129

173-
dlg.querySelector('.template-container').appendChild(template)
174-
},
130+
$('#template-picker').ocdialog({
131+
closeOnEscape: true,
132+
modal: true,
133+
buttons: buttonlist,
134+
})
175135
}
176136

177-
export default NewFileMenu
137+
const appendTemplateFromData = (dlg, data) => {
138+
const template = dlg.querySelector('.template-model').cloneNode(true)
139+
template.className = ''
140+
template.querySelector('img').src = generateUrl('apps/richdocuments/template/preview/' + data.id)
141+
template.querySelector('h2').textContent = data.name
142+
template.onclick = function(e) {
143+
e.preventDefault()
144+
dlg.dataset.templateId = data.id
145+
}
146+
if (!dlg.dataset.templateId) {
147+
dlg.dataset.templateId = data.id
148+
}
149+
150+
dlg.querySelector('.template-container').appendChild(template)
151+
}

0 commit comments

Comments
 (0)