You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-13 22:12:50 +02:00
Merge branch 'master' into clipper_html_mode
This commit is contained in:
4
.github/ISSUE_TEMPLATE.md
vendored
Normal file
4
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
👉 Please follow one of these issue templates:
|
||||
- https://github.com/laurent22/joplin/issues/new/choose
|
||||
|
||||
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.
|
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: "🐛 Bug Report"
|
||||
about: Report a reproducible bug or regression in Joplin.
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please provide a clear and concise description of what the bug is. (In the section Steps To Reproduce.)
|
||||
Include screenshots if needed.
|
||||
Please test using the latest Joplin release to make sure your issue has not already been fixed.
|
||||
-->
|
||||
|
||||
## Environment
|
||||
|
||||
Joplin version:
|
||||
Platform:
|
||||
OS specifcs:
|
||||
<!--
|
||||
Platform can be one of: macOS, Linux, Windows, Android, iOS, terminal (or a combination)
|
||||
OS specifcs: e.g. OS version, Linux distribution, Android/iOS version, ...
|
||||
-->
|
||||
|
||||
## Steps To Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
<!--
|
||||
Issues without reproduction steps are likely to stall.
|
||||
-->
|
||||
|
||||
Describe what you expected to happen:
|
||||
|
||||
|
||||
|
||||
## Logfile
|
||||
|
||||
<!--
|
||||
Please attach a debug log. Issues without a debug log are likely to stall.
|
||||
For information on how to collect a log file: https://joplinapp.org/debugging/
|
||||
-->
|
33
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a feature for Joplin.
|
||||
title: '[Feature request] '
|
||||
labels: 'feature request'
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please search open issues first - many features have already been requested!
|
||||
-->
|
||||
|
||||
## Has it been discussed in the forum? Link to topic.
|
||||
<!--
|
||||
Feature requests should be discussed in the forum first. https://discourse.joplinapp.org
|
||||
Please provide a link to the topic.
|
||||
-->
|
||||
|
||||
|
||||
## Is your feature request related to a problem? Please describe.
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
|
||||
## Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
|
||||
## Describe alternatives you've considered
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
|
||||
## Additional context
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
29
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: "🤔 Questions and Help"
|
||||
about: The issue tracker is not for questions. Please ask questions on https://discourse.joplinapp.org/.
|
||||
title: 'Question: '
|
||||
labels: 'question'
|
||||
|
||||
---
|
||||
|
||||
🚨 The issue tracker is not for questions. 🚨
|
||||
|
||||
As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek.
|
||||
|
||||
## Questions and Help
|
||||
|
||||
Please read the [documentation](https://joplinapp.org/) and [FAQ](https://joplinapp.org/faq/) first.
|
||||
|
||||
### https://discourse.joplinapp.org/
|
||||
|
||||
If you have still questions related to Joplin, please open a topic in the [forum](https://discourse.joplinapp.org/).
|
||||
You can use your GitHub credentials to login to the forum.
|
||||
|
||||
## Links
|
||||
|
||||
- Documentation: https://joplinapp.org
|
||||
- FAQ: https://joplinapp.org/faq/
|
||||
- Forum: https://discourse.joplinapp.org
|
||||
- How to enable end-to-end encryption: https://joplinapp.org/e2ee/
|
||||
- API documentation: https://joplinapp.org/api/
|
||||
- How to enable debug mode: https://joplinapp.org/debugging/
|
25
.github/stale.yml
vendored
Normal file
25
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 90
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- "good first issue"
|
||||
- "essential"
|
||||
- "essential-reviewed"
|
||||
- "help wanted"
|
||||
- "nice to have"
|
||||
- "upstream"
|
||||
- "backlog"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs.
|
||||
You may also label this issue as "backlog" and I will leave it open.
|
||||
Thank you for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.
|
||||
only: issues
|
@@ -1985,7 +1985,7 @@ msgstr ""
|
||||
|
||||
#, javascript-format
|
||||
msgid "Links with protocol \"%s\" are not supported"
|
||||
msgstr ""
|
||||
msgstr "Verweise mit dem Protokoll \"%s\" sind nicht unterstützt"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Unsupported image type: %s"
|
||||
|
@@ -26,11 +26,13 @@ const ResourceService = require('lib/services/ResourceService');
|
||||
const ClipperServer = require('lib/ClipperServer');
|
||||
const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
const { shell } = require('electron');
|
||||
const Menu = bridge().Menu;
|
||||
const MenuItem = bridge().MenuItem;
|
||||
const PluginManager = require('lib/services/PluginManager');
|
||||
const RevisionService = require('lib/services/RevisionService');
|
||||
const MigrationService = require('lib/services/MigrationService');
|
||||
const TemplateUtils = require('lib/TemplateUtils');
|
||||
|
||||
const pluginClasses = [
|
||||
require('./plugins/GotoAnything.min'),
|
||||
@@ -209,7 +211,7 @@ class Application extends BaseApplication {
|
||||
// The bridge runs within the main process, with its own instance of locale.js
|
||||
// so it needs to be set too here.
|
||||
bridge().setLocale(Setting.value('locale'));
|
||||
this.refreshMenu();
|
||||
await this.refreshMenu();
|
||||
}
|
||||
|
||||
if (action.type == 'SETTING_UPDATE_ONE' && action.key == 'showTrayIcon' || action.type == 'SETTING_UPDATE_ALL') {
|
||||
@@ -246,10 +248,10 @@ class Application extends BaseApplication {
|
||||
return result;
|
||||
}
|
||||
|
||||
refreshMenu() {
|
||||
async refreshMenu() {
|
||||
const screen = this.lastMenuScreen_;
|
||||
this.lastMenuScreen_ = null;
|
||||
this.updateMenu(screen);
|
||||
await this.updateMenu(screen);
|
||||
}
|
||||
|
||||
focusElement_(target) {
|
||||
@@ -260,7 +262,7 @@ class Application extends BaseApplication {
|
||||
});
|
||||
}
|
||||
|
||||
updateMenu(screen) {
|
||||
async updateMenu(screen) {
|
||||
if (this.lastMenuScreen_ === screen) return;
|
||||
|
||||
const sortNoteFolderItems = (type) => {
|
||||
@@ -328,6 +330,7 @@ class Application extends BaseApplication {
|
||||
const exportItems = [];
|
||||
const preferencesItems = [];
|
||||
const toolsItemsFirst = [];
|
||||
const templateItems = [];
|
||||
const ioService = new InteropService();
|
||||
const ioModules = ioService.modules();
|
||||
for (let i = 0; i < ioModules.length; i++) {
|
||||
@@ -504,6 +507,57 @@ class Application extends BaseApplication {
|
||||
screens: ['Main'],
|
||||
});
|
||||
|
||||
const templateDirExists = await shim.fsDriver().exists(Setting.value('templateDir'));
|
||||
|
||||
templateItems.push({
|
||||
label: _('Create note from template'),
|
||||
visible: templateDirExists,
|
||||
click: () => {
|
||||
this.dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'selectTemplate',
|
||||
noteType: 'note',
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: _('Create to-do from template'),
|
||||
visible: templateDirExists,
|
||||
click: () => {
|
||||
this.dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'selectTemplate',
|
||||
noteType: 'todo',
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: _('Insert template'),
|
||||
visible: templateDirExists,
|
||||
accelerator: 'CommandOrControl+Alt+I',
|
||||
click: () => {
|
||||
this.dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'selectTemplate',
|
||||
});
|
||||
}
|
||||
}, {
|
||||
label: _('Open template directory'),
|
||||
click: () => {
|
||||
const templateDir = Setting.value('templateDir');
|
||||
if (!templateDirExists) shim.fsDriver().mkdir(templateDir);
|
||||
shell.openItem(templateDir);
|
||||
}
|
||||
}, {
|
||||
label: _('Refresh templates'),
|
||||
click: async () => {
|
||||
const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir'));
|
||||
|
||||
this.store().dispatch({
|
||||
type: 'TEMPLATE_UPDATE_ALL',
|
||||
templates: templates
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const toolsItems = toolsItemsFirst.concat(preferencesItems);
|
||||
|
||||
function _checkForUpdates(ctx) {
|
||||
@@ -563,6 +617,13 @@ class Application extends BaseApplication {
|
||||
shim.isMac() ? noItem : newNotebookItem, {
|
||||
type: 'separator',
|
||||
visible: shim.isMac() ? false : true
|
||||
}, {
|
||||
label: _('Templates'),
|
||||
visible: shim.isMac() ? false : true,
|
||||
submenu: templateItems,
|
||||
}, {
|
||||
type: 'separator',
|
||||
visible: shim.isMac() ? false : true
|
||||
}, {
|
||||
label: _('Import'),
|
||||
visible: shim.isMac() ? false : true,
|
||||
@@ -615,6 +676,11 @@ class Application extends BaseApplication {
|
||||
selector: 'performClose:',
|
||||
}, {
|
||||
type: 'separator',
|
||||
}, {
|
||||
label: _('Templates'),
|
||||
submenu: templateItems,
|
||||
}, {
|
||||
type: 'separator',
|
||||
}, {
|
||||
label: _('Import'),
|
||||
submenu: importItems,
|
||||
@@ -1081,6 +1147,13 @@ class Application extends BaseApplication {
|
||||
css: cssString
|
||||
});
|
||||
|
||||
const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir'));
|
||||
|
||||
this.store().dispatch({
|
||||
type: 'TEMPLATE_UPDATE_ALL',
|
||||
templates: templates
|
||||
});
|
||||
|
||||
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
||||
// but then doesn't install it on exit.
|
||||
if (shim.isWindows() || shim.isMac()) {
|
||||
|
@@ -74,12 +74,13 @@ class MainScreenComponent extends React.Component {
|
||||
async doCommand(command) {
|
||||
if (!command) return;
|
||||
|
||||
const createNewNote = async (title, isTodo) => {
|
||||
const createNewNote = async (template, isTodo) => {
|
||||
const folderId = Setting.value('activeFolderId');
|
||||
if (!folderId) return;
|
||||
|
||||
const newNote = {
|
||||
parent_id: folderId,
|
||||
template: template,
|
||||
is_todo: isTodo ? 1 : 0,
|
||||
};
|
||||
|
||||
@@ -272,6 +273,30 @@ class MainScreenComponent extends React.Component {
|
||||
eventManager.emit('alarmChange', { noteId: note.id });
|
||||
}
|
||||
|
||||
this.setState({ promptOptions: null });
|
||||
}
|
||||
},
|
||||
});
|
||||
} else if (command.name === 'selectTemplate') {
|
||||
this.setState({
|
||||
promptOptions: {
|
||||
label: _('Template file:'),
|
||||
inputType: 'dropdown',
|
||||
value: this.props.templates[0], // Need to start with some value
|
||||
autocomplete: this.props.templates,
|
||||
onClose: async (answer) => {
|
||||
if (answer) {
|
||||
if (command.noteType === 'note' || command.noteType === 'todo') {
|
||||
createNewNote(answer.value, command.noteType === 'todo');
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'insertTemplate',
|
||||
value: answer.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ promptOptions: null });
|
||||
}
|
||||
},
|
||||
@@ -523,6 +548,7 @@ const mapStateToProps = (state) => {
|
||||
selectedNoteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null,
|
||||
plugins: state.plugins,
|
||||
noteDevToolsVisible: state.noteDevToolsVisible,
|
||||
templates: state.templates,
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -40,6 +40,7 @@ const DecryptionWorker = require('lib/services/DecryptionWorker');
|
||||
const ModelCache = require('lib/services/ModelCache');
|
||||
const NoteTextViewer = require('./NoteTextViewer.min');
|
||||
const NoteRevisionViewer = require('./NoteRevisionViewer.min');
|
||||
const TemplateUtils = require('lib/TemplateUtils');
|
||||
|
||||
require('brace/mode/markdown');
|
||||
// https://ace.c9.io/build/kitchen-sink.html
|
||||
@@ -470,14 +471,18 @@ class NoteTextComponent extends React.Component {
|
||||
const stateNoteId = this.state.note ? this.state.note.id : null;
|
||||
let noteId = null;
|
||||
let note = null;
|
||||
let newNote = null;
|
||||
let loadingNewNote = true;
|
||||
let parentFolder = null;
|
||||
let noteTags = [];
|
||||
let scrollPercent = 0;
|
||||
|
||||
if (props.newNote) {
|
||||
note = Object.assign({}, props.newNote);
|
||||
// assign new note and prevent body from being null
|
||||
note = Object.assign({}, props.newNote, {body: ''});
|
||||
this.lastLoadedNoteId_ = null;
|
||||
if (note.template)
|
||||
note.body = TemplateUtils.render(note.template);
|
||||
} else {
|
||||
noteId = props.noteId;
|
||||
|
||||
@@ -1024,6 +1029,8 @@ class NoteTextComponent extends React.Component {
|
||||
fn = this.commandShowLocalSearch;
|
||||
} else if (command.name === 'textCode') {
|
||||
fn = this.commandTextCode;
|
||||
} else if (command.name === 'insertTemplate') {
|
||||
fn = () => { return this.commandTemplate(command.value); };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1361,6 +1368,10 @@ class NoteTextComponent extends React.Component {
|
||||
this.wrapSelectionWithStrings('`', '`');
|
||||
}
|
||||
|
||||
commandTemplate(value) {
|
||||
this.wrapSelectionWithStrings(TemplateUtils.render(value));
|
||||
}
|
||||
|
||||
addListItem(string1, string2 = '', defaultText = '') {
|
||||
const currentLine = this.selectionRangeCurrentLine();
|
||||
let newLine = '\n'
|
||||
@@ -1936,6 +1947,7 @@ const mapStateToProps = (state) => {
|
||||
customCss: state.customCss,
|
||||
lastEditorScrollPercents: state.lastEditorScrollPercents,
|
||||
historyNotes: state.historyNotes,
|
||||
templates: state.templates,
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -6,6 +6,7 @@ const { themeStyle } = require('../theme.js');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const Datetime = require('react-datetime');
|
||||
const CreatableSelect = require('react-select/lib/Creatable').default;
|
||||
const Select = require('react-select').default;
|
||||
const makeAnimated = require('react-select/lib/animated').default;
|
||||
|
||||
class PromptDialog extends React.Component {
|
||||
@@ -101,7 +102,7 @@ class PromptDialog extends React.Component {
|
||||
borderColor: theme.dividerColor,
|
||||
};
|
||||
|
||||
this.styles_.tagList = {
|
||||
this.styles_.select = {
|
||||
control: (provided) => (Object.assign(provided, {
|
||||
minWidth: width * 0.2,
|
||||
maxWidth: width * 0.5,
|
||||
@@ -115,6 +116,10 @@ class PromptDialog extends React.Component {
|
||||
fontFamily: theme.fontFamily,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
})),
|
||||
option: (provided) => (Object.assign(provided, {
|
||||
color: theme.color,
|
||||
fontFamily: theme.fontFamily,
|
||||
})),
|
||||
multiValueLabel: (provided) => (Object.assign(provided, {
|
||||
fontFamily: theme.fontFamily,
|
||||
})),
|
||||
@@ -123,14 +128,22 @@ class PromptDialog extends React.Component {
|
||||
})),
|
||||
};
|
||||
|
||||
this.styles_.tagListTheme = (tagTheme) => (Object.assign(tagTheme, {
|
||||
this.styles_.selectTheme = (tagTheme) => (Object.assign(tagTheme, {
|
||||
borderRadius: 2,
|
||||
colors: Object.assign(tagTheme.colors, {
|
||||
primary: theme.raisedBackgroundColor,
|
||||
primary25: theme.raisedBackgroundColor,
|
||||
neutral0: theme.backgroundColor,
|
||||
neutral5: theme.backgroundColor,
|
||||
neutral10: theme.raisedBackgroundColor,
|
||||
neutral20: theme.raisedBackgroundColor,
|
||||
neutral30: theme.raisedBackgroundColor,
|
||||
neutral40: theme.color,
|
||||
neutral50: theme.color,
|
||||
neutral60: theme.color,
|
||||
neutral70: theme.color,
|
||||
neutral80: theme.color,
|
||||
neutral90: theme.color,
|
||||
danger: theme.backgroundColor,
|
||||
dangerLight: theme.colorError2,
|
||||
}),
|
||||
@@ -179,14 +192,19 @@ class PromptDialog extends React.Component {
|
||||
this.setState({ answer: momentObject });
|
||||
}
|
||||
|
||||
const onTagsChange = (newTags) => {
|
||||
this.setState({ answer: newTags });
|
||||
const onSelectChange = (newValue) => {
|
||||
this.setState({ answer: newValue });
|
||||
this.focusInput_ = true;
|
||||
}
|
||||
|
||||
const onKeyDown = (event) => {
|
||||
if (event.key === 'Enter' && this.props.inputType !== 'tags') {
|
||||
if (event.key === 'Enter') {
|
||||
if (this.props.inputType !== 'tags' && this.props.inputType !== 'dropdown') {
|
||||
onClose(true);
|
||||
} else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) {
|
||||
// The menu will be open if the user is selecting a new item
|
||||
onClose(true);
|
||||
}
|
||||
} else if (event.key === 'Escape') {
|
||||
onClose(false);
|
||||
}
|
||||
@@ -206,8 +224,8 @@ class PromptDialog extends React.Component {
|
||||
/>
|
||||
} else if (this.props.inputType === 'tags') {
|
||||
inputComp = <CreatableSelect
|
||||
styles={styles.tagList}
|
||||
theme={styles.tagListTheme}
|
||||
styles={styles.select}
|
||||
theme={styles.selectTheme}
|
||||
ref={this.answerInput_}
|
||||
value={this.state.answer}
|
||||
placeholder=""
|
||||
@@ -216,7 +234,20 @@ class PromptDialog extends React.Component {
|
||||
isClearable={false}
|
||||
backspaceRemovesValue={true}
|
||||
options={this.props.autocomplete}
|
||||
onChange={onTagsChange}
|
||||
onChange={onSelectChange}
|
||||
onKeyDown={(event) => onKeyDown(event)}
|
||||
/>
|
||||
} else if (this.props.inputType === 'dropdown') {
|
||||
inputComp = <Select
|
||||
styles={styles.select}
|
||||
theme={styles.selectTheme}
|
||||
ref={this.answerInput_}
|
||||
components={makeAnimated()}
|
||||
value={this.props.answer}
|
||||
defaultValue={this.props.defaultValue}
|
||||
isClearable={false}
|
||||
options={this.props.autocomplete}
|
||||
onChange={onSelectChange}
|
||||
onKeyDown={(event) => onKeyDown(event)}
|
||||
/>
|
||||
} else {
|
||||
|
5
ElectronClient/app/package-lock.json
generated
5
ElectronClient/app/package-lock.json
generated
@@ -4519,6 +4519,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"mustache": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mustache/-/mustache-3.0.1.tgz",
|
||||
"integrity": "sha512-jFI/4UVRsRYdUbuDTKT7KzfOp7FiD5WzYmmwNwXyUVypC0xjoTL78Fqc0jHUPIvvGD+6DQSPHIt1NE7D1ArsqA=="
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
|
||||
|
@@ -111,21 +111,22 @@
|
||||
"mark.js": "^8.11.1",
|
||||
"markdown-it": "^8.4.1",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-anchor": "^5.0.2",
|
||||
"markdown-it-anchor": "^5.2.4",
|
||||
"markdown-it-deflist": "^2.0.3",
|
||||
"markdown-it-emoji": "^1.4.0",
|
||||
"markdown-it-footnote": "^3.0.1",
|
||||
"markdown-it-footnote": "^3.0.2",
|
||||
"markdown-it-ins": "^2.0.0",
|
||||
"markdown-it-katex": "^2.0.3",
|
||||
"markdown-it-mark": "^2.0.0",
|
||||
"markdown-it-multimd-table": "^3.2.0",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.0.0",
|
||||
"markdown-it-toc-done-right": "^4.0.2",
|
||||
"md5": "^2.2.1",
|
||||
"mime": "^2.3.1",
|
||||
"moment": "^2.22.2",
|
||||
"multiparty": "^4.2.1",
|
||||
"mustache": "^3.0.1",
|
||||
"node-fetch": "^1.7.3",
|
||||
"node-notifier": "^5.2.1",
|
||||
"promise": "^8.0.1",
|
||||
|
@@ -47,6 +47,18 @@ table td, table th {
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(100, 100, 100, 0.7);
|
||||
}
|
||||
|
||||
.fade_out {
|
||||
-webkit-transition: 0.15s;
|
||||
transition: 0.15s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.fade_in {
|
||||
-webkit-transition: 0.3s;
|
||||
transition: 0.3s;
|
||||
opacity: 1;
|
||||
}
|
||||
/* By default, the Ice Editor displays invalid characters, such as non-breaking spaces
|
||||
as red boxes, but since those are actually valid characters and common in imported
|
||||
Evernote data, we hide them here. */
|
||||
|
@@ -71,7 +71,7 @@ if [[ ! -e ~/.joplin/VERSION ]] || [[ $(< ~/.joplin/VERSION) != "$version" ]]; t
|
||||
|
||||
# Create icon for Gnome
|
||||
echo 'Create Desktop icon.'
|
||||
if [[ $desktop =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.* ]]
|
||||
if [[ $desktop =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*X-Cinnamon.* ]]
|
||||
then
|
||||
: "${TMPDIR:=/tmp}"
|
||||
# This command extracts to squashfs-root by default and can't be changed...
|
||||
|
48
README.md
48
README.md
@@ -28,7 +28,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/
|
||||
|
||||
Operating System | Download | Alt. Download
|
||||
-----------------|----------|----------------
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplinapp.org/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.279/joplin-v1.0.279.apk)
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://joplinapp.org/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.281/joplin-v1.0.281.apk)
|
||||
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://joplinapp.org/images/BadgeIOS.png'/></a> | -
|
||||
|
||||
## Terminal application
|
||||
@@ -316,6 +316,25 @@ It is generally recommended to enter the notes as Markdown as it makes the notes
|
||||
|
||||
Rendered markdown can be customized by placing a userstyle file in the profile directory `~/.config/joplin-desktop/userstyle.css` (This path might be different on your device - check at the top of the Config screen for the exact path). This file supports standard CSS syntax. Joplin ***must*** be restarted for the new css to be applied, please ensure that Joplin is not closing to the tray, but is actually exiting. Note that this file is used only when display the notes, **not when printing or exporting to PDF**. This is because printing has a lot more restrictions (for example, printing white text over a black background is usually not wanted), so special rules are applied to make it look good when printing, and a userstyle.css would interfer with that.
|
||||
|
||||
## New Note Templates
|
||||
|
||||
Templates can be used for new notes by creating a templates folder in `~/.config/joplin-desktop/` and placing markdown template files into it. For example creating the file `hours.md` in the directory `~/.config/joplin-desktop/templates/` with the contents:
|
||||
|
||||
```markdown
|
||||
Date: {{date}}
|
||||
Hours:
|
||||
Details:
|
||||
```
|
||||
|
||||
When creating a new note you will now be prompted to insert a template that contains the above text (and {{date}} replaced with today's date). Templates can also be inserted from the menu (File->Templates).
|
||||
|
||||
The currently supported template variables are:
|
||||
| Variable | Description | Example |
|
||||
| {{date}} | Today's date formatted based on the settings format | 2019-01-01 |
|
||||
| {{time}} | Current time formatted based on the settings format | 13:00 |
|
||||
| {{datetime}} | Current date and time formatted based on the settings format | 01/01/19 1:00 PM |
|
||||
| {{#custom_datetime}} | Current date and/or time formatted based on a supplied string (using [moment.js](https://momentjs.com/) formatting) | {{#custom_datetime}}M d{{/custom_datetime}} |
|
||||
|
||||
# Searching
|
||||
|
||||
Joplin implements the SQLite Full Text Search (FTS4) extension. It means the content of all the notes is indexed in real time and search queries return results very fast. Both [Simple FTS Queries](https://www.sqlite.org/fts3.html#simple_fts_queries) and [Full-Text Index Queries](https://www.sqlite.org/fts3.html#full_text_index_queries) are supported. See below for the list of supported queries:
|
||||
@@ -401,6 +420,33 @@ Current translations:
|
||||
 | 한국말 | [ko](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ko.po) | | 87%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Contributors
|
||||
|
||||
<!-- CONTRIBUTORS-TABLE-AUTO-GENERATED -->
|
||||
| | | | | |
|
||||
| :---: | :---: | :---: | :---: | :---: |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/1285584?v=4"/></br>[laurent22](https://api.github.com/users/laurent22) | <img width="50" src="https://avatars3.githubusercontent.com/u/223439?v=4"/></br>[tessus](https://api.github.com/users/tessus) | <img width="50" src="https://avatars3.githubusercontent.com/u/2179547?v=4"/></br>[CalebJohn](https://api.github.com/users/CalebJohn) | <img width="50" src="https://avatars3.githubusercontent.com/u/4553672?v=4"/></br>[tanrax](https://api.github.com/users/tanrax) | <img width="50" src="https://avatars0.githubusercontent.com/u/8701534?v=4"/></br>[rtmkrlv](https://api.github.com/users/rtmkrlv) |
|
||||
| <img width="50" src="https://avatars3.githubusercontent.com/u/10997189?v=4"/></br>[fmrtn](https://api.github.com/users/fmrtn) | <img width="50" src="https://avatars3.githubusercontent.com/u/16101778?v=4"/></br>[gabcoh](https://api.github.com/users/gabcoh) | <img width="50" src="https://avatars2.githubusercontent.com/u/1685517?v=4"/></br>[Abijeet](https://api.github.com/users/Abijeet) | <img width="50" src="https://avatars2.githubusercontent.com/u/6557454?v=4"/></br>[innocuo](https://api.github.com/users/innocuo) | <img width="50" src="https://avatars3.githubusercontent.com/u/10927304?v=4"/></br>[matsest](https://api.github.com/users/matsest) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/5365582?v=4"/></br>[marcosvega91](https://api.github.com/users/marcosvega91) | <img width="50" src="https://avatars3.githubusercontent.com/u/37639389?v=4"/></br>[petrz12](https://api.github.com/users/petrz12) | <img width="50" src="https://avatars3.githubusercontent.com/u/208212?v=4"/></br>[foxmask](https://api.github.com/users/foxmask) | <img width="50" src="https://avatars1.githubusercontent.com/u/4237724?v=4"/></br>[alexdevero](https://api.github.com/users/alexdevero) | <img width="50" src="https://avatars0.githubusercontent.com/u/3194829?v=4"/></br>[moltenform](https://api.github.com/users/moltenform) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/5199995?v=4"/></br>[zuphilip](https://api.github.com/users/zuphilip) | <img width="50" src="https://avatars0.githubusercontent.com/u/6319051?v=4"/></br>[abonte](https://api.github.com/users/abonte) | <img width="50" src="https://avatars2.githubusercontent.com/u/31567272?v=4"/></br>[0ndrey](https://api.github.com/users/0ndrey) | <img width="50" src="https://avatars1.githubusercontent.com/u/6734573?v=4"/></br>[stweil](https://api.github.com/users/stweil) | <img width="50" src="https://avatars3.githubusercontent.com/u/32770029?v=4"/></br>[bradmcl](https://api.github.com/users/bradmcl) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/226708?v=4"/></br>[RaphaelKimmig](https://api.github.com/users/RaphaelKimmig) | <img width="50" src="https://avatars0.githubusercontent.com/u/17768566?v=4"/></br>[RenatoXSR](https://api.github.com/users/RenatoXSR) | <img width="50" src="https://avatars1.githubusercontent.com/u/36303913?v=4"/></br>[sensor-freak](https://api.github.com/users/sensor-freak) | <img width="50" src="https://avatars2.githubusercontent.com/u/4245227?v=4"/></br>[zblesk](https://api.github.com/users/zblesk) | <img width="50" src="https://avatars2.githubusercontent.com/u/560571?v=4"/></br>[chrisb86](https://api.github.com/users/chrisb86) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/4168339?v=4"/></br>[solariz](https://api.github.com/users/solariz) | <img width="50" src="https://avatars0.githubusercontent.com/u/390889?v=4"/></br>[mmahmoudian](https://api.github.com/users/mmahmoudian) | <img width="50" src="https://avatars1.githubusercontent.com/u/25288?v=4"/></br>[maicki](https://api.github.com/users/maicki) | <img width="50" src="https://avatars3.githubusercontent.com/u/2136373?v=4"/></br>[mjjzf](https://api.github.com/users/mjjzf) | <img width="50" src="https://avatars0.githubusercontent.com/u/2486806?v=4"/></br>[sebastienjust](https://api.github.com/users/sebastienjust) |
|
||||
| <img width="50" src="https://avatars1.githubusercontent.com/u/4079047?v=4"/></br>[Zorbeyd](https://api.github.com/users/Zorbeyd) | <img width="50" src="https://avatars0.githubusercontent.com/u/35413451?v=4"/></br>[chenlhlinux](https://api.github.com/users/chenlhlinux) | <img width="50" src="https://avatars0.githubusercontent.com/u/17399340?v=4"/></br>[pf-siedler](https://api.github.com/users/pf-siedler) | <img width="50" src="https://avatars1.githubusercontent.com/u/17232523?v=4"/></br>[ruuti](https://api.github.com/users/ruuti) | <img width="50" src="https://avatars2.githubusercontent.com/u/23638148?v=4"/></br>[s1nceri7y](https://api.github.com/users/s1nceri7y) |
|
||||
| <img width="50" src="https://avatars1.githubusercontent.com/u/22592201?v=4"/></br>[tfinnberg](https://api.github.com/users/tfinnberg) | <img width="50" src="https://avatars1.githubusercontent.com/u/7471938?v=4"/></br>[ShuiHuo](https://api.github.com/users/ShuiHuo) | <img width="50" src="https://avatars2.githubusercontent.com/u/11596277?v=4"/></br>[ikunya](https://api.github.com/users/ikunya) | <img width="50" src="https://avatars1.githubusercontent.com/u/498326?v=4"/></br>[Shaxine](https://api.github.com/users/Shaxine) | <img width="50" src="https://avatars2.githubusercontent.com/u/7034200?v=4"/></br>[bimlas](https://api.github.com/users/bimlas) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/105843?v=4"/></br>[chaifeng](https://api.github.com/users/chaifeng) | <img width="50" src="https://avatars2.githubusercontent.com/u/549349?v=4"/></br>[charles-e](https://api.github.com/users/charles-e) | <img width="50" src="https://avatars3.githubusercontent.com/u/1686759?v=4"/></br>[chrmoritz](https://api.github.com/users/chrmoritz) | <img width="50" src="https://avatars0.githubusercontent.com/u/5131923?v=4"/></br>[donbowman](https://api.github.com/users/donbowman) | <img width="50" src="https://avatars2.githubusercontent.com/u/47756?v=4"/></br>[dflock](https://api.github.com/users/dflock) |
|
||||
| <img width="50" src="https://avatars3.githubusercontent.com/u/1962738?v=4"/></br>[einverne](https://api.github.com/users/einverne) | <img width="50" src="https://avatars0.githubusercontent.com/u/628474?v=4"/></br>[Atalanttore](https://api.github.com/users/Atalanttore) | <img width="50" src="https://avatars1.githubusercontent.com/u/16492558?v=4"/></br>[eodeluga](https://api.github.com/users/eodeluga) | <img width="50" src="https://avatars2.githubusercontent.com/u/1714374?v=4"/></br>[FleischKarussel](https://api.github.com/users/FleischKarussel) | <img width="50" src="https://avatars0.githubusercontent.com/u/6190183?v=4"/></br>[gmag11](https://api.github.com/users/gmag11) |
|
||||
| <img width="50" src="https://avatars2.githubusercontent.com/u/2257024?v=4"/></br>[gusbemacbe](https://api.github.com/users/gusbemacbe) | <img width="50" src="https://avatars0.githubusercontent.com/u/18524580?v=4"/></br>[Fvbor](https://api.github.com/users/Fvbor) | <img width="50" src="https://avatars3.githubusercontent.com/u/3379379?v=4"/></br>[sczhg](https://api.github.com/users/sczhg) | <img width="50" src="https://avatars1.githubusercontent.com/u/1716229?v=4"/></br>[Vistaus](https://api.github.com/users/Vistaus) | <img width="50" src="https://avatars3.githubusercontent.com/u/11466782?v=4"/></br>[jacobherrington](https://api.github.com/users/jacobherrington) |
|
||||
| <img width="50" src="https://avatars1.githubusercontent.com/u/29855366?v=4"/></br>[jcgerhard](https://api.github.com/users/jcgerhard) | <img width="50" src="https://avatars1.githubusercontent.com/u/4995433?v=4"/></br>[jaredcrowe](https://api.github.com/users/jaredcrowe) | <img width="50" src="https://avatars2.githubusercontent.com/u/339645?v=4"/></br>[jmontane](https://api.github.com/users/jmontane) | <img width="50" src="https://avatars0.githubusercontent.com/u/163555?v=4"/></br>[JoelRSimpson](https://api.github.com/users/JoelRSimpson) | <img width="50" src="https://avatars1.githubusercontent.com/u/23194385?v=4"/></br>[jony0008](https://api.github.com/users/jony0008) |
|
||||
| <img width="50" src="https://avatars1.githubusercontent.com/u/6048003?v=4"/></br>[joybinchen](https://api.github.com/users/joybinchen) | <img width="50" src="https://avatars1.githubusercontent.com/u/1560189?v=4"/></br>[y-usuzumi](https://api.github.com/users/y-usuzumi) | <img width="50" src="https://avatars0.githubusercontent.com/u/1660460?v=4"/></br>[xuhcc](https://api.github.com/users/xuhcc) | <img width="50" src="https://avatars3.githubusercontent.com/u/7824233?v=4"/></br>[kklas](https://api.github.com/users/kklas) | <img width="50" src="https://avatars2.githubusercontent.com/u/2599210?v=4"/></br>[lboullo0](https://api.github.com/users/lboullo0) |
|
||||
| <img width="50" src="https://avatars1.githubusercontent.com/u/1562062?v=4"/></br>[dbinary](https://api.github.com/users/dbinary) | <img width="50" src="https://avatars3.githubusercontent.com/u/5699725?v=4"/></br>[mvonmaltitz](https://api.github.com/users/mvonmaltitz) | <img width="50" src="https://avatars3.githubusercontent.com/u/5788516?v=4"/></br>[Marmo](https://api.github.com/users/Marmo) | <img width="50" src="https://avatars2.githubusercontent.com/u/12831489?v=4"/></br>[mgroth0](https://api.github.com/users/mgroth0) | <img width="50" src="https://avatars0.githubusercontent.com/u/51273874?v=4"/></br>[MichipX](https://api.github.com/users/MichipX) |
|
||||
| <img width="50" src="https://avatars3.githubusercontent.com/u/9076687?v=4"/></br>[NJannasch](https://api.github.com/users/NJannasch) | <img width="50" src="https://avatars2.githubusercontent.com/u/12369770?v=4"/></br>[Ouvill](https://api.github.com/users/Ouvill) | <img width="50" src="https://avatars3.githubusercontent.com/u/43815417?v=4"/></br>[shorty2380](https://api.github.com/users/shorty2380) | <img width="50" src="https://avatars3.githubusercontent.com/u/6306608?v=4"/></br>[Diadlo](https://api.github.com/users/Diadlo) | <img width="50" src="https://avatars0.githubusercontent.com/u/8766773?v=4"/></br>[Cogitri](https://api.github.com/users/Cogitri) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/559346?v=4"/></br>[metbril](https://api.github.com/users/metbril) | <img width="50" src="https://avatars1.githubusercontent.com/u/744655?v=4"/></br>[ruzaq](https://api.github.com/users/ruzaq) | <img width="50" src="https://avatars2.githubusercontent.com/u/505011?v=4"/></br>[kcrt](https://api.github.com/users/kcrt) | <img width="50" src="https://avatars1.githubusercontent.com/u/538584?v=4"/></br>[xissy](https://api.github.com/users/xissy) | <img width="50" src="https://avatars3.githubusercontent.com/u/466122?v=4"/></br>[Tekki](https://api.github.com/users/Tekki) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/8731922?v=4"/></br>[tbroadley](https://api.github.com/users/tbroadley) | <img width="50" src="https://avatars1.githubusercontent.com/u/114300?v=4"/></br>[Kriechi](https://api.github.com/users/Kriechi) | <img width="50" src="https://avatars0.githubusercontent.com/u/3457339?v=4"/></br>[tkilaker](https://api.github.com/users/tkilaker) | <img width="50" src="https://avatars1.githubusercontent.com/u/4201229?v=4"/></br>[tcyrus](https://api.github.com/users/tcyrus) | <img width="50" src="https://avatars2.githubusercontent.com/u/834914?v=4"/></br>[tobias-grasse](https://api.github.com/users/tobias-grasse) |
|
||||
| <img width="50" src="https://avatars3.githubusercontent.com/u/6691273?v=4"/></br>[strobeltobias](https://api.github.com/users/strobeltobias) | <img width="50" src="https://avatars2.githubusercontent.com/u/11031696?v=4"/></br>[ymitsos](https://api.github.com/users/ymitsos) | <img width="50" src="https://avatars3.githubusercontent.com/u/28493662?v=4"/></br>[cdorin93](https://api.github.com/users/cdorin93) | <img width="50" src="https://avatars3.githubusercontent.com/u/30935096?v=4"/></br>[cybertramp](https://api.github.com/users/cybertramp) | <img width="50" src="https://avatars3.githubusercontent.com/u/9694906?v=4"/></br>[delta-emil](https://api.github.com/users/delta-emil) |
|
||||
| <img width="50" src="https://avatars0.githubusercontent.com/u/926263?v=4"/></br>[doc75](https://api.github.com/users/doc75) | <img width="50" src="https://avatars2.githubusercontent.com/u/2903013?v=4"/></br>[ebayer](https://api.github.com/users/ebayer) | <img width="50" src="https://avatars0.githubusercontent.com/u/14201321?v=4"/></br>[rasperepodvipodvert](https://api.github.com/users/rasperepodvipodvert) | <img width="50" src="https://avatars1.githubusercontent.com/u/11388094?v=4"/></br>[hydrandt](https://api.github.com/users/hydrandt) | <img width="50" src="https://avatars1.githubusercontent.com/u/42961947?v=4"/></br>[pensierocrea](https://api.github.com/users/pensierocrea) |
|
||||
| <img width="50" src="https://avatars3.githubusercontent.com/u/10206967?v=4"/></br>[rhtenhove](https://api.github.com/users/rhtenhove) | <img width="50" src="https://avatars3.githubusercontent.com/u/14062932?v=4"/></br>[simonsan](https://api.github.com/users/simonsan) | <img width="50" src="https://avatars0.githubusercontent.com/u/10956653?v=4"/></br>[tcassaert](https://api.github.com/users/tcassaert) | <img width="50" src="https://avatars0.githubusercontent.com/u/2216902?v=4"/></br>[xcffl](https://api.github.com/users/xcffl) | |
|
||||
<!-- CONTRIBUTORS-TABLE-AUTO-GENERATED -->
|
||||
|
||||
# Known bugs
|
||||
|
||||
- Resources larger than 10 MB are not currently supported on mobile. They will crash the application so it is recommended not to attach such resources at the moment. The issue is being looked at.
|
||||
|
@@ -94,8 +94,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097515
|
||||
versionName "1.0.279"
|
||||
versionCode 2097517
|
||||
versionName "1.0.281"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
@@ -546,6 +546,7 @@ class BaseApplication {
|
||||
|
||||
Setting.setConstant('env', initArgs.env);
|
||||
Setting.setConstant('profileDir', profileDir);
|
||||
Setting.setConstant('templateDir', profileDir + '/templates');
|
||||
Setting.setConstant('resourceDirName', resourceDirName);
|
||||
Setting.setConstant('resourceDir', resourceDir);
|
||||
Setting.setConstant('tempDir', tempDir);
|
||||
|
59
ReactNativeClient/lib/TemplateUtils.js
Normal file
59
ReactNativeClient/lib/TemplateUtils.js
Normal file
@@ -0,0 +1,59 @@
|
||||
const fs = require('fs-extra');
|
||||
const { shim } = require('lib/shim.js');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const Mustache = require('mustache');
|
||||
|
||||
const TemplateUtils = {};
|
||||
|
||||
// new template variables can be added here
|
||||
// If there are too many, this should be moved to a new file
|
||||
const view = {
|
||||
date: time.formatMsToLocal(new Date().getTime(), time.dateFormat()),
|
||||
time: time.formatMsToLocal(new Date().getTime(), time.timeFormat()),
|
||||
datetime: time.formatMsToLocal(new Date().getTime()),
|
||||
custom_datetime: () => { return (text, render) => {
|
||||
return render(time.formatMsToLocal(new Date().getTime(), text));
|
||||
}},
|
||||
}
|
||||
|
||||
// Mustache escapes strings (including /) with the html code by default
|
||||
// This isn't useful for markdown so it's disabled
|
||||
Mustache.escape = (text) => { return text; }
|
||||
|
||||
TemplateUtils.render = function(input) {
|
||||
return Mustache.render(input, view);
|
||||
}
|
||||
|
||||
TemplateUtils.loadTemplates = async function(filePath) {
|
||||
let templates = [];
|
||||
let files = [];
|
||||
|
||||
if (await shim.fsDriver().exists(filePath)) {
|
||||
try {
|
||||
files = await shim.fsDriver().readDirStats(filePath);
|
||||
} catch (error) {
|
||||
let msg = error.message ? error.message : '';
|
||||
msg = 'Could not read template names from ' + filePath + '\n' + msg;
|
||||
error.message = msg;
|
||||
throw error;
|
||||
}
|
||||
|
||||
files.forEach(async (file) => {
|
||||
if (file.path.endsWith('.md')) {
|
||||
try {
|
||||
let fileString = await shim.fsDriver().readFile(filePath + '/' + file.path, 'utf-8');
|
||||
templates.push({label: file.path, value: fileString});
|
||||
} catch (error) {
|
||||
let msg = error.message ? error.message : '';
|
||||
msg = 'Could not load template ' + file.path + '\n' + msg;
|
||||
error.message = msg;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
module.exports = TemplateUtils;
|
@@ -613,8 +613,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
const output = [];
|
||||
|
||||
const createdDateString = time.unixMsToLocalDateTime(note.user_created_time);
|
||||
const updatedDateString = time.unixMsToLocalDateTime(note.user_updated_time);
|
||||
const createdDateString = time.formatMsToLocal(note.user_created_time);
|
||||
const updatedDateString = time.formatMsToLocal(note.user_updated_time);
|
||||
|
||||
output.push({ title: _('Created: %s', createdDateString) });
|
||||
output.push({ title: _('Updated: %s', updatedDateString) });
|
||||
|
@@ -648,6 +648,7 @@ Setting.constants_ = {
|
||||
resourceDirName: '',
|
||||
resourceDir: '',
|
||||
profileDir: '',
|
||||
templateDir: '',
|
||||
tempDir: '',
|
||||
openDevTools: false,
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ const defaultState = {
|
||||
hasDisabledSyncItems: false,
|
||||
newNote: null,
|
||||
customCss: '',
|
||||
templates: [],
|
||||
collapsedFolderIds: [],
|
||||
clipperServer: {
|
||||
startState: 'idle',
|
||||
@@ -714,6 +715,12 @@ const reducer = (state = defaultState, action) => {
|
||||
newState.customCss = action.css;
|
||||
break;
|
||||
|
||||
case 'TEMPLATE_UPDATE_ALL':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.templates = action.templates;
|
||||
break;
|
||||
|
||||
case 'SET_NOTE_TAGS':
|
||||
newState = Object.assign({}, state);
|
||||
newState.selectedNoteTags = action.items;
|
||||
|
@@ -23,17 +23,17 @@
|
||||
"katex": "^0.10.0",
|
||||
"markdown-it": "^8.4.0",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-anchor": "^5.0.2",
|
||||
"markdown-it-anchor": "^5.2.4",
|
||||
"markdown-it-deflist": "^2.0.3",
|
||||
"markdown-it-emoji": "^1.4.0",
|
||||
"markdown-it-footnote": "^3.0.1",
|
||||
"markdown-it-footnote": "^3.0.2",
|
||||
"markdown-it-ins": "^2.0.0",
|
||||
"markdown-it-katex": "^2.0.3",
|
||||
"markdown-it-mark": "^2.0.0",
|
||||
"markdown-it-multimd-table": "^3.2.0",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.0.0",
|
||||
"markdown-it-toc-done-right": "^4.0.2",
|
||||
"md5": "^2.2.1",
|
||||
"moment": "^2.18.1",
|
||||
"prop-types": "^15.6.0",
|
||||
|
@@ -22,7 +22,7 @@ const cliLocalesDir = cliDir + '/locales';
|
||||
const rnDir = rootDir + '/ReactNativeClient';
|
||||
const electronDir = rootDir + '/ElectronClient/app';
|
||||
|
||||
const { execCommand, isMac } = require('./tool-utils.js');
|
||||
const { execCommand, isMac, insertContentIntoFile } = require('./tool-utils.js');
|
||||
const { countryDisplayName, countryCodeOnly } = require('lib/locale.js');
|
||||
|
||||
function parsePoFile(filePath) {
|
||||
@@ -203,16 +203,12 @@ function translationStatusToMdTable(status) {
|
||||
}
|
||||
|
||||
async function updateReadmeWithStats(stats) {
|
||||
const mdTableMarkerOpen = '<!-- LOCALE-TABLE-AUTO-GENERATED -->\n';
|
||||
const mdTableMarkerClose = '\n<!-- LOCALE-TABLE-AUTO-GENERATED -->';
|
||||
let mdTable = translationStatusToMdTable(stats);
|
||||
mdTable = mdTableMarkerOpen + mdTable + mdTableMarkerClose;
|
||||
|
||||
let content = await fs.readFile(rootDir + '/README.md', 'utf-8');
|
||||
// [^]* matches any character including new lines
|
||||
const regex = new RegExp(mdTableMarkerOpen + '[^]*?' + mdTableMarkerClose);
|
||||
content = content.replace(regex, mdTable);
|
||||
await fs.writeFile(rootDir + '/README.md', content);
|
||||
await insertContentIntoFile(
|
||||
rootDir + '/README.md',
|
||||
'<!-- LOCALE-TABLE-AUTO-GENERATED -->\n',
|
||||
'\n<!-- LOCALE-TABLE-AUTO-GENERATED -->',
|
||||
translationStatusToMdTable(stats)
|
||||
);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
92
Tools/package-lock.json
generated
92
Tools/package-lock.json
generated
@@ -75,6 +75,15 @@
|
||||
"hoek": "4.x.x"
|
||||
}
|
||||
},
|
||||
"camel-case": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
|
||||
"integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
|
||||
"requires": {
|
||||
"no-case": "^2.2.0",
|
||||
"upper-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
|
||||
@@ -85,6 +94,14 @@
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
|
||||
"integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
|
||||
"requires": {
|
||||
"source-map": "~0.6.0"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
|
||||
@@ -113,6 +130,11 @@
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
@@ -323,11 +345,30 @@
|
||||
"sntp": "2.x.x"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"hoek": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
|
||||
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
|
||||
},
|
||||
"html-minifier": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
|
||||
"integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
|
||||
"requires": {
|
||||
"camel-case": "^3.0.0",
|
||||
"clean-css": "^4.2.1",
|
||||
"commander": "^2.19.0",
|
||||
"he": "^1.2.0",
|
||||
"param-case": "^2.1.1",
|
||||
"relateurl": "^0.2.7",
|
||||
"uglify-js": "^3.5.1"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
@@ -438,6 +479,11 @@
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lower-case": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
|
||||
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
|
||||
},
|
||||
"map-age-cleaner": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
||||
@@ -501,6 +547,14 @@
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
|
||||
},
|
||||
"no-case": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
|
||||
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
|
||||
"requires": {
|
||||
"lower-case": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
@@ -558,7 +612,7 @@
|
||||
},
|
||||
"p-is-promise": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
|
||||
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4="
|
||||
},
|
||||
"p-limit": {
|
||||
@@ -582,6 +636,14 @@
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
|
||||
"integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ=="
|
||||
},
|
||||
"param-case": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
|
||||
"integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
|
||||
"requires": {
|
||||
"no-case": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
@@ -621,6 +683,11 @@
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
|
||||
},
|
||||
"relateurl": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.85.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz",
|
||||
@@ -701,6 +768,11 @@
|
||||
"hoek": "4.x.x"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
@@ -780,11 +852,25 @@
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
|
||||
"integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg=="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
|
||||
"integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
|
||||
"requires": {
|
||||
"commander": "~2.20.0",
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
|
||||
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
|
||||
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
|
||||
},
|
||||
"uri-template": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-template/-/uri-template-1.0.1.tgz",
|
||||
@@ -823,7 +909,7 @@
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||
"requires": {
|
||||
"string-width": "^1.0.1",
|
||||
@@ -855,7 +941,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
|
@@ -12,6 +12,7 @@
|
||||
"app-module-path": "^2.2.0",
|
||||
"fs-extra": "^4.0.3",
|
||||
"gettext-parser": "^1.3.0",
|
||||
"html-minifier": "^4.0.0",
|
||||
"markdown-it": "^8.4.1",
|
||||
"mustache": "^2.3.0",
|
||||
"node-fetch": "^1.7.3",
|
||||
|
@@ -151,4 +151,13 @@ toolUtils.isMac = () => {
|
||||
return process && process.platform === 'darwin';
|
||||
}
|
||||
|
||||
toolUtils.insertContentIntoFile = async function (filePath, markerOpen, markerClose, contentToInsert) {
|
||||
const fs = require('fs-extra');
|
||||
let content = await fs.readFile(filePath, 'utf-8');
|
||||
// [^]* matches any character including new lines
|
||||
const regex = new RegExp(markerOpen + '[^]*?' + markerClose);
|
||||
content = content.replace(regex, markerOpen + contentToInsert + markerClose);
|
||||
await fs.writeFile(filePath, content);
|
||||
}
|
||||
|
||||
module.exports = toolUtils;
|
108
Tools/update-readme-contributors.js
Normal file
108
Tools/update-readme-contributors.js
Normal file
@@ -0,0 +1,108 @@
|
||||
require('app-module-path').addPath(__dirname + '/../ReactNativeClient');
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const https = require('https');
|
||||
const request = require('request');
|
||||
|
||||
const { fileExtension } = require('lib/path-utils.js');
|
||||
const readmePath = __dirname + '/../README.md';
|
||||
const { insertContentIntoFile } = require('./tool-utils.js');
|
||||
const markdownUtils = require('lib/markdownUtils');
|
||||
|
||||
async function gitHubContributors(page) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get({
|
||||
url: 'https://api.github.com/repos/laurent22/joplin/contributors' + (page ? '?page=' + page : ''),
|
||||
json: true,
|
||||
headers: {'User-Agent': 'Joplin Readme Updater'}
|
||||
}, (error, response, data) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else if (response.statusCode !== 200) {
|
||||
reject(new Error('Error HTTP ' + response.statusCode));
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function contributorTable(contributors) {
|
||||
let rows = [];
|
||||
|
||||
let row = [];
|
||||
rows.push(row);
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
let rowLength = 5;
|
||||
let contributorIndex = 0;
|
||||
while (contributorIndex < contributors.length) {
|
||||
const c = contributors[contributorIndex];
|
||||
contributorIndex++;
|
||||
|
||||
const cell = `<img width="50" src="${c.avatar_url}"/></br>[${c.login}](${c.url})`;
|
||||
|
||||
row.push(cell);
|
||||
|
||||
if (row.length >= rowLength) {
|
||||
row = [];
|
||||
rows.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
while (rows[rows.length - 1].length < rowLength) rows[rows.length - 1].push('');
|
||||
|
||||
const header = [];
|
||||
const headerLine = [];
|
||||
for (let i = 0; i < rowLength; i++) {
|
||||
header.push(' ');
|
||||
headerLine.push(':---:');
|
||||
}
|
||||
|
||||
const lines = [];
|
||||
lines.push('| ' + header.join(' | ') + ' |');
|
||||
lines.push('| ' + headerLine.join(' | ') + ' |');
|
||||
|
||||
for (const row of rows) {
|
||||
lines.push('| ' + row.join(' | ') + ' |');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
async function main(argv) {
|
||||
let contributors = [];
|
||||
let pageIndex = 0;
|
||||
const doneNames = [];
|
||||
while (true) {
|
||||
const response = await gitHubContributors(pageIndex);
|
||||
pageIndex++;
|
||||
if (!response.length) break;
|
||||
|
||||
// Remove duplicates
|
||||
const temp = [];
|
||||
for (const r of response) {
|
||||
if (doneNames.indexOf(r.login) >= 0) continue;
|
||||
doneNames.push(r.login);
|
||||
temp.push(r);
|
||||
}
|
||||
|
||||
contributors = contributors.concat(temp);
|
||||
}
|
||||
|
||||
const tableHtml = contributorTable(contributors);
|
||||
|
||||
await insertContentIntoFile(
|
||||
readmePath,
|
||||
'<!-- CONTRIBUTORS-TABLE-AUTO-GENERATED -->\n',
|
||||
'\n<!-- CONTRIBUTORS-TABLE-AUTO-GENERATED -->',
|
||||
tableHtml
|
||||
);
|
||||
}
|
||||
|
||||
main(process.argv).catch((error) => {
|
||||
console.error('Fatal error', error);
|
||||
process.exit(1);
|
||||
});
|
@@ -1,26 +0,0 @@
|
||||
### Operating system
|
||||
|
||||
<!-- Please only leave those relevant to your request -->
|
||||
|
||||
- Windows
|
||||
- macOS
|
||||
- Linux
|
||||
- Android
|
||||
- iOS
|
||||
|
||||
### Application
|
||||
|
||||
<!-- Please only leave those relevant to your request -->
|
||||
|
||||
- Desktop
|
||||
- Mobile
|
||||
- Terminal
|
||||
|
||||
<!--
|
||||
Please read the guide first! https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md
|
||||
|
||||
If you are reporting a bug, did you try enabling debug mode? https://joplinapp.org/debugging/
|
||||
If so, please post any error or warning.
|
||||
|
||||
For general discussion, user support or to discuss feature requests, please post to the forum https://discourse.joplinapp.org/ (You can login with your GitHub account)
|
||||
-->
|
Reference in New Issue
Block a user