Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show more than first line in note list preview #1647

Merged
merged 4 commits into from
Oct 31, 2019
Merged
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
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
### Fixes

- Rework WordPress.com signin to prevent infinite looping and login failures [#1627](https://github.com/Automattic/simplenote-electron/pull/1627)
- Fixed bug that only shows the first line of text in note list preview [#1647](https://github.com/Automattic/simplenote-electron/pull/1647)
- Update link to release-notes in updater config: CHANGELOG -> RELEASE_NOTES

## [v1.9.1]
Expand Down
96 changes: 46 additions & 50 deletions lib/utils/note-utils.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,57 @@
import removeMarkdown from 'remove-markdown';
import { isFunction } from 'lodash';

/**
* Matches the title and excerpt in a note's content
*
* Both the title and the excerpt are determined as
* content starting with something that isn't
* whitespace and leads up to a newline or line end
*
* @type {RegExp} matches a title and excerpt in note content
*/
const noteTitleAndPreviewRegExp = /\s*(\S[^\n]*)\s*(\S[^\n]*)?/;
export const maxTitleChars = 64;
export const maxPreviewChars = 200;
const maxPreviewLines = 4; // probably need to adjust if we're in the comfy view

const matchUntilLimit = (pattern, source, preview = '', lines = 0) => {
const match = pattern.exec(source);
// must match, must have no more than four lines, must not be longer than N=10 characters
if (!match || lines > maxPreviewLines || preview.length > maxPreviewChars) {
return preview;
}

const [, chunk] = match;
return matchUntilLimit(pattern, source, preview + chunk, lines + 1);
};

/**
* Matches the title and excerpt in a note's content skipping opening # from title
*
* Both the title and the excerpt are determined as
* content starting with something that isn't
* whitespace and leads up to a newline or line end
* Returns a string with markdown stripped
*
* @type {RegExp} matches a title and excerpt in note content skipping opening #'s from title and preview
* @param {String} inputString string for which to remove markdown
* @returns {String} string with markdown removed
*/
const noteTitleAndPreviewMdRegExp = /(?:#{0,6}\s+)?(\S[^\n]*)\s*(?:#{0,6}\s+)?(\S[^\n]*)?/;

export const titleCharacterLimit = 200;
const removeMarkdownWithFix = inputString => {
// Workaround for a bug in `remove-markdown`
// See https://github.com/stiang/remove-markdown/issues/35
return removeMarkdown(inputString.replace(/(\s)\s+/g, '$1'), {
stripListLeaders: false,
});
};

// Ample amount of characters for the 'Expanded' list view
export const previewCharacterLimit = 300;
const getTitle = content => {
const titlePattern = new RegExp(`\s*([^\n]{1,${maxTitleChars}})`, 'g');
const titleMatch = titlePattern.exec(content);
if (!titleMatch) {
return 'New Note…';
}
const [, title] = titleMatch;
return title;
};

// Defaults for notes with empty content
export const defaults = {
title: 'New Note...',
preview: '',
const getPreview = content => {
const previewPattern = new RegExp(
`[^\n]*\n+[ \t]*([^]{0,${maxPreviewChars}})`,
'g'
);
return matchUntilLimit(previewPattern, content);
};

const removeMarkdownFromOutput = isMarkdown
? s => removeMarkdownWithFix(s) || s
: s => s;

/**
* Returns the title and excerpt for a given note
*
Expand All @@ -42,34 +60,12 @@ export const defaults = {
*/
export const noteTitleAndPreview = note => {
const content = (note && note.data && note.data.content) || '';

const match = isMarkdown(note)
? noteTitleAndPreviewMdRegExp.exec(content || '')
: noteTitleAndPreviewRegExp.exec(content || '');

if (!match) {
return defaults;
}

let [, title = defaults.title, preview = defaults.preview] = match;

title = title.slice(0, titleCharacterLimit);
preview = preview.slice(0, previewCharacterLimit);

if (preview && isMarkdown(note)) {
// Workaround for a bug in `remove-markdown`
// See https://github.com/stiang/remove-markdown/issues/35
const previewWithSpacesTrimmed = preview.replace(/(\s)\s+/g, '$1');

preview = removeMarkdown(previewWithSpacesTrimmed, {
stripListLeaders: false,
});
}

const title = removeMarkdownFromOutput(getTitle(content));
const preview = removeMarkdownFromOutput(getPreview(content));
return { title, preview };
};

export function isMarkdown(note) {
function isMarkdown(note) {
return note && note.data && note.data.systemTags.includes('markdown');
}

Expand Down
15 changes: 7 additions & 8 deletions lib/utils/note-utils.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import noteTitleAndPreview, {
defaults,
normalizeForSorting,
previewCharacterLimit,
titleCharacterLimit,
maxTitleChars,
maxPreviewChars,
} from './note-utils';

describe('noteTitleAndPreview', () => {
Expand All @@ -19,7 +18,7 @@ describe('noteTitleAndPreview', () => {

it('should return default values if note content is empty', () => {
const result = noteTitleAndPreview(note);
expect(result).toEqual(defaults);
expect(result).toEqual({ preview: '', title: 'New Note…' });
});

it('should return the title and preview when note is not Markdown', () => {
Expand Down Expand Up @@ -55,13 +54,13 @@ describe('noteTitleAndPreview', () => {

it('should have enough text for an Expanded preview, even if the title is very long', () => {
// Longer than the char limits
const title = 'foo'.repeat(titleCharacterLimit);
const paragraph = 'foo'.repeat(previewCharacterLimit);
const title = 'A really long title'.repeat(100);
const paragraph = 'A really long paragraph'.repeat(100);

note.data.content = title + '\n' + paragraph;
const result = noteTitleAndPreview(note);
expect(result.title).toHaveLength(titleCharacterLimit);
expect(result.preview).toHaveLength(previewCharacterLimit);
expect(result.title).toHaveLength(maxTitleChars);
expect(result.preview).toHaveLength(maxPreviewChars);
});
});

Expand Down