
committed by
GitHub

No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
133 changed files with 12451 additions and 79701 deletions
-
13.babelrc.js
-
9.editorconfig
-
79.eslintrc.js
-
3.gitignore
-
26.scrutinizer.yml
-
26.stylelintrc.js
-
29.travis.yml
-
2AUTHORS
-
29CONTRIBUTING.md
-
160Makefile
-
30README.md
-
2appinfo/info.xml
-
37appinfo/routes.php
-
5composer.json
-
32css/app-navigation.scss
-
373css/notes.scss
-
BINimg/loading.gif
-
1img/search.svg
-
6js/.bowerrc
-
4js/.gitignore
-
48js/.jshintrc
-
42js/README.md
-
45js/app/controllers/appcontroller.js
-
185js/app/controllers/notecontroller.js
-
102js/app/controllers/notescontroller.js
-
26js/app/controllers/notessettingscontroller.js
-
16js/app/directives/autofocus.js
-
56js/app/directives/editor.js
-
25js/app/directives/tooltip.js
-
14js/app/filters/and.js
-
10js/app/filters/categoryTitle.js
-
22js/app/filters/groupNotes.js
-
17js/app/filters/wordCount.js
-
25js/app/services/debounce.js
-
14js/app/services/is.js
-
115js/app/services/notesmodel.js
-
80js/app/services/savequeue.js
-
40js/app/services/urlFinder.js
-
10js/bower.json
-
88js/config/app.js
-
118js/gulpfile.js
-
88js/karma.conf.js
-
32js/package.json
-
2js/public/app.min.js
-
1js/public/app.min.js.map
-
13js/tests/stubs/app.js
-
12js/tests/stubs/owncloud.js
-
63js/tests/unit/controllers/appcontrollerSpec.js
-
72js/tests/unit/controllers/notecontrollerSpec.js
-
120js/tests/unit/controllers/notescontrollerSpec.js
-
76js/tests/unit/directives/timeoutchangeSpec.js
-
36js/tests/unit/filters/andfilterSpec.js
-
19js/tests/unit/services/isSpec.js
-
65js/tests/unit/services/notesmodelSpec.js
-
116js/tests/unit/services/savequeueSpec.js
-
20js/vendor/angular-route/.bower.json
-
21js/vendor/angular-route/LICENSE.md
-
68js/vendor/angular-route/README.md
-
1071js/vendor/angular-route/angular-route.js
-
16js/vendor/angular-route/angular-route.min.js
-
8js/vendor/angular-route/angular-route.min.js.map
-
10js/vendor/angular-route/bower.json
-
2js/vendor/angular-route/index.js
-
33js/vendor/angular-route/package.json
-
18js/vendor/angular/.bower.json
-
21js/vendor/angular/LICENSE.md
-
64js/vendor/angular/README.md
-
21js/vendor/angular/angular-csp.css
-
32621js/vendor/angular/angular.js
-
324js/vendor/angular/angular.min.js
-
BINjs/vendor/angular/angular.min.js.gzip
-
8js/vendor/angular/angular.min.js.map
-
9js/vendor/angular/bower.json
-
2js/vendor/angular/index.js
-
25js/vendor/angular/package.json
-
29js/vendor/restangular/.bower.json
-
24js/vendor/restangular/.github/ISSUE_TEMPLATE.md
-
19js/vendor/restangular/.gitignore
-
23js/vendor/restangular/.jshintrc
-
11js/vendor/restangular/.travis.yml
-
77js/vendor/restangular/CHANGELOG.md
-
67js/vendor/restangular/CONTRIBUTING.md
-
188js/vendor/restangular/Gruntfile.js
-
1386js/vendor/restangular/README.md
-
18js/vendor/restangular/bower.json
-
1452js/vendor/restangular/dist/restangular.js
-
6js/vendor/restangular/dist/restangular.min.js
-
BINjs/vendor/restangular/dist/restangular.zip
-
89js/vendor/restangular/karma.conf.js
-
77js/vendor/restangular/karma.underscore.conf.js
-
21js/vendor/restangular/license.md
-
63js/vendor/restangular/package.json
-
1447js/vendor/restangular/src/restangular.js
-
35js/vendor/simplemde/.bower.json
-
10js/vendor/simplemde/CONTRIBUTING.md
-
22js/vendor/simplemde/LICENSE
-
331js/vendor/simplemde/README.md
-
23js/vendor/simplemde/bower.json
-
676js/vendor/simplemde/debug/simplemde.css
-
17023js/vendor/simplemde/debug/simplemde.debug.js
@ -0,0 +1,13 @@ |
|||
module.exports = { |
|||
plugins: ['@babel/plugin-syntax-dynamic-import'], |
|||
presets: [ |
|||
[ |
|||
'@babel/preset-env', |
|||
{ |
|||
targets: { |
|||
browsers: ['last 2 versions', 'ie >= 11'] |
|||
} |
|||
} |
|||
] |
|||
] |
|||
} |
@ -0,0 +1,79 @@ |
|||
module.exports = { |
|||
root: true, |
|||
parserOptions: { |
|||
parser: 'babel-eslint', |
|||
ecmaVersion: 6, |
|||
}, |
|||
settings: { |
|||
'import/resolver': { |
|||
webpack: { |
|||
config: 'webpack.common.js', |
|||
}, |
|||
node: { |
|||
paths: ['src'], |
|||
extensions: ['.js', '.vue'], |
|||
}, |
|||
}, |
|||
}, |
|||
extends: [ |
|||
'eslint:recommended', |
|||
'plugin:import/recommended', |
|||
'plugin:vue/recommended', |
|||
'standard', |
|||
], |
|||
globals: { |
|||
$: 'readonly', |
|||
t: 'readonly', |
|||
n: 'readonly', |
|||
OC: 'readonly', |
|||
OCA: 'readonly', |
|||
}, |
|||
plugins: [ |
|||
'vue', |
|||
], |
|||
rules: { |
|||
// allow space before function () (was "always" in "standard")
|
|||
'space-before-function-paren': ['error', 'never'], |
|||
// stay consistent with array brackets (not in "standard")
|
|||
'array-bracket-newline': ['error', 'consistent'], |
|||
|
|||
// tabs only (was spaces in "standard")
|
|||
'indent': ['error', 'tab'], |
|||
// allow tabs for indentation (was forbidden in "standard")
|
|||
'no-tabs': ['error', { allowIndentationTabs: true }], |
|||
// indentation in vue's html should be tabs (was spaces in "vue/strongly-recommended")
|
|||
'vue/html-indent': ['error', 'tab'], |
|||
|
|||
// only debug console (not in "standard")
|
|||
'no-console': ['error', { allow: ['error', 'warn', 'info', 'debug'] }], |
|||
// always add a trailing comma, for diff readability (was "never" in "standard")
|
|||
'comma-dangle': ['warn', 'always-multiline'], |
|||
// always have the operator in front (was "after" in "standard")
|
|||
'operator-linebreak': ['error', 'before'], |
|||
// ternary on multiline (not in "standard")
|
|||
'multiline-ternary': ['error', 'always-multiline'], |
|||
|
|||
// disallow use of "var" (not in "standard")
|
|||
'no-var': 'error', |
|||
// Suggest using const
|
|||
'prefer-const': 'warn', |
|||
|
|||
// check case of component names (not in "vue/recommended")
|
|||
'vue/component-name-in-template-casing': 'error', |
|||
// no ending html tag on a new line (was warn in "vue/strongly-recommended")
|
|||
'vue/html-closing-bracket-newline': 'error', |
|||
// space before self-closing elements (was warn in "vue/strongly-recommended")
|
|||
'vue/html-closing-bracket-spacing': 'error', |
|||
// code spacing with attributes (default is 1)
|
|||
'vue/max-attributes-per-line': [ |
|||
'error', |
|||
{ |
|||
singleline: 3, |
|||
multiline: { |
|||
max: 3, |
|||
allowFirstLine: true, |
|||
} |
|||
} |
|||
], |
|||
}, |
|||
} |
@ -1,16 +1,18 @@ |
|||
filter: |
|||
excluded_paths: |
|||
- 'js/vendor/*' |
|||
- 'js/public/*' |
|||
- 'js/tests/stubs/*' |
|||
- 'templates/*' |
|||
- 'l10n/*' |
|||
- 'tests/*' |
|||
excluded_paths: |
|||
- 'js/*' |
|||
- 'templates/*' |
|||
- 'l10n/*' |
|||
- 'tests/*' |
|||
|
|||
imports: |
|||
- javascript |
|||
- php |
|||
build: |
|||
nodes: |
|||
analysis: |
|||
tests: |
|||
override: |
|||
- php-scrutinizer-run |
|||
- eslint-run --ext .js,.vue src |
|||
|
|||
tools: |
|||
external_code_coverage: |
|||
timeout: 1800 |
|||
external_code_coverage: false |
|||
js_hint: false |
@ -0,0 +1,26 @@ |
|||
module.exports = { |
|||
extends: 'stylelint-config-recommended-scss', |
|||
rules: { |
|||
indentation: 'tab', |
|||
'selector-type-no-unknown': null, |
|||
'number-leading-zero': null, |
|||
'rule-empty-line-before': [ |
|||
'always', |
|||
{ |
|||
ignore: ['after-comment', 'inside-block'] |
|||
} |
|||
], |
|||
'declaration-empty-line-before': [ |
|||
'never', |
|||
{ |
|||
ignore: ['after-declaration'] |
|||
} |
|||
], |
|||
'comment-empty-line-before': null, |
|||
'selector-type-case': null, |
|||
'selector-list-comma-newline-after': null, |
|||
'no-descending-specificity': null, |
|||
'string-quotes': 'single' |
|||
}, |
|||
plugins: ['stylelint-scss'] |
|||
} |
@ -1,2 +0,0 @@ |
|||
Jan-Christoph Borchardt (http://jancborchardt.net) |
|||
Bernhard Posselt <dev@bernhard-posselt.com> |
@ -1,29 +0,0 @@ |
|||
## Submitting issues |
|||
|
|||
If you have questions about how to install or use Nextcloud, please direct these to the [mailing list][mailinglist] or our [forum][forum]. We are also available on [IRC][irc]. |
|||
|
|||
### Short version |
|||
|
|||
* The [**issue template can be found here**][template]. Please always use the issue template when reporting issues. |
|||
|
|||
### Guidelines |
|||
* Please search the existing issues first, it's likely that your issue was already reported or even fixed. |
|||
- Go to one of the repositories, click "issues" and type any word in the top search/command bar. |
|||
- You can also filter by appending e. g. "state:open" to the search string. |
|||
- More info on [search syntax within github](https://help.github.com/articles/searching-issues) |
|||
* This repository ([notes](https://github.com/nextcloud/notes/issues)) is *only* for issues within the Nextcloud notes code. |
|||
* __SECURITY__: Report any potential security bug to security@nextcloud.com following our [security policy](https://nextcloud.com/security/) instead of filing an issue in our bug tracker |
|||
* Report the issue using our [template][template], it includes all the information we need to track down the issue. |
|||
|
|||
Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues. |
|||
|
|||
[template]: https://raw.github.com/nextcloud/server/master/issue_template.md |
|||
[mailinglist]: https://mailman.owncloud.org/mailman/listinfo/owncloud |
|||
[forum]: https://help.nextcloud.com/ |
|||
[irc]: https://webchat.freenode.net/?channels=nextcloud&uio=d4 |
|||
[irc-dev]: https://webchat.freenode.net/?channels=nextcloud-dev&uio=d4 |
|||
|
|||
### Contribute Code and translations |
|||
Please check [core's contribution guidelines](https://github.com/nextcloud/server/blob/master/CONTRIBUTING.md) for further information about contributing code and translations. |
|||
|
|||
For further development questions / discussions you can also join the [#nextcloud-dev][irc-dev] IRC channel. |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"require-dev": { |
|||
"christophwurst/nextcloud": "^15.0" |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
#app-navigation li.collapsible.category-header:not(.open) a { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
#app-navigation > ul > li.app-navigation-caption { |
|||
padding: 0; |
|||
pointer-events: inherit; |
|||
} |
|||
|
|||
/* icons for sidebar */ |
|||
.nav-icon-files { |
|||
@include icon-color('folder', 'notes', $color-black); |
|||
} |
|||
|
|||
.nav-icon-emptyfolder { |
|||
@include icon-color('folder-empty', 'notes', $color-black); |
|||
} |
|||
|
|||
.nav-icon-recent { |
|||
@include icon-color('recent', 'notes', $color-black); |
|||
} |
|||
|
|||
.app-navigation-entry-utils-menu-button { |
|||
visibility: hidden; |
|||
} |
|||
|
|||
.active .app-navigation-entry-utils-menu-button, |
|||
li:hover .app-navigation-entry-utils-menu-button, |
|||
li:focus .app-navigation-entry-utils-menu-button { |
|||
visibility: visible; |
|||
} |
|||
|
@ -1,372 +1 @@ |
|||
/** |
|||
* Copyright (c) 2013, Jan-Christoph Borchardt http://jancborchardt.net |
|||
* and others |
|||
* This file is licensed under the Affero General Public License version 3 or later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
#app { |
|||
width: 100%; |
|||
} |
|||
#app-content { |
|||
height: 100%; |
|||
} |
|||
|
|||
#app-navigation > ul > li.has-error a{ |
|||
color: var(--color-error); |
|||
} |
|||
|
|||
#app-navigation li .nav-entry { |
|||
display: block; |
|||
width: 100%; |
|||
line-height: 44px; |
|||
min-height: 44px; |
|||
padding: 0 12px; |
|||
overflow: hidden; |
|||
box-sizing: border-box; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
color: var(--color-main-text); |
|||
opacity: .57; |
|||
} |
|||
|
|||
#app-navigation li .nav-entry .emptycontent-search { |
|||
white-space: normal; |
|||
} |
|||
@media (max-height: 600px) { |
|||
#app-navigation li .nav-entry .emptycontent-search { |
|||
margin-top: inherit; |
|||
} |
|||
} |
|||
|
|||
#app-navigation li.search-result-header > a, |
|||
#app-navigation li.search-result-header > a * { |
|||
font-style: italic; |
|||
cursor: default; |
|||
} |
|||
|
|||
#app-navigation li:hover .nav-entry, |
|||
#app-navigation li:focus .nav-entry { |
|||
opacity: 1; |
|||
} |
|||
|
|||
|
|||
/* only display the delete button when the note is active */ |
|||
#app-navigation .app-navigation-entry-utils-menu-button { |
|||
display: none; |
|||
} |
|||
|
|||
#app-navigation .app-navigation-entry-utils-menu-button.button-star.starred, |
|||
#app-navigation .active .app-navigation-entry-utils-menu-button.button-delete, |
|||
#app-navigation .active .app-navigation-entry-utils-menu-button.button-star, |
|||
#app-navigation li:hover .app-navigation-entry-utils-menu-button.button-delete, |
|||
#app-navigation li:hover .app-navigation-entry-utils-menu-button.button-star { |
|||
display: inline-block; |
|||
} |
|||
#app-navigation .app-navigation-entry-utils .app-navigation-entry-utils-menu-button .icon-delete { |
|||
opacity: .3; |
|||
} |
|||
#app-navigation .app-navigation-entry-utils-menu-button .icon-starred { |
|||
display: inline-block; |
|||
opacity: 1 !important; |
|||
} |
|||
|
|||
#app-settings-content > div + div { |
|||
padding-top: 2ex; |
|||
} |
|||
|
|||
#app-settings-content form, |
|||
#app-content .note-meta > .note-category > form { |
|||
display: inline-flex; |
|||
} |
|||
|
|||
.tooltip { |
|||
text-shadow: none; |
|||
text-transform: none; |
|||
} |
|||
|
|||
#app-content-container { |
|||
height: 100%; |
|||
} |
|||
|
|||
/* special styling to make editor subtle and fit the window */ |
|||
.CodeMirror { |
|||
position: relative; |
|||
min-height: 100%; |
|||
max-width: 47em; |
|||
margin: 0 0 -50px; |
|||
padding: 30px 0 90px; |
|||
border: none; |
|||
font-size: 16px; |
|||
line-height: 1.5em; |
|||
} |
|||
|
|||
.CodeMirror-scroll { |
|||
overflow-x: auto !important; |
|||
} |
|||
|
|||
/* enable clickthrough for links */ |
|||
.CodeMirror-cursor { |
|||
pointer-events: none; |
|||
border-color: var(--color-main-text); |
|||
} |
|||
|
|||
#app-content .note-meta { |
|||
position: fixed; |
|||
bottom: 0; |
|||
width: 100%; |
|||
padding: 0 45px 0px 45px; |
|||
margin: -10px 0 0; |
|||
background-color: var(--color-main-background); |
|||
-ms-user-select: none; |
|||
-moz-user-select: none; |
|||
-webkit-user-select: none; |
|||
z-index: 5; |
|||
} |
|||
#app-content .note-meta > * { |
|||
opacity: .5; |
|||
} |
|||
|
|||
#app-content .note-meta > .note-category { |
|||
padding-right: 1ex; |
|||
} |
|||
|
|||
#app-content .note-meta > .note-error { |
|||
opacity: 1; |
|||
background-color: var(--color-error); |
|||
color: var(--color-primary-text); |
|||
border-radius: 0.5ex; |
|||
padding: 0.5ex 1ex; |
|||
} |
|||
#app-content .note-meta-right { |
|||
position: fixed; |
|||
bottom: 10px; |
|||
right: 10px; |
|||
} |
|||
|
|||
#app-content .note-meta > .saving { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
width: 2.5ex; |
|||
height: 2.5ex; |
|||
background: url('../img/loading.gif') no-repeat; |
|||
background-size: contain; |
|||
opacity: 1; |
|||
margin: 0 1ex; |
|||
} |
|||
|
|||
#app-content .note-meta form { |
|||
display: inline; |
|||
} |
|||
|
|||
#app-content .note-meta .note-category { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
#app-content .note-meta .note-category .icon-loading-small { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
margin: 0px 5px; |
|||
} |
|||
|
|||
#app-content .note-meta .edit { |
|||
background-color: transparent; |
|||
border: none; |
|||
opacity: 0.5; |
|||
vertical-align: middle; |
|||
} |
|||
#app-content .note-meta:hover .note-category, |
|||
#app-content .note-meta:hover .edit { |
|||
opacity: 1; |
|||
} |
|||
|
|||
|
|||
.btn-fullscreen { |
|||
padding: 15px; |
|||
} |
|||
|
|||
|
|||
/* category and auto-complete */ |
|||
|
|||
form.category #category { |
|||
width: 15em; |
|||
} |
|||
|
|||
form.category .icon-confirm { |
|||
margin-right: 0; |
|||
} |
|||
.ui-autocomplete.category-autocomplete { |
|||
z-index: 5000 !important; |
|||
position: fixed; |
|||
max-height: 200px; |
|||
overflow-y: auto; |
|||
overflow-x: hidden; |
|||
border-top: 1px solid var(--color-border); |
|||
border-radius: 0; |
|||
border-top-left-radius: 3px; |
|||
border-top-right-radius: 3px; |
|||
} |
|||
.category-autocomplete .ui-menu-item a { |
|||
font-weight: inherit; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
|
|||
/* markdown styling */ |
|||
.CodeMirror { |
|||
background: transparent; |
|||
color: inherit; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code { |
|||
width: 100%; |
|||
} |
|||
.CodeMirror .CodeMirror-code .cm-header { |
|||
/* break from core in using semibold, otherwise not emphasized in texts */ |
|||
font-weight: 600; |
|||
} |
|||
.CodeMirror .CodeMirror-code .cm-header-1 { |
|||
font-size: 28px; |
|||
margin: 50px 0 20px; |
|||
line-height: 120%; |
|||
} |
|||
.CodeMirror .CodeMirror-code .cm-header-2 { |
|||
font-size: 20px; |
|||
margin-top: 12px; |
|||
line-height: 150%; |
|||
} |
|||
.CodeMirror .CodeMirror-code .cm-header-3, |
|||
.CodeMirror .CodeMirror-code .cm-header-4, |
|||
.CodeMirror .CodeMirror-code .cm-header-5, |
|||
.CodeMirror .CodeMirror-code .cm-header-6 { |
|||
font-size: 16px; |
|||
margin: 0; |
|||
font-weight: 300; |
|||
} |
|||
.CodeMirror .CodeMirror-code .cm-header-3 { |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-hr { |
|||
position: relative; |
|||
display: inline-block; |
|||
width: 100%; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-hr:before { |
|||
position: absolute; |
|||
content: ""; |
|||
top: 50%; |
|||
width: 100%; |
|||
z-index: -1; |
|||
border-top: 5px solid rgba(120, 120, 120, 0.2); |
|||
} |
|||
|
|||
|
|||
/* hanging punctuation */ |
|||
.CodeMirror .CodeMirror-code .CodeMirror-line { |
|||
padding-left: 45px; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-formatting-header:not(:only-child), |
|||
.CodeMirror .CodeMirror-code .cm-formatting-list, |
|||
.CodeMirror .CodeMirror-code .cm-formatting-quote { |
|||
position: absolute; |
|||
display: inline-block; |
|||
width: 90px; |
|||
margin-top: 0; |
|||
margin-left: -90px; |
|||
text-align: right; |
|||
white-space: pre; |
|||
color: rgba(120, 120, 120, 0.5); |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-formatting-header:not(:first-child) { |
|||
width: auto; |
|||
margin-left: 0px; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-comment { |
|||
font-family: MONOSPACE; |
|||
} |
|||
|
|||
/* Checkboxes */ |
|||
.CodeMirror .CodeMirror-code .cm-formatting-task { |
|||
position: relative; |
|||
display: inline-block; |
|||
width: 1.8em; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-formatting-task.cm-meta::before { |
|||
content: "\2610"; |
|||
font-size: 1.5em; |
|||
background: white; |
|||
position: absolute; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .cm-formatting-task.cm-property::before { |
|||
content: "\2611"; |
|||
font-size: 1.5em; |
|||
background: white; |
|||
position: absolute; |
|||
} |
|||
|
|||
.CodeMirror .CodeMirror-code .CodeMirror-line.completed-task { |
|||
color: #999; |
|||
text-decoration: line-through; |
|||
} |
|||
|
|||
/* Recommended tab size increase for readability */ |
|||
.CodeMirror .CodeMirror-code .cm-tab { |
|||
width: 2em; |
|||
} |
|||
|
|||
/* distraction free styles */ |
|||
:-webkit-full-screen, |
|||
:-moz-full-screen, |
|||
:-ms-fullscreen, |
|||
:fullscreen { |
|||
width: 100%; |
|||
background-color: var(--color-main-background); |
|||
|
|||
#app-content-container { |
|||
margin: 0 auto; |
|||
} |
|||
} |
|||
|
|||
/* larger screen sizes */ |
|||
@media only screen and (min-width: 769px) { |
|||
/* use slightly more space on the left so all # signs of h3โh6 show */ |
|||
.CodeMirror .CodeMirror-code .CodeMirror-line, |
|||
#app-content .note-meta { |
|||
padding-left: 90px; |
|||
} |
|||
} |
|||
|
|||
|
|||
/* icons for sidebar */ |
|||
.nav-icon-files { |
|||
@include icon-color('folder', 'notes', $color-black); |
|||
} |
|||
.nav-icon-emptyfolder { |
|||
@include icon-color('folder-empty', 'notes', $color-black); |
|||
} |
|||
.nav-icon-recent { |
|||
@include icon-color('recent', 'notes', $color-black); |
|||
} |
|||
.nav-icon-search { |
|||
@include icon-color('search', 'notes', $color-black); |
|||
} |
|||
|
|||
|
|||
|
|||
.separator-below { |
|||
border-bottom: 1px solid var(--color-border); |
|||
} |
|||
.separator-above { |
|||
border-top: 1px solid var(--color-border); |
|||
} |
|||
.current-category-item > a, |
|||
a.current-category-item { |
|||
font-weight: bold; |
|||
} |
|||
@import 'app-navigation.scss'; |
Before Width: 32 | Height: 32 | Size: 3.1 KiB |
@ -1 +0,0 @@ |
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 16 16" height="16" width="16"><g stroke="#000" stroke-width="2" fill="none"><ellipse rx="4" ry="4" cy="6" cx="6"/><path d="m14.3 14.25-5.65-5.65"/></g></svg> |
@ -1,6 +0,0 @@ |
|||
{ |
|||
"directory": "vendor", |
|||
"ignoredDependencies": [ |
|||
"lodash" |
|||
] |
|||
} |
@ -1,4 +0,0 @@ |
|||
node_modules/ |
|||
*.log |
|||
test-results.xml |
|||
vendor/**/test |
@ -1,48 +0,0 @@ |
|||
{ |
|||
"esnext": true, |
|||
"bitwise": true, |
|||
"camelcase": true, |
|||
"curly": true, |
|||
"eqeqeq": true, |
|||
"forin": false, |
|||
"immed": true, |
|||
"indent": 4, |
|||
"latedef": true, |
|||
"newcap": true, |
|||
"noarg": true, |
|||
"noempty": true, |
|||
"nonew": true, |
|||
"plusplus": true, |
|||
"quotmark": "single", |
|||
"undef": true, |
|||
"unused": true, |
|||
"strict": true, |
|||
"maxparams": false, |
|||
"maxdepth": 3, |
|||
"maxlen": 80, |
|||
"browser": true, |
|||
"devel": true, |
|||
"jquery": true, |
|||
"globals": { |
|||
"angular": true, |
|||
"app": true, |
|||
"OC": true, |
|||
"requestToken": true, |
|||
"inject": true, |
|||
"module": true, |
|||
"protractor": true, |
|||
"browser": true, |
|||
"By": true, |
|||
"it": true, |
|||
"afterEach": true, |
|||
"jasmine": true, |
|||
"describe": true, |
|||
"beforeEach": true, |
|||
"expect": true, |
|||
"exports": true, |
|||
"t": true, |
|||
"mdEdit": true, |
|||
"require": true, |
|||
"__dirname": true |
|||
} |
|||
} |
@ -1,42 +0,0 @@ |
|||
# Building JavaScript and CSS |
|||
|
|||
To build JavaScript and CSS first install Gulp and install the required modules via npm: |
|||
|
|||
sudo npm install -g gulp |
|||
npm install |
|||
|
|||
To simply build everything run: |
|||
|
|||
gulp |
|||
|
|||
You can also run it in watch mode to rebuild when files change: |
|||
|
|||
gulp watch |
|||
|
|||
# Tests |
|||
|
|||
Run all tests: |
|||
|
|||
gulp test-all |
|||
|
|||
Run JavaScript tests: |
|||
|
|||
gulp test |
|||
|
|||
in watch mode: |
|||
|
|||
gulp watch-test |
|||
|
|||
Run PHP unit tests: |
|||
|
|||
gulp test-php |
|||
|
|||
in watch mode: |
|||
|
|||
gulp watch-test-php |
|||
|
|||
|
|||
Run PHP integration tests: |
|||
|
|||
gulp test-php-integration |
|||
|
@ -1,45 +0,0 @@ |
|||
/** |
|||
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
app.controller('AppController', function ($scope, $location, is) { |
|||
'use strict'; |
|||
|
|||
$scope.is = is; |
|||
|
|||
$scope.init = function (lastViewedNote, errorMessage) { |
|||
$scope.defaultTitle = document.title; |
|||
|
|||
if(lastViewedNote !== 0 && $location.path()==='') { |
|||
$location.path('/notes/' + lastViewedNote); |
|||
} |
|||
if(errorMessage) { |
|||
OC.Notification.showTemporary(errorMessage); |
|||
} |
|||
$scope.initSearch(); |
|||
}; |
|||
|
|||
$scope.search = ''; |
|||
$scope.defaultTitle = null; |
|||
|
|||
$scope.initSearch = function() { |
|||
new OCA.Search( |
|||
function (query) { |
|||
$scope.search = query; |
|||
$scope.$apply(); |
|||
if($('#app-navigation-toggle').css('display')!=='none' && |
|||
!$('body').hasClass('snapjs-left')) { |
|||
$('#app-navigation-toggle').click(); |
|||
} |
|||
}, |
|||
function () { |
|||
$scope.search = ''; |
|||
$scope.$apply(); |
|||
} |
|||
); |
|||
}; |
|||
|
|||
}); |
@ -1,185 +0,0 @@ |
|||
/** |
|||
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
app.controller('NoteController', function($routeParams, $scope, NotesModel, |
|||
SaveQueue, note, debounce, |
|||
$document, $timeout) { |
|||
'use strict'; |
|||
|
|||
NotesModel.updateIfExists(note); |
|||
|
|||
$scope.note = NotesModel.get($routeParams.noteId); |
|||
|
|||
$scope.isSaving = function () { |
|||
return SaveQueue.isSaving(); |
|||
}; |
|||
$scope.isManualSaving = function () { |
|||
return SaveQueue.isManualSaving(); |
|||
}; |
|||
|
|||
$scope.updateTitle = function () { |
|||
var content = $scope.note.content; |
|||
|
|||
// prepare content: remove markdown characters and empty spaces
|
|||
content = content.replace(/^\s*[*+-]\s+/mg, ''); // list item
|
|||
content = content.replace(/^#+\s+(.*?)\s*#*$/mg, '$1'); // headline
|
|||
content = content.replace(/^(=+|-+)$/mg, ''); // separate headline
|
|||
content = content.replace(/(\*+|_+)(.*?)\1/mg, '$2'); // emphasis
|
|||
|
|||
// prevent directory traversal, illegal characters
|
|||
content = content.replace(/[\*\|\/\\\:\"<>\?]/g, ''); |
|||
// prevent unintended file names
|
|||
content = content.replace(/^[\. ]+/mg, ''); |
|||
|
|||
// generate title from the first line of the content
|
|||
$scope.note.title = content.trim().split(/\r?\n/, 2)[0] || |
|||
t('notes', 'New note'); |
|||
}; |
|||
|
|||
$scope.toggleCheckbox = function (el) { |
|||
var $el = $(el); |
|||
var cm = $('.CodeMirror')[0].CodeMirror; |
|||
var doc = cm.getDoc(); |
|||
var index = $el.parents('.CodeMirror-line').index(); |
|||
var line = doc.getLineHandle(index); |
|||
|
|||
var newvalue = ( $el.text() === '[x]' ) ? '[ ]' : '[x]'; |
|||
|
|||
// + 1 for some reason... not sure why
|
|||
doc.replaceRange(newvalue, |
|||
{line: index, ch: line.text.indexOf('[')}, |
|||
{line: index, ch: line.text.indexOf(']') + 1} |
|||
); |
|||
}; |
|||
|
|||
$scope.onEdit = function() { |
|||
var note = $scope.note; |
|||
note.unsaved = true; |
|||
$scope.autoSave(note); |
|||
}; |
|||
|
|||
$scope.autoSave = debounce(function(note) { |
|||
SaveQueue.add(note); |
|||
}, 1000); |
|||
|
|||
$scope.manualSave = function() { |
|||
var note = $scope.note; |
|||
note.error = false; |
|||
SaveQueue.addManual(note); |
|||
}; |
|||
|
|||
$scope.editCategory = false; |
|||
$scope.showEditCategory = function() { |
|||
$('#category').val($scope.note.category); |
|||
$scope.editCategory = true; |
|||
$('#category').autocomplete({ |
|||
source: NotesModel.getCategories(NotesModel.getAll(), 0, false), |
|||
minLength: 0, |
|||
position: { my: 'left bottom', at: 'left top', of: '#category' }, |
|||
open: function() { |
|||
$timeout(function() { |
|||
var width = $('form.category').innerWidth() - 2; |
|||
$('.ui-autocomplete.ui-menu').width(width); |
|||
}); |
|||
}, |
|||
}).autocomplete('widget').addClass('category-autocomplete'); |
|||
// fix space between input and confirm-button
|
|||
$('form.category .icon-confirm').insertAfter('#category'); |
|||
|
|||
$timeout(function() { |
|||
$('#category').focus(); |
|||
$('#category').autocomplete('search', ''); |
|||
}); |
|||
}; |
|||
$scope.saveCategory = function () { |
|||
var category = $('#category').val(); |
|||
if($scope.note.category === category) { |
|||
$scope.editCategory = false; |
|||
return; |
|||
} |
|||
$scope.isCategorySaving = true; |
|||
$scope.note.customPUT({category: category}, 'category', {}, {}) |
|||
.then( |
|||
function (updatedNote) { |
|||
$scope.note.category = updatedNote.category; |
|||
if(category !== updatedNote.category) { |
|||
OC.Notification.showTemporary( |
|||
t('notes', 'Updating the note\'s category has failed.'+ |
|||
' Is the target directory writable?') |
|||
); |
|||
} |
|||
}, |
|||
function () { |
|||
OC.Notification.showTemporary( |
|||
t('notes', 'Updating the note\'s category has failed.') |
|||
); |
|||
} |
|||
) |
|||
.finally( |
|||
function () { |
|||
$scope.isCategorySaving = false; |
|||
$scope.editCategory = false; |
|||
} |
|||
); |
|||
}; |
|||
|
|||
|
|||
$document.unbind('keypress.notes.save'); |
|||
$document.bind('keypress.notes.save', function(event) { |
|||
if(event.ctrlKey || event.metaKey) { |
|||
switch(String.fromCharCode(event.which).toLowerCase()) { |
|||
case 's': |
|||
event.preventDefault(); |
|||
$scope.manualSave(); |
|||
break; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
$scope.toggleDistractionFree = function() { |
|||
function launchIntoFullscreen(element) { |
|||
if(element.requestFullscreen) { |
|||
element.requestFullscreen(); |
|||
} else if(element.mozRequestFullScreen) { |
|||
element.mozRequestFullScreen(); |
|||
} else if(element.webkitRequestFullscreen) { |
|||
element.webkitRequestFullscreen(); |
|||
} else if(element.msRequestFullscreen) { |
|||
element.msRequestFullscreen(); |
|||
} |
|||
} |
|||
|
|||
function exitFullscreen() { |
|||
if(document.exitFullscreen) { |
|||
document.exitFullscreen(); |
|||
} else if(document.mozCancelFullScreen) { |
|||
document.mozCancelFullScreen(); |
|||
} else if(document.webkitExitFullscreen) { |
|||
document.webkitExitFullscreen(); |
|||
} |
|||
} |
|||
|
|||
if(document.fullscreenElement || |
|||
document.mozFullScreenElement || |
|||
document.webkitFullscreenElement) { |
|||
exitFullscreen(); |
|||
} else { |
|||
launchIntoFullscreen(document.getElementById('app-content')); |
|||
} |
|||
}; |
|||
|
|||
$scope.$watch(function() { |
|||
return $scope.note.title; |
|||
}, function(newValue) { |
|||
if(newValue) { |
|||
document.title = newValue + ' - ' + $scope.defaultTitle; |
|||
} else { |
|||
document.title = $scope.defaultTitle; |
|||
} |
|||
}); |
|||
|
|||
}); |
@ -1,102 +0,0 @@ |
|||
/** |
|||
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
// This is available by using ng-controller="NotesController" in your HTML
|
|||
app.controller('NotesController', function($routeParams, $scope, $location, |
|||
Restangular, NotesModel, $window) { |
|||
'use strict'; |
|||
|
|||
$scope.route = $routeParams; |
|||
$scope.notesLoaded = false; |
|||
$scope.notes = NotesModel.getAll(); |
|||
|
|||
$scope.folderSelectorOpen = false; |
|||
$scope.filterCategory = null; |
|||
|
|||
$scope.orderRecent = ['-favorite','-modified']; |
|||
$scope.orderAlpha = ['category','-favorite','title']; |
|||
$scope.filterOrder = $scope.orderRecent; |
|||
|
|||
var notesResource = Restangular.all('notes'); |
|||
|
|||
// initial request for getting all notes
|
|||
notesResource.getList().then(function (notes) { |
|||
NotesModel.addAll(notes); |
|||
$scope.notesLoaded = true; |
|||
}); |
|||
|
|||
$scope.create = function () { |
|||
notesResource.post({category: $scope.filterCategory}) |
|||
.then(function (note) { |
|||
NotesModel.add(note); |
|||
$location.path('/notes/' + note.id); |
|||
}); |
|||
}; |
|||
|
|||
$scope.delete = function (noteId) { |
|||
var note = NotesModel.get(noteId); |
|||
note.remove().then(function () { |
|||
NotesModel.remove(noteId); |
|||
$scope.$emit('$routeChangeError'); |
|||
}); |
|||
}; |
|||
|
|||
$scope.toggleFavorite = function (noteId, event) { |
|||
var note = NotesModel.get(noteId); |
|||
note.customPUT({favorite: !note.favorite}, |
|||
'favorite', {}, {}).then(function (favorite) { |
|||
note.favorite = favorite ? true : false; |
|||
}); |
|||
event.target.blur(); |
|||
}; |
|||
|
|||
$scope.categories = []; |
|||
$scope.$watch('notes', function(notes) { |
|||
$scope.categories = NotesModel.getCategories(notes, 1, true); |
|||
}, true); |
|||
|
|||
$scope.toggleFolderSelector = function () { |
|||
$scope.folderSelectorOpen = !$scope.folderSelectorOpen; |
|||
}; |
|||
|
|||
$scope.setFilter = function (category) { |
|||
if(category===null) { |
|||
$scope.filterOrder = $scope.orderRecent; |
|||
} else { |
|||
$scope.filterOrder = $scope.orderAlpha; |
|||
} |
|||
$scope.filterCategory = category; |
|||
$scope.folderSelectorOpen = false; |
|||
$('#app-navigation > ul').animate({scrollTop: 0}, 'fast'); |
|||
}; |
|||
|
|||
$scope.categoryFilter = function (note) { |
|||
if($scope.filterCategory!==null) { |
|||
if(note.category===$scope.filterCategory) { |
|||
return true; |
|||
} else if(note.category!==null) { |
|||
return note.category.startsWith($scope.filterCategory+'/'); |
|||
} |
|||
} |
|||
return true; |
|||
}; |
|||
|
|||
$scope.isCategory = function (item) { |
|||
return typeof item === 'string'; |
|||
}; |
|||
|
|||
$window.onbeforeunload = function() { |
|||
var notes = NotesModel.getAll(); |
|||
for(var i=0; i<notes.length; i+=1) { |
|||
if(notes[i].unsaved) { |
|||
return t('notes', 'There are unsaved notes. Leaving ' + |
|||
'the page will discard all changes!'); |
|||
} |
|||
} |
|||
return null; |
|||
}; |
|||
}); |
@ -1,26 +0,0 @@ |
|||
app.controller('NotesSettingsController', |
|||
function($scope, Restangular, $document) { |
|||
'use strict'; |
|||
|
|||
$scope.extensions = ['.txt', '.md']; |
|||
|
|||
Restangular.one('settings').get().then(function(settings) { |
|||
if(angular.isObject(settings)) { |
|||
$scope.settings = settings; |
|||
} else { |
|||
$scope.settings = Restangular.one('settings'); |
|||
} |
|||
}); |
|||
|
|||
$document.on('change', '#notesPath', function() { |
|||
var msg = t('notes', 'Please wait while new settings are appliedโฆ'); |
|||
OC.Notification.show(msg); |
|||
$scope.settings.put().then(function() { |
|||
window.location.reload(true); |
|||
}); |
|||
}); |
|||
|
|||
$document.on('change', '#fileSuffix', function() { |
|||
$scope.settings.put(); |
|||
}); |
|||
}); |
@ -1,16 +0,0 @@ |
|||
/** |
|||
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
app.directive('notesAutofocus', function () { |
|||
'use strict'; |
|||
return { |
|||
restrict: 'A', |
|||
link: function (scope, element) { |
|||
element.focus(); |
|||
} |
|||
}; |
|||
}); |
@ -1,56 +0,0 @@ |
|||
/*global SimpleMDE*/ |
|||
app.directive('editor', ['$timeout', |
|||
'urlFinder', |
|||
function ($timeout, urlFinder) { |
|||
'use strict'; |
|||
return { |
|||
restrict: 'A', |
|||
link: function(scope, element) { |
|||
|
|||
var simplemde = new SimpleMDE({ |
|||
element: element[0], |
|||
spellChecker: false, |
|||
autoDownloadFontAwesome: false, |
|||
toolbar: false, |
|||
status: false, |
|||
forceSync: true |
|||
}); |
|||
var editorElement = $(simplemde.codemirror.getWrapperElement()); |
|||
|
|||
simplemde.value(scope.note.content); |
|||
simplemde.codemirror.focus(); |
|||
|
|||
/* Initialize Checkboxes */ |
|||
$('.CodeMirror-code').on('mousedown.checkbox touchstart.checkbox', '.cm-formatting-task', function (e) { |
|||
e.preventDefault(); |
|||
e.stopImmediatePropagation(); |
|||
scope.toggleCheckbox(e.target); |
|||
}); |
|||
|
|||
simplemde.codemirror.on('update', function () { |
|||
// For strikethrough styling of completed tasks
|
|||
$('.CodeMirror-line').removeClass('completed-task'); |
|||
$('.CodeMirror-line:contains("[x]")').addClass('completed-task'); |
|||
}); |
|||
|
|||
simplemde.codemirror.on('change', function() { |
|||
$timeout(function() { |
|||
scope.$apply(function () { |
|||
scope.note.content = simplemde.value(); |
|||
scope.onEdit(); |
|||
scope.updateTitle(); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
editorElement.on('click', '.cm-link, .cm-url', function(event) { |
|||
if(event.ctrlKey) { |
|||
var url = urlFinder(this); |
|||
if(angular.isDefined(url)) { |
|||
window.open(url, '_blank'); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
}]); |
@ -1,25 +0,0 @@ |
|||
/** |
|||
* Copyright (c) 2013, Bernhard Posselt <dev@bernhard-posselt.com> |
|||
* This file is licensed under the Affero General Public License version 3 or |
|||
* later. |
|||
* See the COPYING file. |
|||
*/ |
|||
|
|||
app.directive('notesTooltip', function () { |
|||
'use strict'; |
|||
|
|||
return { |
|||
restrict: 'A', |
|||
link: function (scope, element) { |
|||
element.tooltip({'container': 'body'}); |
|||
|
|||
element.on('$destroy', function() { |
|||
element.tooltip('hide'); |
|||
}); |
|||
|
|||
element.on('click', function() { |
|||
element.tooltip('hide'); |
|||
}); |
|||
} |
|||
}; |
|||
}); |
@ -1,14 +0,0 @@ |
|||
/** |
|||
* filter by multiple words (AND operation) |
|||
*/ |
|||
app.filter('and', ['$filter', function ($filter) { |
|||
'use strict'; |
|||
return function (items, searchString) { |
|||
var searchValues = searchString.split(' '); |
|||
var filtered = items; |
|||
for(var i in searchValues) { |
|||
filtered = $filter('filter')(filtered, searchValues[i]); |
|||
} |
|||
return filtered; |
|||
}; |
|||
}]); |