main.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /* eslint-env browser */
  2. const marked = require('marked')
  3. const dragdrop = require('drag-drop')
  4. const transloadit = require('@uppy/robodog')
  5. // TOP SECRET!!!!!!!
  6. const TRANSLOADIT_KEY = '05a61ed019fe11e783fdbd1f56c73eb0'
  7. const THUMB_SIZE = [400, 300]
  8. /* eslint-disable no-template-curly-in-string */
  9. const IMAGE_FILTER = ['${file.mime}', 'regex', 'image/']
  10. const VIDEO_FILTER = ['${file.mime}', 'regex', 'video/']
  11. const AUDIO_FILTER = ['${file.mime}', 'regex', 'audio/']
  12. /* eslint-enable no-template-curly-in-string */
  13. const transloaditSteps = {
  14. ':original': {
  15. robot: '/upload/handle'
  16. },
  17. // Separate source files
  18. images: {
  19. use: [':original'],
  20. robot: '/file/filter',
  21. result: true,
  22. accepts: [IMAGE_FILTER]
  23. },
  24. videos: {
  25. use: [':original'],
  26. robot: '/file/filter',
  27. result: true,
  28. accepts: [VIDEO_FILTER]
  29. },
  30. audios: {
  31. use: [':original'],
  32. robot: '/file/filter',
  33. result: true,
  34. accepts: [AUDIO_FILTER]
  35. },
  36. others: {
  37. use: [':original'],
  38. robot: '/file/filter',
  39. result: true,
  40. rejects: [IMAGE_FILTER, VIDEO_FILTER, AUDIO_FILTER]
  41. },
  42. // Generate thumbs for different types of files
  43. audio_thumbnails: {
  44. use: ['audios'],
  45. robot: '/audio/artwork'
  46. },
  47. resized_thumbnails: {
  48. use: ['images', 'audio_thumbnails'],
  49. robot: '/image/resize',
  50. imagemagick_stack: 'v1.0.0',
  51. width: THUMB_SIZE[0],
  52. height: THUMB_SIZE[1],
  53. resize_strategy: 'fit',
  54. zoom: false
  55. },
  56. video_thumbnails: {
  57. use: ['videos'],
  58. robot: '/video/thumbs',
  59. ffmpeg_stack: 'v2.2.3',
  60. count: 1,
  61. offsets: ['50%'],
  62. format: 'jpeg',
  63. width: THUMB_SIZE[0],
  64. height: THUMB_SIZE[1],
  65. resize_strategy: 'fit'
  66. },
  67. // Optimize thumbnails for decent file size
  68. thumbnails: {
  69. use: ['resized_thumbnails', 'video_thumbnails'],
  70. robot: '/image/optimize'
  71. },
  72. // Store all the things away
  73. store_sources: {
  74. use: ['images', 'videos', 'audios', 'others'],
  75. robot: '/s3/store',
  76. credentials: 'uppy_test_s3',
  77. // eslint-disable-next-line no-template-curly-in-string
  78. path: 'markdownbin/sources/${unique_prefix}/${file.url_name}',
  79. result: true
  80. },
  81. store_thumbnails: {
  82. use: ['thumbnails'],
  83. robot: '/s3/store',
  84. credentials: 'uppy_test_s3',
  85. // eslint-disable-next-line no-template-curly-in-string
  86. path: 'markdownbin/thumbs/${file.md5hash}',
  87. result: true
  88. }
  89. }
  90. class MarkdownTextarea {
  91. constructor (element) {
  92. this.element = element
  93. this.controls = document.createElement('div')
  94. this.controls.classList.add('mdtxt-controls')
  95. this.uploadLine = document.createElement('div')
  96. this.uploadLine.classList.add('mdtxt-upload')
  97. this.uploadLine.appendChild(
  98. document.createTextNode('Upload an attachment'))
  99. }
  100. install () {
  101. const { element } = this
  102. const wrapper = document.createElement('div')
  103. wrapper.classList.add('mdtxt')
  104. element.parentNode.replaceChild(wrapper, element)
  105. wrapper.appendChild(this.controls)
  106. wrapper.appendChild(element)
  107. wrapper.appendChild(this.uploadLine)
  108. this.setupUploadLine()
  109. }
  110. setupTextareaDrop () {
  111. dragdrop(this.element, (files) => {
  112. this.uploadFiles(files)
  113. })
  114. }
  115. setupUploadLine () {
  116. this.uploadLine.addEventListener('click', () => {
  117. this.pickFiles()
  118. })
  119. }
  120. reportUploadError (err) {
  121. this.uploadLine.classList.add('error')
  122. const message = document.createElement('span')
  123. message.appendChild(document.createTextNode(err.message))
  124. this.uploadLine.insertChild(message, this.uploadLine.firstChild)
  125. }
  126. unreportUploadError () {
  127. this.uploadLine.classList.remove('error')
  128. const message = this.uploadLine.querySelector('message')
  129. if (message) {
  130. this.uploadLine.removeChild(message)
  131. }
  132. }
  133. insertAttachments (attachments) {
  134. attachments.forEach((attachment) => {
  135. const { file, thumb } = attachment
  136. const link = `\n[LABEL](${file.ssl_url})\n`
  137. const labelText = `View File ${file.basename}`
  138. if (thumb) {
  139. this.element.value += link.replace('LABEL', `![${labelText}](${thumb.ssl_url})`)
  140. } else {
  141. this.element.value += link.replace('LABEL', labelText)
  142. }
  143. })
  144. }
  145. matchFilesAndThumbs (results) {
  146. const filesById = {}
  147. const thumbsById = {}
  148. results.forEach((result) => {
  149. if (result.stepName === 'thumbnails') {
  150. thumbsById[result.original_id] = result
  151. } else {
  152. filesById[result.original_id] = result
  153. }
  154. })
  155. return Object.keys(filesById).reduce((acc, key) => {
  156. const file = filesById[key]
  157. const thumb = thumbsById[key]
  158. acc.push({ file, thumb })
  159. return acc
  160. }, [])
  161. }
  162. uploadFiles (files) {
  163. transloadit.upload({
  164. waitForEncoding: true,
  165. params: {
  166. auth: { key: TRANSLOADIT_KEY },
  167. steps: transloaditSteps
  168. }
  169. }).then((result) => {
  170. this.insertAttachments(
  171. this.matchFilesAndThumbs(result.results)
  172. )
  173. }).catch((err) => {
  174. console.error(err)
  175. this.reportUploadError(err)
  176. })
  177. }
  178. pickFiles () {
  179. transloadit.pick({
  180. waitForEncoding: true,
  181. params: {
  182. auth: { key: TRANSLOADIT_KEY },
  183. steps: transloaditSteps
  184. }
  185. }).then((result) => {
  186. this.insertAttachments(
  187. this.matchFilesAndThumbs(result.results)
  188. )
  189. }).catch((err) => {
  190. console.error(err)
  191. this.reportUploadError(err)
  192. })
  193. }
  194. }
  195. const textarea = new MarkdownTextarea(
  196. document.querySelector('#new textarea'))
  197. textarea.install()
  198. function renderSnippet (title, text) {
  199. const template = document.querySelector('#snippet')
  200. const newSnippet = document.importNode(template.content, true)
  201. const titleEl = newSnippet.querySelector('.snippet-title')
  202. const contentEl = newSnippet.querySelector('.snippet-content')
  203. titleEl.appendChild(document.createTextNode(title))
  204. contentEl.innerHTML = marked(text)
  205. const list = document.querySelector('#snippets')
  206. list.insertBefore(newSnippet, list.firstChild)
  207. }
  208. function saveSnippet (title, text) {
  209. const id = parseInt(localStorage.numSnippets || 0, 10)
  210. localStorage[`snippet_${id}`] = JSON.stringify({ title, text })
  211. localStorage.numSnippets = id + 1
  212. }
  213. function loadSnippets () {
  214. for (let id = 0; localStorage[`snippet_${id}`] != null; id += 1) {
  215. const { title, text } = JSON.parse(localStorage[`snippet_${id}`])
  216. renderSnippet(title, text)
  217. }
  218. }
  219. document.querySelector('#new').addEventListener('submit', (event) => {
  220. event.preventDefault()
  221. const title = event.target.querySelector('input[name="title"]').value ||
  222. 'Unnamed Snippet'
  223. const text = textarea.element.value
  224. saveSnippet(title, text)
  225. renderSnippet(title, text)
  226. event.target.querySelector('input').value = ''
  227. event.target.querySelector('textarea').value = ''
  228. })
  229. window.addEventListener('DOMContentLoaded', () => {
  230. loadSnippets()
  231. })