Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions browser/components/markdown.styl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ body
padding 5px
border-radius 5px
justify-content left
.audio-player
width: 100%
margin-bottom: 1em
li
label.taskListItem
margin-left -1.8em
Expand Down
53 changes: 53 additions & 0 deletions browser/lib/markdown-it-audio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict'
import { normalizeReference } from 'markdown-it/lib/common/utils'
module.exports = function audioPlugin (md) {
function audio (state, startLine) {
// match @[](src.mp3) or @[refsrc]
const audioSouceRegex = /^@\[.*\]\((.*?)\)/
const audioReferenceSourceRegex = /^@\[(.*?)\]/
const start = state.bMarks[startLine]
const end = state.eMarks[startLine]
let token = null

// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }

// Audio must be at start of input or the previous line must be blank.
if (startLine !== 0) {
const prevLineStartPos = state.bMarks[startLine - 1] + state.tShift[startLine - 1]
const prevLineMaxPos = state.eMarks[startLine - 1]
if (prevLineMaxPos > prevLineStartPos) return false
}

let match = audioSouceRegex.exec(state.src.slice(start, end))
if (!match || match.length < 2) {
match = audioReferenceSourceRegex.exec(state.src.slice(start, end))
}
if (!match || match.length < 2) {
return false
}
let src = match[1]
// this is a reference link
if (!src.endsWith('.mp3') && !src.endsWith('.wav') && !src.endsWith('.ogg')) {
if (typeof state.env.references === 'undefined') {
return false
}
src = state.env.references[normalizeReference(src)].href
}
token = state.push('audio')
state.line = startLine + 1
token.src = src
return true
}

function audioRender (tokens, idx) {
const token = tokens[idx]
return `<audio class='audio-player' src='${token.src}' controls></audio>`
}

md.block.ruler.before('fence', 'audio', audio, {
alt: ['paragraph', 'reference', 'blockquote', 'list']
})

md.renderer.rules['audio'] = audioRender
}
1 change: 1 addition & 0 deletions browser/lib/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class Markdown {
this.md.use(require('markdown-it-sup'))
this.md.use(require('./markdown-it-deflist'))
this.md.use(require('./markdown-it-frontmatter'))
this.md.use(require('./markdown-it-audio'))

this.md.use(require('./markdown-it-fence'), {
chart: token => {
Expand Down
50 changes: 41 additions & 9 deletions browser/main/lib/dataApi/attachmentManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import i18n from 'browser/lib/i18n'
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
const DESTINATION_FOLDER = 'attachments'
const PATH_SEPARATORS = escapeStringRegexp(path.posix.sep) + escapeStringRegexp(path.win32.sep)
// file type of attachments
const FILE_TYPES = {
IMAGE: 'image',
AUDIO: 'audio'
}
/**
* @description
* Create a Image element to get the real size of image.
Expand Down Expand Up @@ -227,7 +232,7 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
*/
function fixLocalURLS (renderedHTML, storagePath) {
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?["|\']', 'g'), function (match) {
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
})
Expand All @@ -237,11 +242,20 @@ function fixLocalURLS (renderedHTML, storagePath) {
* @description Generates the markdown code for a given attachment
* @param {String} fileName Name of the attachment
* @param {String} path Path of the attachment
* @param {Boolean} showPreview Indicator whether the generated markdown should show a preview of the image. Note that at the moment only previews for images are supported
* @param {Boolean} showPreview Indicator whether the generated markdown should show a preview of the attachment.
* @param {String} previewType Name of the type of attachment to preview
* @returns {String} Generated markdown code
*/
function generateAttachmentMarkdown (fileName, path, showPreview) {
return `${showPreview ? '!' : ''}[${fileName}](${path})`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you remove the parameter (and evaluation) ´showPreview´????

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I'll fix it right away 😄

function generateAttachmentMarkdown (fileName, path, showPreview, previewType) {
if (!showPreview) {
return `[${fileName}](${path})`
}
switch (previewType) {
case FILE_TYPES.IMAGE:
return `![${fileName}](${path})`
case FILE_TYPES.AUDIO:
return `@[${fileName}](${path})`
}
}

/**
Expand All @@ -256,22 +270,40 @@ function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) {
const file = dropEvent.dataTransfer.files[0]
const filePath = file.path
const originalFileName = path.basename(filePath)
const fileType = file['type']
const isImage = fileType.startsWith('image')
const fileType = getFileType(file['type'])
let promise
if (isImage) {
if (fileType === FILE_TYPES.IMAGE) {
promise = fixRotate(file).then(base64data => {
return copyAttachment({type: 'base64', data: base64data, sourceFilePath: filePath}, storageKey, noteKey)
})
} else {
promise = copyAttachment(filePath, storageKey, noteKey)
}
// generate markdown syntax part
promise.then((fileName) => {
const imageMd = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), isImage)
codeEditor.insertAttachmentMd(imageMd)
let shouldShowPreview = false
// whenever there's a new type of attachment can be preview, add it to this list
const canPreviewTypes = [FILE_TYPES.IMAGE, FILE_TYPES.AUDIO]
if (canPreviewTypes.indexOf(fileType) !== -1) {
shouldShowPreview = true
}
const md = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), shouldShowPreview, fileType)
codeEditor.insertAttachmentMd(md)
})
}

function getFileType (type) {
const types = Object.keys(FILE_TYPES)
for (let i = 0; i < types.length; i++) {
const currentTypeName = types[i]
const currentTypeValue = FILE_TYPES[currentTypeName]
if (type.startsWith(currentTypeValue)) {
return currentTypeValue
}
}
return 'unknown'
}

/**
* @description Creates a new file in the storage folder belonging to the current note and inserts the correct markdown code
* @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code
Expand Down
7 changes: 5 additions & 2 deletions tests/dataApi/attachmentManagement.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,14 @@ it('should replace the ":storage" path with the actual storage path when they ha
expect(actual).toEqual(expectedOutput)
})

it('should test that generateAttachmentMarkdown works correct both with previews and without', function () {
it('should test that generateAttachmentMarkdown works correct both with different previews and without', function () {
const fileName = 'fileName'
const path = 'path'
let expected = `![${fileName}](${path})`
let actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, true)
let actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, true, 'image')
expect(actual).toEqual(expected)
expected = `@[${fileName}](${path})`
actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, true, 'audio')
expect(actual).toEqual(expected)
expected = `[${fileName}](${path})`
actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, false)
Expand Down
15 changes: 14 additions & 1 deletion tests/fixtures/markdowns.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ const smartQuotes = 'This is a "QUOTE".'

const breaks = 'This is the first line.\nThis is the second line.'

const audio = `
@[audio.mp3]

Audio must be at start of input or the previous line must be blank.
@[notaudio.mp3]

@[audio](audio.mp3)

[ref]: audio.mp3

@[ref]
`
const abbrevations = `
## abbr

Expand Down Expand Up @@ -115,5 +127,6 @@ export default {
subTexts,
supTexts,
deflists,
shortcuts
shortcuts,
audio
}
5 changes: 5 additions & 0 deletions tests/lib/markdown-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ test('Markdown.render() should render line breaks correctly', t => {
t.snapshot(renderedNonBreaks)
})

test('Markdown.render() should render audio correctly', t => {
const rendered = md.render(markdownFixtures.audio)
t.snapshot(rendered)
})

test('Markdown.render() should renders abbrevations correctly', t => {
const rendered = md.render(markdownFixtures.abbrevations)
t.snapshot(rendered)
Expand Down
8 changes: 8 additions & 0 deletions tests/lib/snapshots/markdown-test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ The actual snapshot is saved in `markdown-test.js.snap`.

Generated by [AVA](https://ava.li).

## Markdown.render() should render audio correctly

> Snapshot 1

`<audio class='audio-player' src='audio.mp3' controls></audio><p data-line="3">Audio must be at start of input or the previous line must be blank.<br />␊
@[notaudio.mp3]</p>␊
<audio class='audio-player' src='audio.mp3' controls></audio><audio class='audio-player' src='audio.mp3' controls></audio>`

## Markdown.render() should render line breaks correctly

> Snapshot 1
Expand Down
Binary file modified tests/lib/snapshots/markdown-test.js.snap
Binary file not shown.