Compare commits
No commits in common. "v4" and "master" have entirely different histories.
14
.babelrc
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", { "modules": false }],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": ["transform-runtime"],
|
||||
"comments": false,
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": ["env", "stage-2"],
|
||||
"plugins": ["transform-es2015-modules-commonjs", "dynamic-import-node"]
|
||||
}
|
||||
}
|
||||
}
|
9
.dockerignore
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules
|
||||
.git
|
||||
dist
|
||||
.history
|
||||
images
|
||||
docs
|
||||
Dockerfile
|
||||
README.md
|
||||
build.sh
|
@ -1,9 +1,9 @@
|
||||
# http://EditorConfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
build/*.js
|
||||
config/*.js
|
||||
src/libs/*.js
|
44
.eslintrc.js
Normal file
@ -0,0 +1,44 @@
|
||||
// http://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: 'babel-eslint',
|
||||
parserOptions: {
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
},
|
||||
extends: 'airbnb-base',
|
||||
// required to lint *.vue files
|
||||
plugins: [
|
||||
'html'
|
||||
],
|
||||
globals: {
|
||||
"NODE_ENV": false,
|
||||
"VERSION": false
|
||||
},
|
||||
// check if imports actually resolve
|
||||
'settings': {
|
||||
'import/resolver': {
|
||||
'webpack': {
|
||||
'config': 'build/webpack.base.conf.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
'no-param-reassign': [2, { 'props': false }],
|
||||
// don't require .vue extension when importing
|
||||
'import/extensions': ['error', 'always', {
|
||||
'js': 'never',
|
||||
'vue': 'never'
|
||||
}],
|
||||
// allow optionalDependencies
|
||||
'import/no-extraneous-dependencies': ['error', {
|
||||
'optionalDependencies': ['test/unit/index.js']
|
||||
}],
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
|
||||
}
|
||||
}
|
16
.gitignore
vendored
@ -1,8 +1,10 @@
|
||||
.project
|
||||
.idea
|
||||
.settings
|
||||
node_modules
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
stackedit.iml
|
||||
public/res/bower-libs
|
||||
node_modules/
|
||||
dist/
|
||||
.history
|
||||
.idea
|
||||
npm-debug.log*
|
||||
.vscode
|
||||
stackedit_v4
|
||||
chrome-app/*.zip
|
||||
/test/unit/coverage/
|
||||
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"curly": true,
|
||||
"node": true,
|
||||
"indent": 4,
|
||||
"latedef": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"expr": true
|
||||
}
|
8
.postcssrc.js
Normal file
@ -0,0 +1,8 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
// to edit target browsers: use "browserlist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
7
.stylelintrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"processors": ["stylelint-processor-html"],
|
||||
"extends": "stylelint-config-standard",
|
||||
"rules": {
|
||||
"no-empty-source": null
|
||||
}
|
||||
}
|
22
.travis.yml
Normal file
@ -0,0 +1,22 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "12"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_deploy:
|
||||
# Run docker build
|
||||
- docker build -t benweet/stackedit .
|
||||
# Install Helm
|
||||
- curl -SL -o /tmp/get_helm.sh https://git.io/get_helm.sh
|
||||
- chmod 700 /tmp/get_helm.sh
|
||||
- /tmp/get_helm.sh
|
||||
- helm init --client-only
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: bash build/deploy.sh
|
||||
on:
|
||||
tags: true
|
19
Dockerfile
@ -1,7 +1,16 @@
|
||||
# Pull base image.
|
||||
FROM node:0.12-onbuild
|
||||
FROM mafgwo/wkhtmltopdf-nodejs:11.15.0
|
||||
|
||||
# Node base will default the command to `node server.js`.
|
||||
WORKDIR /opt/stackedit
|
||||
|
||||
# Expose port.
|
||||
EXPOSE 3000
|
||||
COPY package*json /opt/stackedit/
|
||||
COPY gulpfile.js /opt/stackedit/
|
||||
|
||||
RUN npm install --unsafe-perm \
|
||||
&& npm cache clean --force
|
||||
COPY . /opt/stackedit
|
||||
ENV NODE_ENV production
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD [ "node", "." ]
|
||||
|
285
Gulpfile.js
@ -1,285 +0,0 @@
|
||||
/* jshint -W015 */
|
||||
var gulp = require('gulp');
|
||||
var util = require('gulp-util');
|
||||
var clean = require('gulp-clean');
|
||||
var jshint = require('gulp-jshint');
|
||||
var requirejs = require('gulp-requirejs');
|
||||
var bowerRequirejs = require('bower-requirejs');
|
||||
var uglify = require('gulp-uglify');
|
||||
var less = require('gulp-less');
|
||||
var inject = require('gulp-inject');
|
||||
var replace = require('gulp-replace');
|
||||
var bump = require('gulp-bump');
|
||||
var childProcess = require('child_process');
|
||||
var runSequence = require('run-sequence');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
/** __________________________________________
|
||||
* constants.js
|
||||
*/
|
||||
function getVersion() {
|
||||
var packageJson = JSON.parse(fs.readFileSync(__dirname + '/package.json', {
|
||||
encoding: 'utf8'
|
||||
}));
|
||||
return packageJson.version;
|
||||
}
|
||||
|
||||
gulp.task('constants', function() {
|
||||
return gulp.src('./public/res/constants.js')
|
||||
.pipe(replace(/constants\.VERSION = .*/, 'constants.VERSION = "' + getVersion() + '";'))
|
||||
.pipe(gulp.dest('./public/res/'));
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* JSHint
|
||||
*/
|
||||
|
||||
gulp.task('jshint', function() {
|
||||
return gulp.src([
|
||||
'./*.js',
|
||||
'./app/**/*.js',
|
||||
'./public/res/classes/**/*.js',
|
||||
'./public/res/extensions/**/*.js',
|
||||
'./public/res/helpers/**/*.js',
|
||||
'./public/res/providers/**/*.js',
|
||||
'./public/res/*.js'
|
||||
])
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter('default'))
|
||||
.pipe(jshint.reporter('fail'));
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* RequireJS
|
||||
*/
|
||||
|
||||
gulp.task('clean-requirejs', function() {
|
||||
return gulp.src([
|
||||
'./public/res-min/main.js',
|
||||
'./public/res-min/require.js'
|
||||
])
|
||||
.pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('copy-requirejs', ['clean-requirejs'], function() {
|
||||
return gulp.src('./public/res/bower-libs/requirejs/require.js')
|
||||
.pipe(gulp.dest('./public/res-min/'));
|
||||
});
|
||||
|
||||
gulp.task('requirejs', [
|
||||
'copy-requirejs',
|
||||
'constants'
|
||||
], function() {
|
||||
return requirejs({
|
||||
baseUrl: 'public/res',
|
||||
name: 'main',
|
||||
out: 'main.js',
|
||||
mainConfigFile: 'public/res/main.js',
|
||||
// optimize: 'uglify2',
|
||||
inlineText: true,
|
||||
paths: {
|
||||
mathjax: 'empty:'
|
||||
},
|
||||
excludeShallow: [
|
||||
'css/css-builder',
|
||||
'less/lessc-server',
|
||||
'less/lessc'
|
||||
]
|
||||
})
|
||||
.pipe(uglify({
|
||||
output: {
|
||||
beautify: true,
|
||||
indent_level: 1,
|
||||
ascii_only: true
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./public/res-min/'));
|
||||
});
|
||||
|
||||
gulp.task('bower-requirejs', function() {
|
||||
return new Promise(function (resolve) {
|
||||
bowerRequirejs({
|
||||
config: './public/res/main.js'
|
||||
}, resolve);
|
||||
})
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* Less
|
||||
*/
|
||||
|
||||
gulp.task('clean-less', function() {
|
||||
return gulp.src('./public/res-min/themes')
|
||||
.pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('less', ['clean-less'], function() {
|
||||
return gulp.src([
|
||||
'./public/res/styles/base.less',
|
||||
'./public/res/themes/*.less'
|
||||
])
|
||||
.pipe(less({
|
||||
compress: true
|
||||
}))
|
||||
.pipe(gulp.dest('./public/res-min/themes/'));
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* Fonts
|
||||
*/
|
||||
|
||||
gulp.task('clean-font', function() {
|
||||
return gulp.src('./public/res-min/font')
|
||||
.pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('copy-font', ['clean-font'], function() {
|
||||
return gulp.src('./public/res/font/*')
|
||||
.pipe(gulp.dest('./public/res-min/font/'));
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* Images
|
||||
*/
|
||||
|
||||
gulp.task('clean-img', function() {
|
||||
return gulp.src('./public/res-min/img')
|
||||
.pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('copy-img', ['clean-img'], function() {
|
||||
return gulp.src('./public/res/img/*')
|
||||
.pipe(gulp.dest('./public/res-min/img/'));
|
||||
});
|
||||
|
||||
/** __________________________________________
|
||||
* cache.manifest
|
||||
*/
|
||||
|
||||
gulp.task('cache-manifest', function() {
|
||||
return gulp.src('./public/cache.manifest')
|
||||
.pipe(replace(/(#Date ).*/, '$1' + Date()))
|
||||
.pipe(inject(gulp.src([
|
||||
'./res-min/**/*.*'
|
||||
], {
|
||||
read: false,
|
||||
cwd: './public'
|
||||
}),
|
||||
{
|
||||
starttag: '# start_inject_resources',
|
||||
endtag: '# end_inject_resources',
|
||||
ignoreExtensions: true,
|
||||
transform: function(filepath) {
|
||||
return filepath.substring(1);
|
||||
}
|
||||
}))
|
||||
.pipe(inject(gulp.src([
|
||||
'./res/bower-libs/MathJax/MathJax.js',
|
||||
'./res/bower-libs/MathJax/config/Safe.js',
|
||||
'./res/bower-libs/MathJax/config/TeX-AMS_SVG.js',
|
||||
'./res/bower-libs/MathJax/images/CloseX-31.png',
|
||||
'./res/bower-libs/MathJax/images/MenuArrow-15.png',
|
||||
'./res/bower-libs/MathJax/jax/output/SVG/jax.js',
|
||||
'./res/bower-libs/MathJax/extensions/**/*.*',
|
||||
'./res/bower-libs/MathJax/jax/element/**/*.*',
|
||||
'./res/bower-libs/MathJax/jax/output/SVG/autoload/**/*.*',
|
||||
'./res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/**/*.*'
|
||||
], {
|
||||
read: false,
|
||||
cwd: './public'
|
||||
}),
|
||||
{
|
||||
starttag: '# start_inject_mathjax',
|
||||
endtag: '# end_inject_mathjax',
|
||||
ignoreExtensions: true,
|
||||
transform: function(filepath) {
|
||||
if(filepath == '/res/bower-libs/MathJax/MathJax.js') {
|
||||
filepath += '?config=TeX-AMS_SVG';
|
||||
}
|
||||
else {
|
||||
filepath += '?rev=2.6.1';
|
||||
}
|
||||
return filepath.substring(1);
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./public/'));
|
||||
});
|
||||
|
||||
gulp.task('clean', [
|
||||
'clean-requirejs',
|
||||
'clean-less',
|
||||
'clean-font',
|
||||
'clean-img'
|
||||
]);
|
||||
gulp.task('default', function(cb) {
|
||||
runSequence([
|
||||
// 'jshint',
|
||||
'requirejs',
|
||||
'less',
|
||||
'copy-font',
|
||||
'copy-img'
|
||||
],
|
||||
'cache-manifest',
|
||||
cb);
|
||||
});
|
||||
|
||||
function bumpTask(importance) {
|
||||
return function() {
|
||||
return gulp.src([
|
||||
'./package.json',
|
||||
'./bower.json'
|
||||
])
|
||||
.pipe(bump({type: importance}))
|
||||
.pipe(gulp.dest('./'));
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('bump-patch', bumpTask('patch'));
|
||||
gulp.task('bump-minor', bumpTask('minor'));
|
||||
gulp.task('bump-major', bumpTask('major'));
|
||||
|
||||
function exec(cmd) {
|
||||
return new Promise (function (resolve, reject) {
|
||||
childProcess.exec(cmd, {cwd: process.cwd()}, function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
util.log(stdout, stderr);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
gulp.task('git-tag', function() {
|
||||
var tag = 'v' + getVersion();
|
||||
util.log('Tagging as: ' + util.colors.cyan(tag));
|
||||
return exec('git add ./public/res-min')
|
||||
.then(function () {
|
||||
return exec('git commit -a -m "Prepare release"');
|
||||
})
|
||||
.then(function () {
|
||||
return exec('git tag -a ' + tag + ' -m "Version ' + getVersion() + '"');
|
||||
})
|
||||
.then(function () {
|
||||
return exec('npm publish');
|
||||
})
|
||||
.then(function () {
|
||||
return exec('git push origin v4 --tags');
|
||||
});
|
||||
});
|
||||
|
||||
function releaseTask(importance) {
|
||||
return function(cb) {
|
||||
runSequence(
|
||||
'bump-' + importance,
|
||||
'default',
|
||||
'git-tag',
|
||||
cb);
|
||||
};
|
||||
}
|
||||
|
||||
gulp.task('patch', releaseTask('patch'));
|
||||
gulp.task('minor', releaseTask('minor'));
|
||||
gulp.task('major', releaseTask('major'));
|
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,4 +0,0 @@
|
||||
StackEdit - The Markdown editor powered by PageDown.
|
||||
|
||||
Copyright 2013 Benoit Schweblin (http://www.benoitschweblin.com)
|
||||
Licensed under an Apache License (http://www.apache.org/licenses/LICENSE-2.0)
|
218
README.md
@ -1,55 +1,191 @@
|
||||
StackEdit
|
||||
=========
|
||||
<h1 align="center" style="text-align:center;">
|
||||
<img src="chrome-app/icon-512.png" width="128" />
|
||||
<br />
|
||||
StackEdit中文版
|
||||
</h1>
|
||||
<p align="center">
|
||||
<strong>笔记利器,在线Markdown编辑器。</strong><br>
|
||||
项目clone自<a href="https://gitee.com/mafgwo/stackedit" target="_blank" title="豆萁">豆萁/stackedit</a>,如果你喜欢该项目,请过去点一下Star,您的肯定是作者最大的动力!
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://stackedit.cn/">https://stackedit.cn</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://www.apache.org/licenses/LICENSE-2.0.txt">
|
||||
<img src="https://img.shields.io/:license-Apache2-blue.svg" alt="Apache 2" />
|
||||
</a>
|
||||
<a target="_blank" href="https://hub.docker.com/r/mafgwo/stackedit">
|
||||
<img src="https://img.shields.io/docker/pulls/mafgwo/stackedit.svg" alt="Docker Pulls" />
|
||||
</a>
|
||||
<a target="_blank" href='https://gitee.com/mafgwo/stackedit/stargazers'>
|
||||
<img src='https://gitee.com/mafgwo/stackedit/badge/star.svg' alt='gitee star'/>
|
||||
</a>
|
||||
</p>
|
||||
<br/>
|
||||
<hr />
|
||||
1 笔记支持Gitee、GitHub、Gitea等Git仓库存储。<br>
|
||||
2 支持直接上传图片,也支持多种外部图床(GitHub、Gitea、SM.MS、自定义图床)粘贴或拖拽上传。<br>
|
||||
3 编辑区域支持选择主题或自定义,总有你喜欢的主题。<br>
|
||||
4 支持历史版本管理,不用担心编辑覆盖后无法回滚。<br>
|
||||
5 支持ChatGPT辅助写作。<br>
|
||||
6 支持KaTeX数学表达式、Mermaid UML图、乐谱等扩展。
|
||||
<hr />
|
||||
|
||||
StackEdit is a full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.
|
||||
## 说明
|
||||
|
||||
Main showcase: https://stackedit.io/.
|
||||
本项目为本人clone修改自用,如果你也喜欢,请至原作者处获取及交流。
|
||||
|
||||
Support StackEdit:
|
||||
## 截图
|
||||
|
||||
[![](https://cdn.monetizejs.com/resources/button-32.png)](https://monetizejs.com/authorize?client_id=ESTHdCYOi18iLhhO&summary=true)
|
||||
**亮暗主题切换、编辑主题切换**
|
||||
![](./images/theme.gif)
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> - Documents are stored in the [browser's local storage][1], which means they are not shared between different browsers/computers. Clearing your browser's data may delete all your local documents.
|
||||
> - Full access to Dropbox or Google Drive is required to be able to import any document in StackEdit. Imported documents are downloaded in your browser and are not transmitted to a server.
|
||||
**支持的文档空间**
|
||||
![](./images/workspace.png)
|
||||
|
||||
### StackEdit can:
|
||||
**拖拽粘贴上传图片**
|
||||
![](./images/uploadimg.gif)
|
||||
|
||||
- Manage multiple Markdown documents online or offline
|
||||
- Export your documents in Markdown, HTML or PDF and format it using a template
|
||||
- Synchronize your Markdown documents in the Cloud
|
||||
- Edit existing Markdown documents from Google Drive, Dropbox and your local hard drive
|
||||
- Post your Markdown document on Blogger/Blogspot, WordPress, Tumblr
|
||||
- Publish your Markdown document on GitHub, Gist, Google Drive, Dropbox or any SSH server
|
||||
- Share a link to a Markdown document that renders it in a nice viewer
|
||||
- Show statistics about your document
|
||||
- Convert HTML to Markdown
|
||||
**支持文档搜索**
|
||||
![](./images/search.gif)
|
||||
|
||||
### Features:
|
||||
**ChatGPT集成协助写作**
|
||||
![](./images/chatgpt.gif)
|
||||
|
||||
- Real-time HTML preview with Scroll Link feature to bind editor and preview scrollbars
|
||||
- Markdown Extra/GitHub Flavored Markdown support and Prettify/Highlight.js syntax highlighting
|
||||
- LaTeX mathematical expressions using MathJax
|
||||
- WYSIWYG control buttons
|
||||
- Configurable layout
|
||||
- Theming support with different themes available
|
||||
- A la carte extensions
|
||||
- Offline editing
|
||||
- Online synchronization using Google Drive (multi-accounts) and Dropbox
|
||||
- One click publish on Blogger, Dropbox, Gist, GitHub, Google Drive, SSH server, Tumblr, WordPress
|
||||
## 相比国外开源版本的区别:
|
||||
|
||||
### Documentation:
|
||||
- 修复了Github授权登录问题
|
||||
- 支持了Gitee仓库(2022-05-25)
|
||||
- 支持了Gitea仓库(2022-05-25)
|
||||
- 汉化(2022-06-01)
|
||||
- 主文档空间从GoogleDrive切换为Gitee(2022-06-04)
|
||||
- 支持SM.MS图床粘贴/拖拽图片自动上传(2022-07-01)
|
||||
- 支持Gitea图床粘贴/拖拽图片自动上传(2022-07-02)
|
||||
- 支持自定义图床粘贴/拖拽图片自动上传(2022-07-04)
|
||||
- 支持GitHub图床粘贴/拖拽图片自动上传(2022-07-31)
|
||||
- 支持了右上角一键切换主题,补全了深色主题的样式(2022-08-07)
|
||||
- 编辑与预览区域样式优化(2022-08-10)
|
||||
- 左边栏文件资源管理支持搜索文件(2022-08-17)
|
||||
- 支持[TOC]目录(2022-09-04)
|
||||
- 发布支持填写提交信息[针对Gitee、GitHub、Gitea、Gitlab](2022-09-10)
|
||||
- 支持文档空间关闭自动同步[针对Gitee、GitHub、Gitea、Gitlab],关闭后可自定义提交信息(2022-09-23)
|
||||
- Gitea支持后端配置指定应用ID和Secret(2022-10-03)
|
||||
- 支持编辑区域选择主题样式(2022-10-06)
|
||||
- 支持图片直接存储到当前文档空间(2022-10-29)
|
||||
- 支持MD文档之间链接跳转(2022-11-20)
|
||||
- 支持预览区域选择主题样式(2022-12-04)
|
||||
- Gitlab的支持优化(2023-02-23)
|
||||
- 导出HTML、PDF支持带预览主题导出(2023-02-26)
|
||||
- 支持分享文档(2023-03-30)
|
||||
- 支持ChatGPT生成内容(2023-04-10)
|
||||
- GitLab授权接口调整(2023-08-26)
|
||||
- 主文档空间支持GitHub登录(2023-10-19)
|
||||
|
||||
- [Hello! document][2]
|
||||
- [Developer guide][3]
|
||||
- [Theming guide][4]
|
||||
## 国外开源版本弊端:
|
||||
|
||||
> **NOTE:** This page has been written and published with [StackEdit][5].
|
||||
- 作者已经不维护了或很少维护了
|
||||
- 不支持国内常用Gitee
|
||||
- 强依赖GoogleDrive,而Google Drive在国内不能正常访问
|
||||
|
||||
## 部署说明
|
||||
|
||||
[1]: https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Storage#localStorage
|
||||
[2]: https://github.com/benweet/stackedit/blob/master/public/res/WELCOME.md#welcome-to-stackedit---welcome "Welcome document"
|
||||
[3]: https://github.com/benweet/stackedit/blob/master/doc/developer-guide.md#developer-guide "Developer guide"
|
||||
[4]: https://github.com/benweet/stackedit/blob/master/doc/theming.md#stackedit-theming-guide "Theming guide"
|
||||
[5]: https://stackedit.io/ "StackEdit"
|
||||
> 建议docker-compose方式部署,其他部署方式如遇到问题欢迎提issue。
|
||||
|
||||
docker官方仓库下载太慢可以使用阿里云的镜像仓库,镜像仓库地址:registry.cn-hangzhou.aliyuncs.com/mafgwo/stackedit:【版本号】
|
||||
|
||||
`docker-compose.yml`如下:
|
||||
|
||||
```yaml
|
||||
version: "3.7"
|
||||
services:
|
||||
stackedit:
|
||||
image: mafgwo/stackedit:【docker中央仓库找到最新版本】
|
||||
container_name: stackedit
|
||||
environment:
|
||||
- LISTENING_PORT=8080
|
||||
- ROOT_URL=/
|
||||
- USER_BUCKET_NAME=root
|
||||
- DROPBOX_APP_KEY=【不需要支持则删掉】
|
||||
- DROPBOX_APP_KEY_FULL=【不需要支持则删掉】
|
||||
- GITHUB_CLIENT_ID=【不需要支持则删掉】
|
||||
- GITHUB_CLIENT_SECRET=【不需要支持则删掉】
|
||||
- GITEE_CLIENT_ID=【不需要支持则删掉】
|
||||
- GITEE_CLIENT_SECRET=【不需要支持则删掉】
|
||||
- GOOGLE_CLIENT_ID=【不需要支持则删掉】
|
||||
- GOOGLE_API_KEY=【不需要支持则删掉】
|
||||
- GITEA_CLIENT_ID=【不需要支持则删掉】
|
||||
- GITEA_CLIENT_SECRET=【不需要支持则删掉】
|
||||
- GITEA_URL=【不需要支持则删掉】
|
||||
- GITLAB_CLIENT_ID=【不需要支持则删掉】
|
||||
- GITLAB_CLIENT_SECRET=【不需要支持则删掉】
|
||||
- GITLAB_URL=【不需要支持则删掉】
|
||||
ports:
|
||||
- 8080:8080/tcp
|
||||
network_mode: bridge
|
||||
restart: always
|
||||
```
|
||||
|
||||
docker-compose方式的启动或停止命令
|
||||
|
||||
```bash
|
||||
# 在 docker-compose.yml 文件目录下 启动命令
|
||||
docker-compose up -d
|
||||
# 在 docker-compose.yml 文件目录下 停止命令
|
||||
docker-compose down
|
||||
# 更新镜像只需要修改docker-compose.yml中镜像版本执行再停止、启动命令即可
|
||||
```
|
||||
|
||||
或者可以直接通过Docker命名直接启动,命令如下:
|
||||
|
||||
```bash
|
||||
docker run -itd --name stackedit \
|
||||
-p 8080:8080 \
|
||||
-e LISTENING_PORT=8080 \
|
||||
-e ROOT_URL=/ \
|
||||
-e USER_BUCKET_NAME=root \
|
||||
-e DROPBOX_APP_KEY=【不需要支持则删掉】 \
|
||||
-e DROPBOX_APP_KEY_FULL=【不需要支持则删掉】 \
|
||||
-e GITHUB_CLIENT_ID=【不需要支持则删掉】 \
|
||||
-e GITHUB_CLIENT_SECRET=【不需要支持则删掉】 \
|
||||
-e GITEE_CLIENT_ID=【不需要支持则删掉】 \
|
||||
-e GITEE_CLIENT_SECRET=【不需要支持则删掉】 \
|
||||
-e GOOGLE_CLIENT_ID=【不需要支持则删掉】 \
|
||||
-e GOOGLE_API_KEY=【不需要支持则删掉】 \
|
||||
-e GITEA_CLIENT_ID=【不需要支持则删掉】 \
|
||||
-e GITEA_CLIENT_SECRET=【不需要支持则删掉】 \
|
||||
-e GITEA_URL=【不需要支持则删掉】 \
|
||||
-e GITLAB_CLIENT_ID=【不需要支持则删掉】 \
|
||||
-e GITLAB_CLIENT_SECRET=【不需要支持则删掉】 \
|
||||
-e GITLAB_URL=【不需要支持则删掉】 \
|
||||
mafgwo/stackedit:【docker中央仓库找到最新版本】
|
||||
|
||||
```
|
||||
|
||||
## 如何创建三方平台应用
|
||||
|
||||
> 部署时,如果需要支持Gitee或GitHub,则需要自行到对应三方平台创建应用,获取到应用ID和秘钥,替换到以上的环境变量中,再启动应用。
|
||||
|
||||
- Gitee的环境变量:GITEE_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建Gitee应用](./docs/部署之Gitee应用创建.md)**
|
||||
- GitHub的环境变量:GITHUB_CLIENT_ID、GITEE_CLIENT_SECRET,**[如何创建GitHub应用](./docs/部署之GitHub应用创建.md)**
|
||||
- Gitea可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITEA_CLIENT_ID、GITEA_CLIENT_SECRET、GITEA_URL,**[如何创建Gitea应用](./docs/部署之Gitea应用创建.md)**
|
||||
- Gitlab可选择性配置环境变量(未配置则在关联时前端指定,有配置则仅允许配置的应用信息):GITLAB_CLIENT_ID、GITLAB_CLIENT_SECRET、GITLAB_URL **如何创建Gitlab应用(待补充文档)**
|
||||
|
||||
(特别说明:自建的Gitea、Gitlab要能接入stackedit必须支持跨域)
|
||||
|
||||
## 编译与运行
|
||||
|
||||
> 编译运行的nodejs版本选择11.15.0版本
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# serve with hot reload at localhost:8080
|
||||
npm start
|
||||
|
||||
# build for production with minification
|
||||
npm run build
|
||||
|
||||
# build for production and view the bundle analyzer report
|
||||
npm run build --report
|
||||
```
|
||||
|
@ -1,20 +0,0 @@
|
||||
var request = require('request');
|
||||
|
||||
exports.importPublic = function(req, res) {
|
||||
var url = req.param('url');
|
||||
if(!url) {
|
||||
res.send(400, 'No URL parameter');
|
||||
}
|
||||
else if(url.indexOf("http://") === 0 || url.indexOf("https://") === 0) {
|
||||
var stream = request.get(url);
|
||||
stream.on('error', function(err) {
|
||||
res.send(400, err);
|
||||
});
|
||||
stream.on('response', function() {
|
||||
stream.pipe(res);
|
||||
});
|
||||
}
|
||||
else {
|
||||
res.send(400, 'Unknown protocol');
|
||||
}
|
||||
};
|
60
app/index.js
@ -1,60 +0,0 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var compression = require('compression');
|
||||
var serveStatic = require('serve-static');
|
||||
|
||||
// Configure ejs engine
|
||||
app.set('views', __dirname + '/../views');
|
||||
app.engine('html', require('ejs').renderFile);
|
||||
|
||||
// Force HTTPS on stackedit.io
|
||||
app.all('*', function(req, res, next) {
|
||||
if (req.headers.host == 'stackedit.io' && !req.secure && req.headers['x-forwarded-proto'] != 'https') {
|
||||
return res.redirect('https://stackedit.io' + req.url);
|
||||
}
|
||||
/\.(eot|ttf|woff|svg)$/.test(req.url) && res.header('Access-Control-Allow-Origin', '*');
|
||||
next();
|
||||
});
|
||||
|
||||
// Use gzip compression
|
||||
app.use(compression());
|
||||
|
||||
app.post('/pdfExport', require('./pdf').export);
|
||||
app.post('/sshPublish', require('./ssh').publish);
|
||||
app.post('/picasaImportImg', require('./picasa').importImg);
|
||||
app.get('/downloadImport', require('./download').importPublic);
|
||||
|
||||
// Serve static resources
|
||||
app.use(serveStatic(__dirname + '/../public'));
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.renderDebug = function(page) {
|
||||
return res.render(page, {
|
||||
cache: !req.query.hasOwnProperty('debug')
|
||||
});
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
||||
// Serve landing.html in /
|
||||
app.get('/', function(req, res) {
|
||||
res.renderDebug('landing.html');
|
||||
});
|
||||
|
||||
// Serve editor.html in /viewer
|
||||
app.get('/editor', function(req, res) {
|
||||
res.renderDebug('editor.html');
|
||||
});
|
||||
|
||||
// Serve viewer.html in /viewer
|
||||
app.get('/viewer', function(req, res) {
|
||||
res.renderDebug('viewer.html');
|
||||
});
|
||||
|
||||
// Error 404
|
||||
app.use(function(req, res) {
|
||||
res.status(404);
|
||||
res.render('error_404.html');
|
||||
});
|
||||
|
||||
module.exports = app;
|
145
app/pdf.js
@ -1,145 +0,0 @@
|
||||
/* global window,MathJax */
|
||||
var spawn = require('child_process').spawn;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var os = require('os');
|
||||
var request = require('request');
|
||||
|
||||
function waitForJavaScript() {
|
||||
if(window.MathJax) {
|
||||
// Amazon EC2: fix TeX font detection
|
||||
MathJax.Hub.Register.StartupHook("HTML-CSS Jax Startup",function () {
|
||||
var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
|
||||
HTMLCSS.Font.checkWebFont = function (check,font,callback) {
|
||||
if (check.time(callback)) {
|
||||
return;
|
||||
}
|
||||
if (check.total === 0) {
|
||||
HTMLCSS.Font.testFont(font);
|
||||
setTimeout(check,200);
|
||||
} else {
|
||||
callback(check.STATUS.OK);
|
||||
}
|
||||
};
|
||||
});
|
||||
MathJax.Hub.Queue(function () {
|
||||
window.status = 'done';
|
||||
});
|
||||
}
|
||||
else {
|
||||
setTimeout(function() {
|
||||
window.status = 'done';
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
var authorizedPageSizes = [
|
||||
'A3',
|
||||
'A4',
|
||||
'Legal',
|
||||
'Letter'
|
||||
];
|
||||
|
||||
exports.export = function(req, res, next) {
|
||||
function onError(err) {
|
||||
next(err);
|
||||
}
|
||||
function onUnknownError() {
|
||||
res.statusCode = 400;
|
||||
res.end('Unknown error');
|
||||
}
|
||||
function onUnauthorizedError() {
|
||||
res.statusCode = 401;
|
||||
res.end('Unauthorized');
|
||||
}
|
||||
function onTimeout() {
|
||||
res.statusCode = 408;
|
||||
res.end('Request timeout');
|
||||
}
|
||||
request({
|
||||
uri: 'https://monetizejs.com/api/payments',
|
||||
qs: {
|
||||
access_token: req.query.token
|
||||
},
|
||||
json: true
|
||||
}, function (err, paymentsRes, payments) {
|
||||
var authorized = payments && payments.app == 'ESTHdCYOi18iLhhO' && (
|
||||
(payments.chargeOption && payments.chargeOption.alias == 'once') ||
|
||||
(payments.subscriptionOption && payments.subscriptionOption.alias == 'yearly'));
|
||||
if(err || paymentsRes.statusCode != 200 || !authorized) {
|
||||
return onUnauthorizedError();
|
||||
}
|
||||
var options, params = [];
|
||||
try {
|
||||
options = JSON.parse(req.query.options);
|
||||
}
|
||||
catch(e) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
// Margins
|
||||
var marginTop = parseInt(options.marginTop);
|
||||
params.push('-T', isNaN(marginTop) ? 25 : marginTop);
|
||||
var marginRight = parseInt(options.marginRight);
|
||||
params.push('-R', isNaN(marginRight) ? 25 : marginRight);
|
||||
var marginBottom = parseInt(options.marginBottom);
|
||||
params.push('-B', isNaN(marginBottom) ? 25 : marginBottom);
|
||||
var marginLeft = parseInt(options.marginLeft);
|
||||
params.push('-L', isNaN(marginLeft) ? 25 : marginLeft);
|
||||
|
||||
// Header
|
||||
options.headerCenter && params.push('--header-center', options.headerCenter);
|
||||
options.headerLeft && params.push('--header-left', options.headerLeft);
|
||||
options.headerRight && params.push('--header-right', options.headerRight);
|
||||
options.headerFontName && params.push('--header-font-name', options.headerFontName);
|
||||
options.headerFontSize && params.push('--header-font-size', options.headerFontSize);
|
||||
|
||||
// Footer
|
||||
options.footerCenter && params.push('--footer-center', options.footerCenter);
|
||||
options.footerLeft && params.push('--footer-left', options.footerLeft);
|
||||
options.footerRight && params.push('--footer-right', options.footerRight);
|
||||
options.footerFontName && params.push('--footer-font-name', options.footerFontName);
|
||||
options.footerFontSize && params.push('--footer-font-size', options.footerFontSize);
|
||||
|
||||
// Page size
|
||||
params.push('--page-size', authorizedPageSizes.indexOf(options.pageSize) === -1 ? 'A4' : options.pageSize);
|
||||
|
||||
// Use a temp file as wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason
|
||||
var filePath = path.join(os.tmpDir(), Date.now() + '.pdf');
|
||||
var binPath = process.env.WKHTMLTOPDF_PATH || 'wkhtmltopdf';
|
||||
params.push('--run-script', waitForJavaScript.toString() + 'waitForJavaScript()');
|
||||
params.push('--window-status', 'done');
|
||||
var wkhtmltopdf = spawn(binPath, params.concat('-', filePath), {
|
||||
stdio: [
|
||||
'pipe',
|
||||
'ignore',
|
||||
'ignore'
|
||||
]
|
||||
});
|
||||
var timeoutId = setTimeout(function() {
|
||||
timeoutId = undefined;
|
||||
wkhtmltopdf.kill();
|
||||
}, 30000);
|
||||
wkhtmltopdf.on('error', onError);
|
||||
wkhtmltopdf.stdin.on('error', onError);
|
||||
wkhtmltopdf.on('close', function(code) {
|
||||
if(!timeoutId) {
|
||||
return onTimeout();
|
||||
}
|
||||
clearTimeout(timeoutId);
|
||||
if(code) {
|
||||
return onUnknownError();
|
||||
}
|
||||
var readStream = fs.createReadStream(filePath);
|
||||
readStream.on('open', function() {
|
||||
readStream.pipe(res);
|
||||
});
|
||||
readStream.on('close', function() {
|
||||
fs.unlink(filePath, function() {
|
||||
});
|
||||
});
|
||||
readStream.on('error', onUnknownError);
|
||||
});
|
||||
req.pipe(wkhtmltopdf.stdin);
|
||||
});
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
var request = require('request');
|
||||
|
||||
exports.importImg = function(req, res) {
|
||||
var stream = req.pipe(request.post({
|
||||
uri: 'https://picasaweb.google.com/data/feed/api/user/default/albumid/' + req.query.albumId,
|
||||
headers: {
|
||||
'Authorization': req.headers.authorization,
|
||||
'Content-Type': req.headers['content-type'],
|
||||
'Slug': req.headers.slug
|
||||
}
|
||||
}));
|
||||
stream.on('error', function(err) {
|
||||
res.send(400, err);
|
||||
});
|
||||
stream.pipe(res);
|
||||
};
|
62
app/ssh.js
@ -1,62 +0,0 @@
|
||||
var ssh2 = require('ssh2');
|
||||
|
||||
exports.publish = function(req, res) {
|
||||
var done;
|
||||
function sendResult(result) {
|
||||
if(!done) {
|
||||
res.json(result);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
function sendError(error) {
|
||||
sendResult({error: error});
|
||||
}
|
||||
|
||||
var conn = new ssh2();
|
||||
conn.on('ready', function() {
|
||||
conn.sftp(function(err, sftp) {
|
||||
if(err) {
|
||||
return sendError('Unable to establish SFTP connection');
|
||||
}
|
||||
|
||||
var writeStream = sftp.createWriteStream(req.query.path);
|
||||
|
||||
writeStream.on('close', function() {
|
||||
sftp.end();
|
||||
conn.end();
|
||||
});
|
||||
|
||||
writeStream.on('error', function() {
|
||||
sendError('Unable to write "' + req.query.path + '"');
|
||||
sftp.end();
|
||||
conn.end();
|
||||
});
|
||||
|
||||
req.pipe(writeStream);
|
||||
});
|
||||
});
|
||||
|
||||
conn.on('error', function(err) {
|
||||
if(err.level == "authentication") {
|
||||
return sendError('Authentication failure');
|
||||
}
|
||||
if(err.code == "ENOTFOUND") {
|
||||
return sendError('Host not found');
|
||||
}
|
||||
if(err.code == "ETIMEDOUT") {
|
||||
return sendError('Connection timeout');
|
||||
}
|
||||
sendError(err);
|
||||
});
|
||||
|
||||
conn.on('end', function() {
|
||||
sendResult({});
|
||||
});
|
||||
|
||||
conn.connect({
|
||||
host: req.query.host,
|
||||
port: req.query.port || 22,
|
||||
username: req.query.username,
|
||||
password: req.query.password
|
||||
});
|
||||
};
|
42
bower.json
@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "stackedit",
|
||||
"version": "4.3.22",
|
||||
"description": "StackEdit is a free, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.",
|
||||
"dependencies": {
|
||||
"bootstrap": "3.0.3",
|
||||
"jquery": "2.0.3",
|
||||
"underscore": "1.5.1",
|
||||
"requirejs": "~2.1.11",
|
||||
"require-css": "0.1.5",
|
||||
"require-less": "0.1.2",
|
||||
"mousetrap": "~1.4.4",
|
||||
"jgrowl": "~1.2.10",
|
||||
"google-code-prettify": "~1.0.0",
|
||||
"FileSaver": "*",
|
||||
"stacktrace": "~0.6.2",
|
||||
"requirejs-text": "~2.0.10",
|
||||
"bootstrap-tour": "~0.7.1",
|
||||
"pagedown-extra": "https://github.com/jmcmanus/pagedown-extra.git#ea782c3d11eb78f57d00aa819527338996a70721",
|
||||
"crel": "https://github.com/KoryNunn/crel.git#8dbda04b129fc0aec01a2a080d1cab26816e11c1",
|
||||
"waitForImages": "https://github.com/alexanderdickson/waitForImages.git#~1.4.2",
|
||||
"to-markdown": "https://github.com/benweet/to-markdown.git#jquery",
|
||||
"xregexp": "300157f34b39b15b7b0dba7608955945d53e61b9",
|
||||
"yaml.js": "https://github.com/jeremyfa/yaml.js.git#~0.1.4",
|
||||
"prism": "a12e8692b5f660a0123a06f74935f75386a93042",
|
||||
"MutationObservers": "https://github.com/Polymer/MutationObservers.git#~0.2.1",
|
||||
"rangy": "1.2.3",
|
||||
"google-diff-match-patch-js": "~1.0.0",
|
||||
"jsondiffpatch": "https://github.com/benweet/jsondiffpatch.git#fb9dddf7cd076d8ec89d376c0e9de9223e9888f9",
|
||||
"hammerjs": "~1.0.10",
|
||||
"raphael": "~2.1.2",
|
||||
"js-sequence-diagrams": "https://github.com/benweet/js-sequence-diagrams.git#c59e2e39d9185e9291f37b73fc596eba5ed33650",
|
||||
"flowchart": "https://github.com/adrai/flowchart.js.git#751717d3db6437def9a5f8b1cb73e8bb81b5833a",
|
||||
"monetizejs": "~0.2.0",
|
||||
"MathJax": "2.6.1",
|
||||
"alertify.js": "https://github.com/fabien-d/alertify.js.git#fc2e06fa39873363dda199204b8544119ab060bf"
|
||||
},
|
||||
"main": [
|
||||
"/public/res/main.js",
|
||||
"/public/res/styles/jquery.jgrowl.css"
|
||||
]
|
||||
}
|
37
build.sh
Normal file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 检查参数是否提供版本号
|
||||
if [ -z "$1" ]; then
|
||||
echo "请提供版本号作为参数"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 定义版本号变量
|
||||
VERSION="$1"
|
||||
IMAGE_NAME="mafgwo/stackedit"
|
||||
|
||||
# 构建 Docker 镜像
|
||||
build_image() {
|
||||
docker build -t "$IMAGE_NAME" .
|
||||
}
|
||||
|
||||
# 标记 Docker 镜像
|
||||
tag_image() {
|
||||
docker tag "$IMAGE_NAME" "$IMAGE_NAME:$VERSION"
|
||||
docker tag "$IMAGE_NAME" "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME:$VERSION"
|
||||
}
|
||||
|
||||
# 推送 Docker 镜像
|
||||
push_image() {
|
||||
docker push "$IMAGE_NAME"
|
||||
docker push "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME"
|
||||
docker push "$IMAGE_NAME:$VERSION"
|
||||
docker push "registry.cn-hangzhou.aliyuncs.com/$IMAGE_NAME:$VERSION"
|
||||
}
|
||||
|
||||
# 执行构建、标记和推送
|
||||
build_image
|
||||
tag_image
|
||||
push_image
|
||||
|
||||
echo "操作完成"
|
35
build/build.js
Normal file
@ -0,0 +1,35 @@
|
||||
require('./check-versions')()
|
||||
|
||||
process.env.NODE_ENV = 'production'
|
||||
|
||||
var ora = require('ora')
|
||||
var rm = require('rimraf')
|
||||
var path = require('path')
|
||||
var chalk = require('chalk')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var webpackConfig = require('./webpack.prod.conf')
|
||||
|
||||
var spinner = ora('building for production...')
|
||||
spinner.start()
|
||||
|
||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||
if (err) throw err
|
||||
webpack(webpackConfig, function (err, stats) {
|
||||
spinner.stop()
|
||||
if (err) throw err
|
||||
process.stdout.write(stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n')
|
||||
|
||||
console.log(chalk.cyan(' Build complete.\n'))
|
||||
console.log(chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
' Opening index.html over file:// won\'t work.\n'
|
||||
))
|
||||
})
|
||||
})
|
48
build/check-versions.js
Normal file
@ -0,0 +1,48 @@
|
||||
var chalk = require('chalk')
|
||||
var semver = require('semver')
|
||||
var packageConfig = require('../package.json')
|
||||
var shell = require('shelljs')
|
||||
function exec (cmd) {
|
||||
return require('child_process').execSync(cmd).toString().trim()
|
||||
}
|
||||
|
||||
var versionRequirements = [
|
||||
{
|
||||
name: 'node',
|
||||
currentVersion: semver.clean(process.version),
|
||||
versionRequirement: packageConfig.engines.node
|
||||
},
|
||||
]
|
||||
|
||||
if (shell.which('npm')) {
|
||||
versionRequirements.push({
|
||||
name: 'npm',
|
||||
currentVersion: exec('npm --version'),
|
||||
versionRequirement: packageConfig.engines.npm
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
var warnings = []
|
||||
for (var i = 0; i < versionRequirements.length; i++) {
|
||||
var mod = versionRequirements[i]
|
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||
warnings.push(mod.name + ': ' +
|
||||
chalk.red(mod.currentVersion) + ' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
console.log('')
|
||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||
console.log()
|
||||
for (var i = 0; i < warnings.length; i++) {
|
||||
var warning = warnings[i]
|
||||
console.log(' ' + warning)
|
||||
}
|
||||
console.log()
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
24
build/deploy.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Tag and push docker image
|
||||
docker login -u benweet -p "$DOCKER_PASSWORD"
|
||||
docker tag benweet/stackedit "benweet/stackedit:$TRAVIS_TAG"
|
||||
docker push benweet/stackedit:$TRAVIS_TAG
|
||||
docker tag benweet/stackedit:$TRAVIS_TAG benweet/stackedit:latest
|
||||
docker push benweet/stackedit:latest
|
||||
|
||||
# Build the chart
|
||||
cd "$TRAVIS_BUILD_DIR"
|
||||
npm run chart
|
||||
|
||||
# Add chart to helm repository
|
||||
git clone --branch master "https://benweet:$GITHUB_TOKEN@github.com/benweet/stackedit-charts.git" /tmp/charts
|
||||
cd /tmp/charts
|
||||
helm package "$TRAVIS_BUILD_DIR/dist/stackedit"
|
||||
helm repo index --url https://benweet.github.io/stackedit-charts/ .
|
||||
git config user.name "Benoit Schweblin"
|
||||
git config user.email "benoit.schweblin@gmail.com"
|
||||
git add .
|
||||
git commit -m "Added $TRAVIS_TAG"
|
||||
git push origin master
|
9
build/dev-client.js
Normal file
@ -0,0 +1,9 @@
|
||||
/* eslint-disable */
|
||||
require('eventsource-polyfill')
|
||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
||||
|
||||
hotClient.subscribe(function (event) {
|
||||
if (event.action === 'reload') {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
94
build/dev-server.js
Normal file
@ -0,0 +1,94 @@
|
||||
require('./check-versions')()
|
||||
|
||||
var config = require('../config')
|
||||
Object.keys(config.dev.env).forEach((key) => {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = JSON.parse(config.dev.env[key]);
|
||||
}
|
||||
});
|
||||
|
||||
var opn = require('opn')
|
||||
var path = require('path')
|
||||
var express = require('express')
|
||||
var webpack = require('webpack')
|
||||
var proxyMiddleware = require('http-proxy-middleware')
|
||||
var webpackConfig = require('./webpack.dev.conf')
|
||||
|
||||
// default port where dev server listens for incoming traffic
|
||||
var port = process.env.PORT || config.dev.port
|
||||
// automatically open browser, if not set will be false
|
||||
var autoOpenBrowser = !!config.dev.autoOpenBrowser
|
||||
// Define HTTP proxies to your custom API backend
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
var proxyTable = config.dev.proxyTable
|
||||
|
||||
var app = express()
|
||||
var compiler = webpack(webpackConfig)
|
||||
|
||||
// StackEdit custom middlewares
|
||||
require('../server')(app);
|
||||
|
||||
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
quiet: true
|
||||
})
|
||||
|
||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
||||
log: () => {}
|
||||
})
|
||||
// force page reload when html-webpack-plugin template changes
|
||||
compiler.plugin('compilation', function (compilation) {
|
||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
// proxy api requests
|
||||
Object.keys(proxyTable).forEach(function (context) {
|
||||
var options = proxyTable[context]
|
||||
if (typeof options === 'string') {
|
||||
options = { target: options }
|
||||
}
|
||||
app.use(proxyMiddleware(options.filter || context, options))
|
||||
})
|
||||
|
||||
// handle fallback for HTML5 history API
|
||||
app.use(require('connect-history-api-fallback')())
|
||||
|
||||
// serve webpack bundle output
|
||||
app.use(devMiddleware)
|
||||
|
||||
// enable hot-reload and state-preserving
|
||||
// compilation error display
|
||||
app.use(hotMiddleware)
|
||||
|
||||
// serve pure static assets
|
||||
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
|
||||
app.use(staticPath, express.static('./static'))
|
||||
|
||||
var uri = 'http://localhost:' + port
|
||||
|
||||
var _resolve
|
||||
var readyPromise = new Promise(resolve => {
|
||||
_resolve = resolve
|
||||
})
|
||||
|
||||
console.log('> Starting dev server...')
|
||||
devMiddleware.waitUntilValid(() => {
|
||||
console.log('> Listening at ' + uri + '\n')
|
||||
// when env is testing, don't need open it
|
||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
|
||||
opn(uri)
|
||||
}
|
||||
_resolve()
|
||||
})
|
||||
|
||||
var server = app.listen(port)
|
||||
|
||||
module.exports = {
|
||||
ready: readyPromise,
|
||||
close: () => {
|
||||
server.close()
|
||||
}
|
||||
}
|
71
build/utils.js
Normal file
@ -0,0 +1,71 @@
|
||||
var path = require('path')
|
||||
var config = require('../config')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
|
||||
exports.assetsPath = function (_path) {
|
||||
var assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
return path.posix.join(assetsSubDirectory, _path)
|
||||
}
|
||||
|
||||
exports.cssLoaders = function (options) {
|
||||
options = options || {}
|
||||
|
||||
var cssLoader = {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
minimize: process.env.NODE_ENV === 'production',
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loader, loaderOptions) {
|
||||
var loaders = [cssLoader]
|
||||
if (loader) {
|
||||
loaders.push({
|
||||
loader: loader + '-loader',
|
||||
options: Object.assign({}, loaderOptions, {
|
||||
sourceMap: options.sourceMap
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: loaders,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
} else {
|
||||
return ['vue-style-loader'].concat(loaders)
|
||||
}
|
||||
}
|
||||
|
||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(),
|
||||
postcss: generateLoaders(),
|
||||
less: generateLoaders('less'),
|
||||
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||
scss: generateLoaders('sass'),
|
||||
stylus: generateLoaders('stylus'),
|
||||
styl: generateLoaders('stylus')
|
||||
}
|
||||
}
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function (options) {
|
||||
var output = []
|
||||
var loaders = exports.cssLoaders(options)
|
||||
for (var extension in loaders) {
|
||||
var loader = loaders[extension]
|
||||
output.push({
|
||||
test: new RegExp('\\.' + extension + '$'),
|
||||
use: loader
|
||||
})
|
||||
}
|
||||
return output
|
||||
}
|
12
build/vue-loader.conf.js
Normal file
@ -0,0 +1,12 @@
|
||||
var utils = require('./utils')
|
||||
var config = require('../config')
|
||||
var isProduction = process.env.NODE_ENV === 'production'
|
||||
|
||||
module.exports = {
|
||||
loaders: utils.cssLoaders({
|
||||
sourceMap: isProduction
|
||||
? config.build.productionSourceMap
|
||||
: config.dev.cssSourceMap,
|
||||
extract: isProduction
|
||||
})
|
||||
}
|
109
build/webpack.base.conf.js
Normal file
@ -0,0 +1,109 @@
|
||||
var path = require('path')
|
||||
var webpack = require('webpack')
|
||||
var utils = require('./utils')
|
||||
var config = require('../config')
|
||||
var VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
var vueLoaderConfig = require('./vue-loader.conf')
|
||||
var StylelintPlugin = require('stylelint-webpack-plugin')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/'
|
||||
},
|
||||
node: {
|
||||
// For mermaid
|
||||
fs: 'empty' // jison generated code requires 'fs'
|
||||
},
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath: process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'@': resolve('src')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|vue)$/,
|
||||
loader: 'eslint-loader',
|
||||
enforce: 'pre',
|
||||
include: [resolve('src'), resolve('test')],
|
||||
options: {
|
||||
formatter: require('eslint-friendly-formatter')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: vueLoaderConfig
|
||||
},
|
||||
// We can't pass graphlibrary to babel
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'string-replace-loader',
|
||||
include: [
|
||||
resolve('node_modules/graphlibrary')
|
||||
],
|
||||
options: {
|
||||
search: '^\\s*(?:let|const) ',
|
||||
replace: 'var ',
|
||||
flags: 'gm'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: [
|
||||
resolve('src'),
|
||||
resolve('test'),
|
||||
resolve('node_modules/mermaid')
|
||||
],
|
||||
exclude: [
|
||||
resolve('node_modules/mermaid/src/diagrams/class/parser'),
|
||||
resolve('node_modules/mermaid/src/diagrams/flowchart/parser'),
|
||||
resolve('node_modules/mermaid/src/diagrams/gantt/parser'),
|
||||
resolve('node_modules/mermaid/src/diagrams/git/parser'),
|
||||
resolve('node_modules/mermaid/src/diagrams/sequence/parser')
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|otf|woff2?)(\?.*)?$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(md|yml|html)$/,
|
||||
loader: 'raw-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new StylelintPlugin({
|
||||
files: ['**/*.vue', '**/*.scss']
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
VERSION: JSON.stringify(require('../package.json').version)
|
||||
})
|
||||
]
|
||||
}
|
35
build/webpack.dev.conf.js
Normal file
@ -0,0 +1,35 @@
|
||||
var utils = require('./utils')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var merge = require('webpack-merge')
|
||||
var baseWebpackConfig = require('./webpack.base.conf')
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
// add hot-reload related code to entry chunks
|
||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
||||
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
|
||||
})
|
||||
|
||||
module.exports = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
NODE_ENV: config.dev.env.NODE_ENV
|
||||
}),
|
||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'index.html',
|
||||
inject: true
|
||||
}),
|
||||
new FriendlyErrorsPlugin()
|
||||
]
|
||||
})
|
154
build/webpack.prod.conf.js
Normal file
@ -0,0 +1,154 @@
|
||||
var path = require('path')
|
||||
var utils = require('./utils')
|
||||
var webpack = require('webpack')
|
||||
var config = require('../config')
|
||||
var merge = require('webpack-merge')
|
||||
var baseWebpackConfig = require('./webpack.base.conf')
|
||||
var CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
var OfflinePlugin = require('offline-plugin');
|
||||
var WebpackPwaManifest = require('webpack-pwa-manifest')
|
||||
var FaviconsWebpackPlugin = require('favicons-webpack-plugin')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
var env = config.build.env
|
||||
|
||||
var webpackConfig = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true
|
||||
})
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
NODE_ENV: env.NODE_ENV,
|
||||
GOOGLE_CLIENT_ID: env.GOOGLE_CLIENT_ID,
|
||||
GITHUB_CLIENT_ID: env.GITHUB_CLIENT_ID
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
},
|
||||
sourceMap: true
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash].css')
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: {
|
||||
safe: true
|
||||
}
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: config.build.index,
|
||||
template: 'index.html',
|
||||
inject: true,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
}),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks: function (module, count) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
)
|
||||
}
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
chunks: ['vendor']
|
||||
}),
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.resolve(__dirname, '../static'),
|
||||
to: config.build.assetsSubDirectory,
|
||||
ignore: ['.*']
|
||||
}
|
||||
]),
|
||||
new FaviconsWebpackPlugin({
|
||||
logo: resolve('src/assets/favicon.png'),
|
||||
title: 'StackEdit',
|
||||
}),
|
||||
new WebpackPwaManifest({
|
||||
name: 'StackEdit',
|
||||
description: 'Full-featured, open-source Markdown editor',
|
||||
display: 'standalone',
|
||||
orientation: 'any',
|
||||
start_url: 'app',
|
||||
background_color: '#ffffff',
|
||||
crossorigin: 'use-credentials',
|
||||
icons: [{
|
||||
src: resolve('src/assets/favicon.png'),
|
||||
sizes: [96, 128, 192, 256, 384, 512]
|
||||
}]
|
||||
}),
|
||||
new OfflinePlugin({
|
||||
ServiceWorker: {
|
||||
events: true
|
||||
},
|
||||
AppCache: true,
|
||||
excludes: ['**/.*', '**/*.map', '**/index.html', '**/static/oauth2/callback.html', '**/icons-*/*.png', '**/static/fonts/KaTeX_*'],
|
||||
externals: ['/', '/app', '/oauth2/callback']
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
var CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new CompressionWebpackPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(
|
||||
'\\.(' +
|
||||
config.build.productionGzipExtensions.join('|') +
|
||||
')$'
|
||||
),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
56
build/webpack.style.conf.js
Normal file
@ -0,0 +1,56 @@
|
||||
var path = require('path')
|
||||
var utils = require('./utils')
|
||||
var webpack = require('webpack')
|
||||
var utils = require('./utils')
|
||||
var config = require('../config')
|
||||
var vueLoaderConfig = require('./vue-loader.conf')
|
||||
var StylelintPlugin = require('stylelint-webpack-plugin')
|
||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
style: './src/styles/'
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.(ttf|eot|otf|woff2?)(\?.*)?$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
}]
|
||||
.concat(utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true
|
||||
})),
|
||||
},
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath: config.build.assetsPublicPath
|
||||
},
|
||||
plugins: [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false
|
||||
},
|
||||
sourceMap: true
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: '[name].css',
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: {
|
||||
safe: true
|
||||
}
|
||||
}),
|
||||
]
|
||||
}
|
22
chart/.helmignore
Normal file
@ -0,0 +1,22 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
5
chart/Chart.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: v1
|
||||
appVersion: vSTACKEDIT_VERSION
|
||||
description: In-browser Markdown editor
|
||||
name: stackedit
|
||||
version: STACKEDIT_VERSION
|
21
chart/templates/NOTES.txt
Normal file
@ -0,0 +1,21 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "stackedit.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "stackedit.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "stackedit.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "stackedit.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
45
chart/templates/_helpers.tpl
Normal file
@ -0,0 +1,45 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "stackedit.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "stackedit.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "stackedit.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "stackedit.labels" -}}
|
||||
app.kubernetes.io/name: {{ include "stackedit.name" . }}
|
||||
helm.sh/chart: {{ include "stackedit.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
87
chart/templates/deployment.yaml
Normal file
@ -0,0 +1,87 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "stackedit.fullname" . }}
|
||||
labels:
|
||||
{{ include "stackedit.labels" . | indent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "stackedit.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "stackedit.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
volumeMounts:
|
||||
- mountPath: /run
|
||||
name: run-volume
|
||||
- mountPath: /tmp
|
||||
name: tmp-volume
|
||||
env:
|
||||
- name: PORT
|
||||
value: "80"
|
||||
- name: PAYPAL_RECEIVER_EMAIL
|
||||
value: {{ .Values.paypalReceiverEmail }}
|
||||
- name: AWS_ACCESS_KEY_ID
|
||||
value: {{ .Values.awsAccessKeyId }}
|
||||
- name: AWS_SECRET_ACCESS_KEY
|
||||
value: {{ .Values.awsSecretAccessKey }}
|
||||
- name: DROPBOX_APP_KEY
|
||||
value: {{ .Values.dropboxAppKey }}
|
||||
- name: DROPBOX_APP_KEY_FULL
|
||||
value: {{ .Values.dropboxAppKeyFull }}
|
||||
- name: GOOGLE_CLIENT_ID
|
||||
value: {{ .Values.googleClientId }}
|
||||
- name: GOOGLE_API_KEY
|
||||
value: {{ .Values.googleApiKey }}
|
||||
- name: GITHUB_CLIENT_ID
|
||||
value: {{ .Values.githubClientId }}
|
||||
- name: GITHUB_CLIENT_SECRET
|
||||
value: {{ .Values.githubClientSecret }}
|
||||
- name: WORDPRESS_CLIENT_ID
|
||||
value: {{ .Values.wordpressClientId }}
|
||||
- name: WORDPRESS_SECRET
|
||||
value: {{ .Values.wordpressSecret }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: run-volume
|
||||
emptyDir: {}
|
||||
- name: tmp-volume
|
||||
emptyDir: {}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
39
chart/templates/ingress.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "stackedit.fullname" . -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{ include "stackedit.labels" . | indent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ . }}
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
name: http
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
16
chart/templates/service.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "stackedit.fullname" . }}
|
||||
labels:
|
||||
{{ include "stackedit.labels" . | indent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "stackedit.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
15
chart/templates/tests/test-connection.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "stackedit.fullname" . }}-test-connection"
|
||||
labels:
|
||||
{{ include "stackedit.labels" . | indent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test-success
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "stackedit.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
71
chart/values.yaml
Normal file
@ -0,0 +1,71 @@
|
||||
# Default values for stackedit.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
dropboxAppKey: ""
|
||||
dropboxAppKeyFull: ""
|
||||
googleClientId: ""
|
||||
googleApiKey: ""
|
||||
githubClientId: ""
|
||||
githubClientSecret: ""
|
||||
giteeClientId: ""
|
||||
giteeClientSecret: ""
|
||||
wordpressClientId: ""
|
||||
wordpressSecret: ""
|
||||
paypalReceiverEmail: ""
|
||||
awsAccessKeyId: ""
|
||||
awsSecretAccessKey: ""
|
||||
giteaClientId: ""
|
||||
giteaClientSecret: ""
|
||||
giteaUrl: ""
|
||||
gitlabClientId: ""
|
||||
gitlabUrl: ""
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: benweet/stackedit
|
||||
tag: vSTACKEDIT_VERSION
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations:
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# certmanager.k8s.io/issuer: letsencrypt-prod
|
||||
# certmanager.k8s.io/acme-challenge-type: http01
|
||||
hosts: []
|
||||
# - host: stackedit.example.com
|
||||
# paths:
|
||||
# - /
|
||||
|
||||
tls: []
|
||||
# - secretName: stackedit-tls
|
||||
# hosts:
|
||||
# - stackedit.example.com
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
BIN
chrome-app/icon-128.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
chrome-app/icon-16.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
chrome-app/icon-256.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
chrome-app/icon-32.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
chrome-app/icon-512.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
chrome-app/icon-64.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 2.9 KiB |
@ -1,23 +1,28 @@
|
||||
{
|
||||
"name": "StackEdit",
|
||||
"description": "In-browser markdown editor",
|
||||
"version": "1.0.10",
|
||||
"manifest_version": 2,
|
||||
"container" : "GOOGLE_DRIVE",
|
||||
"api_console_project_id" : "241271498917",
|
||||
"icons": {
|
||||
"128": "logo-128.png"
|
||||
},
|
||||
"app": {
|
||||
"urls": [
|
||||
"https://stackedit.io/"
|
||||
],
|
||||
"launch": {
|
||||
"web_url": "https://stackedit.io/editor"
|
||||
}
|
||||
},
|
||||
"offline_enabled": true,
|
||||
"permissions": [
|
||||
"unlimitedStorage"
|
||||
]
|
||||
}
|
||||
"name": "StackEdit中文版",
|
||||
"description": "支持Gitee仓库/粘贴图片自动上传的浏览器内 Markdown 编辑器",
|
||||
"version": "5.15.17",
|
||||
"manifest_version": 2,
|
||||
"container": "GITEE",
|
||||
"api_console_project_id": "241271498917",
|
||||
"icons": {
|
||||
"16": "icon-16.png",
|
||||
"32": "icon-32.png",
|
||||
"64": "icon-64.png",
|
||||
"128": "icon-128.png",
|
||||
"256": "icon-256.png",
|
||||
"512": "icon-512.png"
|
||||
},
|
||||
"app": {
|
||||
"urls": [
|
||||
"https://md.jonylee.top/"
|
||||
],
|
||||
"launch": {
|
||||
"web_url": "https://md.jonylee.top/app"
|
||||
}
|
||||
},
|
||||
"offline_enabled": true,
|
||||
"permissions": [
|
||||
"unlimitedStorage"
|
||||
]
|
||||
}
|
18
config/dev.env.js
Normal file
@ -0,0 +1,18 @@
|
||||
var merge = require('webpack-merge')
|
||||
var prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
// 以下配置是开发临时用的配置 随时可能失效 请替换为自己的
|
||||
GITHUB_CLIENT_ID: '"845b8f75df48f2ee0563"',
|
||||
GITHUB_CLIENT_SECRET: '"80df676597abded1450926861965cc3f9bead6a0"',
|
||||
GITEE_CLIENT_ID: '"925ba7c78b85dec984f7877e4aca5cab10ae333c6d68e761bdb0b9dfb8f55672"',
|
||||
GITEE_CLIENT_SECRET: '"f05731066e42d307339dc8ebbb037a103881dafc7207a359a393b87749f1c562"',
|
||||
CLIENT_ID: '"thF3qCGLN39OtafjGnqHyj6n02WwE6xD"',
|
||||
// GITEA_CLIENT_ID: '"fe30f8f9-b1e8-4531-8f72-c1a5d3912805"',
|
||||
// GITEA_CLIENT_SECRET: '"lus7oMnb3H6M1hsChndphArE20Txr7erwJLf7SDBQWTw"',
|
||||
// GITEA_URL: '"https://gitea.test.com"',
|
||||
GITLAB_CLIENT_ID: '"074cd5103c62dea0f479dac861039656ac80935e304c8113a02cc64c629496ae"',
|
||||
GITLAB_CLIENT_SECRET: '"6f406f24216b686d55d28313dec1913c2a8e599afdb08380d5e8ce838e16e41e"',
|
||||
GITLAB_URL: '"http://gitlab.qicoder.com"',
|
||||
})
|
39
config/index.js
Normal file
@ -0,0 +1,39 @@
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
var path = require('path')
|
||||
|
||||
module.exports = {
|
||||
build: {
|
||||
env: require('./prod.env'),
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
productionSourceMap: true,
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
},
|
||||
dev: {
|
||||
env: require('./dev.env'),
|
||||
port: 80,
|
||||
autoOpenBrowser: false,
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
proxyTable: {},
|
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
// cssSourceMap: false
|
||||
cssSourceMap: true
|
||||
}
|
||||
}
|
3
config/prod.env.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
180
couchdb/setup.js
@ -1,180 +0,0 @@
|
||||
var validate = function(newDoc) {
|
||||
Object.keys(newDoc).forEach(function(key) {
|
||||
if(key[0] !== '_' && [
|
||||
'updated',
|
||||
'tags',
|
||||
'title'
|
||||
].indexOf(key) === -1) {
|
||||
throw({forbidden: 'Unknown document attribute: ' + key});
|
||||
}
|
||||
});
|
||||
var toString = Object.prototype.toString;
|
||||
if(toString.call(newDoc._id) !== '[object String]') {
|
||||
throw({forbidden: 'ID must be a string.'});
|
||||
}
|
||||
if(!newDoc._id.match(/[a-zA-Z0-9]{24}/)) {
|
||||
throw({forbidden: 'Invalid ID format.'});
|
||||
}
|
||||
if(newDoc._deleted) {
|
||||
if(newDoc.updated !== undefined ||
|
||||
newDoc.tags !== undefined ||
|
||||
newDoc.title !== undefined ||
|
||||
newDoc._attachments !== undefined) {
|
||||
throw({forbidden: 'Deleted document must be empty.'});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(toString.call(newDoc.updated) !== '[object Number]') {
|
||||
throw({forbidden: 'Update time must be an integer.'});
|
||||
}
|
||||
if(newDoc.updated > Date.now() + 300000) {
|
||||
throw({forbidden: 'Update time is in the future, please check your clock!'});
|
||||
}
|
||||
if(toString.call(newDoc.title) !== '[object String]') {
|
||||
throw({forbidden: 'Title must be a string.'});
|
||||
}
|
||||
if(!newDoc.title) {
|
||||
throw({forbidden: 'Title is empty.'});
|
||||
}
|
||||
if(newDoc.title.length >= 256) {
|
||||
throw({forbidden: 'Title too long.'});
|
||||
}
|
||||
if(newDoc.tags !== undefined) {
|
||||
if(toString.call(newDoc.tags) !== '[object Array]') {
|
||||
throw({forbidden: 'Tags must be an array.'});
|
||||
}
|
||||
if(newDoc.tags.length >= 16) {
|
||||
throw({forbidden: 'Too many tags.'});
|
||||
}
|
||||
newDoc.tags.forEach(function(tag) {
|
||||
if(toString.call(tag) !== '[object String]') {
|
||||
throw({forbidden: 'Tags must contain strings only.'});
|
||||
}
|
||||
if(!tag) {
|
||||
throw({forbidden: 'Tag is empty.'});
|
||||
}
|
||||
if(tag.length > 32) {
|
||||
throw({forbidden: 'Tag is too long.'});
|
||||
}
|
||||
});
|
||||
}
|
||||
var attachment = (newDoc._attachments || {}).content;
|
||||
if(!attachment) {
|
||||
throw({forbidden: 'Missing attached content.'});
|
||||
}
|
||||
if(attachment.content_type != 'text/plain') {
|
||||
throw({forbidden: 'Invalid content type.'});
|
||||
}
|
||||
if(Object.keys(newDoc._attachments).length > 1) {
|
||||
throw({forbidden: 'Too many attachments.'});
|
||||
}
|
||||
};
|
||||
|
||||
var byUpdate = function(doc) {
|
||||
if(!doc.tags || !doc.tags.length) {
|
||||
emit(doc.updated, null);
|
||||
}
|
||||
};
|
||||
|
||||
var byTagAndUpdate = function(doc) {
|
||||
doc.tags && doc.tags.forEach(function(tag) {
|
||||
emit([
|
||||
tag,
|
||||
doc.updated
|
||||
], null);
|
||||
});
|
||||
};
|
||||
|
||||
var ddocs = [
|
||||
{
|
||||
path: '/_design/validate',
|
||||
body: {
|
||||
validate_doc_update: validate.toString()
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/_design/by_update',
|
||||
body: {
|
||||
views: {
|
||||
default: {
|
||||
map: byUpdate.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/_design/by_tag_and_update',
|
||||
body: {
|
||||
views: {
|
||||
default: {
|
||||
map: byTagAndUpdate.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if(process.argv.length < 3) {
|
||||
console.error('Missing URL parameter');
|
||||
process.exit(-1);
|
||||
}
|
||||
|
||||
var url = require('url').parse(process.argv[2]);
|
||||
var request = require(url.protocol === 'https:' ? 'https' : 'http').request;
|
||||
|
||||
function onError(err, body) {
|
||||
console.error(err);
|
||||
body && console.error(body);
|
||||
process.exit(1);
|
||||
}
|
||||
function uploadDdoc() {
|
||||
if(ddocs.length === 0) {
|
||||
return console.log('All design documents updated successfully.');
|
||||
}
|
||||
var ddoc = ddocs.shift();
|
||||
var options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port,
|
||||
path: url.path + ddoc.path,
|
||||
auth: url.auth,
|
||||
method: 'GET'
|
||||
};
|
||||
request(options, function(res) {
|
||||
var body = '';
|
||||
res
|
||||
.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
})
|
||||
.on('end', function() {
|
||||
if(res.statusCode == 200) {
|
||||
ddoc.body._rev = JSON.parse(body)._rev;
|
||||
}
|
||||
var options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port,
|
||||
path: url.path + ddoc.path,
|
||||
auth: url.auth,
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
};
|
||||
request(options, function(res) {
|
||||
var body = '';
|
||||
res
|
||||
.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
})
|
||||
.on('end', function() {
|
||||
res.statusCode >= 300 && onError('Status code: ' + res.statusCode, body);
|
||||
uploadDdoc();
|
||||
});
|
||||
})
|
||||
.on('error', onError)
|
||||
.end(JSON.stringify(ddoc.body));
|
||||
});
|
||||
})
|
||||
.on('error', onError)
|
||||
.end();
|
||||
}
|
||||
uploadDdoc();
|
@ -1,52 +0,0 @@
|
||||
### Pre-requisites
|
||||
|
||||
- **CouchDB 1.5 or later**, because of the use of `POST /{db}/_changes`,
|
||||
- **Node.js**, to load the design documents in the database.
|
||||
|
||||
> **Note:**
|
||||
>
|
||||
> - In order to work with https://stackedit.io, your database has to be accessible through HTTPS. You can use a free hosting service like [Smileupps](https://www.smileupps.com/) or [configure your own instance to use SSL](http://docs.couchdb.org/en/latest/config/http.html#ssl).
|
||||
>
|
||||
> - StackEdit doesn't deal with user access rights, but you can still set permissions for your database and configure StackEdit to connect to it using URL like this: `https://username:password@instance.smileupps.com/documents`.
|
||||
>
|
||||
> - It's up to you to trigger the database compaction, or to keep the full history of your documents.
|
||||
|
||||
|
||||
### Enable CORS
|
||||
|
||||
Add the following key/value pairs to your CouchDB configuration:
|
||||
|
||||
```
|
||||
[httpd]
|
||||
enable_cors = true
|
||||
|
||||
[cors]
|
||||
origins = http://localhost, https://stackedit.io
|
||||
```
|
||||
|
||||
|
||||
### Create the database
|
||||
|
||||
```bash
|
||||
curl -X PUT https://instance.smileupps.com/documents
|
||||
```
|
||||
|
||||
### Insert the design documents
|
||||
|
||||
```bash
|
||||
curl -O https://raw.githubusercontent.com/benweet/stackedit/master/couchdb/setup.js
|
||||
node setup.js https://instance.smileupps.com/documents
|
||||
```
|
||||
|
||||
Or directly:
|
||||
|
||||
```bash
|
||||
curl https://raw.githubusercontent.com/benweet/stackedit/master/couchdb/setup.js | node /dev/stdin https://instance.smileupps.com/documents
|
||||
```
|
||||
|
||||
### Update StackEdit settings
|
||||
|
||||
To configure StackEdit to use your CouchDB instance, change the in URL in `Menu` > `Settings` > `Advanced` > `CouchDB URL` to `https://instance.smileupps.com/documents`.
|
||||
|
||||
|
||||
> Written with [StackEdit](https://stackedit.io/).
|
@ -1,659 +0,0 @@
|
||||
Developer guide
|
||||
===============
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
### Pre-requisites
|
||||
|
||||
- [Git][1]
|
||||
- [node.js/npm][2]
|
||||
- [Gulp][3]
|
||||
- [Bower][4]
|
||||
|
||||
### Before debugging
|
||||
|
||||
- Download development tools:
|
||||
|
||||
npm install
|
||||
|
||||
- Download dependencies:
|
||||
|
||||
bower install
|
||||
|
||||
- Serve **StackEdit** at `http://localhost/`:
|
||||
|
||||
(export PORT=80 && node server.js)
|
||||
If on Windows, use
|
||||
|
||||
(set PORT=80 && node server.js)
|
||||
|
||||
- Run **StackEdit** in debug mode (no application cache, serve original files instead of minified):
|
||||
|
||||
http://localhost/?debug
|
||||
|
||||
### Add new dependencies
|
||||
|
||||
> **NOTE:** StackEdit uses [RequireJS][5] for asynchronous module definition ([AMD][6]).
|
||||
|
||||
- Install new dependencies using [Bower][7]:
|
||||
|
||||
bower install <library> --save
|
||||
|
||||
- Add the new dependency to [RequireJS][8] configuration file (`main.js`):
|
||||
|
||||
gulp bower-requirejs
|
||||
|
||||
### Build/minify
|
||||
|
||||
gulp
|
||||
|
||||
### Deploy
|
||||
|
||||
- on Heroku:
|
||||
|
||||
heroku create my-stackedit-instance
|
||||
git push heroku master
|
||||
|
||||
- in a Docker container:
|
||||
|
||||
docker build -t my-stackedit-image .
|
||||
docker run -p 3000 my-stackedit-image
|
||||
|
||||
> **NOTE:** OAuth authorizations work out of the box for address `http://localhost/` except for WordPress. To allow another address, you have to add specific keys at the end of `constants.js` and eventually to set up specific proxies with the corresponding key/secret pairs ([WordPress Proxy][9], [Tumblr Proxy][10] and [Gatekeeper][11]).
|
||||
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
![Architecture diagram][12]
|
||||
|
||||
The modules are loaded by RequireJS in the following order:
|
||||
|
||||
1. The 3rd party libraries (jQuery, underscore.js...)
|
||||
2. The `Extension` modules
|
||||
3. The `eventMgr` module
|
||||
4. The `core` module
|
||||
5. The `fileMgr` module and the helpers modules
|
||||
6. The `Provider` modules
|
||||
7. The `publisher` and `synchronizer` modules
|
||||
|
||||
This is important to notice in order to avoid circular dependencies. For instance, if an `Extension` is declared with the `core` module as a dependency, RequireJS will inject `undefined` instead of the actual module.
|
||||
|
||||
Any module though can access any dependencies by implementing the proper [injection listener][13] provided by the `eventMgr`.
|
||||
|
||||
----------
|
||||
|
||||
|
||||
### core
|
||||
|
||||
The `core` module is responsible for:
|
||||
|
||||
- creating the [UI Layout][14], the [ACE][15] editor and the [PageDown][16] editor,
|
||||
- loading/saving the settings,
|
||||
- running periodic tasks,
|
||||
- detecting the user activity,
|
||||
- checking the offline status.
|
||||
|
||||
**Attributes:**
|
||||
|
||||
- `isOffline`: indicates the offline status of the application.
|
||||
|
||||
**Methods:**
|
||||
|
||||
- `onReady(callback)`: sets a callback to be called when all modules have been loaded and the DOM is ready.
|
||||
> **NOTE:** This is preferred over [jQuery's `.ready()`][17] because it ensures that all AMD modules are loaded by [RequireJS][18].
|
||||
|
||||
- `runPeriodically(callback)`: sets a callback to be called every second.
|
||||
> **NOTE:** The callback will not run if the user is inactive or in StackEdit Viewer. User is considered inactive after 5 minutes of inactivity (mouse or keyboard).
|
||||
|
||||
- `setOffline()`: can be called by any other modules when a network timeout occurs for instance.
|
||||
> **NOTE:** the offline status is also set by detecting the window `offline` event. `core.isOffline` is automatically set to `false` when the network is recovered.
|
||||
|
||||
- `initEditor(fileDesc)`: creates or refreshes the [PageDown][19] editor with a given [`FileDescriptor`][20] object.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
|
||||
### fileMgr
|
||||
|
||||
The `fileMgr` module is responsible for:
|
||||
|
||||
- creating and deleting local files,
|
||||
- switching from one file to another.
|
||||
|
||||
**Attributes:**
|
||||
|
||||
- `currentFile`: the [`FileDescriptor`][21] object that is currently edited.
|
||||
|
||||
**Methods:**
|
||||
|
||||
- `createFile(title, content)`: creates a [`FileDescriptor`][22] object, add it in the [`fileSystem`][23] map and returns it.
|
||||
- `deleteFile(fileDesc)`: deletes a [`FileDescriptor`][24] object from the [`fileSystem`][25] map.
|
||||
- `selectFile(fileDesc)`: selects a [`FileDescriptor`][26] object for editing.
|
||||
|
||||
|
||||
#### FileDescriptor
|
||||
|
||||
The `FileDescriptor` class represents a local file. A `FileDescriptor` object has the following properties:
|
||||
|
||||
- `fileIndex`: the unique string index of the file in the file system.
|
||||
- `title`: the title of the document.
|
||||
- `content`: the content of the document.
|
||||
- `syncLocations`: a map containing all the associated [`syncAttributes`][27] objects with their `syncIndex` as a key.
|
||||
- `publishLocations`: a map containing all the associated [`publishAttributes`][28] objects with their `publishIndex` as a key.
|
||||
|
||||
And the following methods:
|
||||
|
||||
- `addSyncLocation(syncAttributes)`: associates a [`syncAttributes`][29] object with the file.
|
||||
- `removeSyncLocation(syncAttributes)`: unassociates a [`syncAttributes`][30] object with the file.
|
||||
- `addPublishLocation(publishAttributes)`: associates a [`publishAttributes`][31] object with the file.
|
||||
- `removePublishLocation(publishAttributes)`: unassociates a [`publishAttributes`][32] object with the file.
|
||||
|
||||
#### fileSystem
|
||||
|
||||
The `fileSystem` module is a map containing all the [`FileDescriptor`][33] objects with their `fileIndex` as a key.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
|
||||
### synchronizer
|
||||
|
||||
The `synchronizer` module is responsible for:
|
||||
|
||||
- creating a new local file from a sync location (import).
|
||||
- creating a new sync location from a local file (export).
|
||||
- running 2 ways synchronization (upload and download) for all sync locations.
|
||||
|
||||
#### synchronizer's providers
|
||||
|
||||
A [`provider`][34] module can be associated with the `synchronizer` module if it implements the following functions:
|
||||
|
||||
- `importFiles()`: downloads one or multiple files and create local files associated with the sync locations.
|
||||
- `exportFile()`: uploads a local file to a new sync location.
|
||||
- `syncDown()`: performs a download of all the changes operated on all sync locations.
|
||||
- `syncUp()`: performs an upload of a change to a sync location.
|
||||
|
||||
#### syncAttributes
|
||||
|
||||
A `syncAttributes` object is an object that describes a sync location. Attributes differ from one provider to another except for the following:
|
||||
|
||||
- `syncIndex`: the unique string index of the publish location.
|
||||
- `provider`: the [`provider`][35] module that handles the sync location.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
|
||||
### publisher
|
||||
|
||||
The `publisher` module is responsible for:
|
||||
|
||||
- creating new publish locations,
|
||||
- updating existing publish locations.
|
||||
|
||||
#### publisher's providers
|
||||
|
||||
A [`provider`][36] module can be associated with the `publisher` module if it implements the following functions:
|
||||
|
||||
- `newPublishAttributes()`: returns a new [`publishAttributes`][37] object in order to create a new publish location.
|
||||
- `publish()`: performs publishing of one publish location.
|
||||
|
||||
#### publishAttributes
|
||||
|
||||
A `publishAttributes` object is an object that describes a publish location. Attributes differ from one provider to another except for the following:
|
||||
|
||||
- `publishIndex`: the unique string index of the publish location.
|
||||
- `provider`: the [`provider`][38] module that handles the publish location.
|
||||
- `format`: the publishing format for the publish location. It can be:
|
||||
- `markdown` for Markdown format.
|
||||
- `html` for HTML format.
|
||||
- `template` for template format.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
|
||||
### eventMgr
|
||||
|
||||
The `eventMgr` module is responsible for receiving and dispatching events. Below is the list of all events signatures.
|
||||
|
||||
Most events (those that are not triggered by the `eventMgr` module) can be triggered by calling methods of the same name in the `eventMgr` module. For example:
|
||||
|
||||
```js
|
||||
eventMgr.onMessage('StackEdit is awesome!');
|
||||
```
|
||||
|
||||
The method `addListener(eventName, callback)` of the `eventMgr` module can be used to listen to these events (except those that can only be handled by `Extension` modules). For example:
|
||||
|
||||
```js
|
||||
eventMgr.addListener('onMessage', function(message) {
|
||||
alert(message);
|
||||
});
|
||||
```
|
||||
|
||||
`Extension` modules have the possibility to listen to those events by implementing methods of the same name. For example:
|
||||
|
||||
```js
|
||||
myExtension.onMessage = function(message) {
|
||||
alert(message);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### Core events
|
||||
|
||||
- **`onReady()`**
|
||||
|
||||
All the modules are loaded and the DOM is ready.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
> This is preferred over [jQuery's `.ready()`][39] because it ensures that all modules have been loaded by RequireJS.
|
||||
|
||||
- **`onMessage(message)`**
|
||||
|
||||
A message destined to the user has been produced.
|
||||
- `message`: the text string of the message.
|
||||
|
||||
- **`onError(error)`**
|
||||
|
||||
An error has been thrown.
|
||||
- `error`: an error object or a string.
|
||||
|
||||
- **`onOfflineChanged(isOffline)`**
|
||||
|
||||
The off-line status has changed.
|
||||
- `isOffline`: the off-line status.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onUserActive()`**
|
||||
|
||||
The user has just moved the mouse or pressed the keyboard.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onAsyncRunning(isRunning)`**
|
||||
|
||||
Some asynchronous tasks have just started or stopped.
|
||||
- `isRunning`: true if started, false if stopped.
|
||||
|
||||
> Triggered by the `AsyncTask` module.
|
||||
|
||||
- **`onPeriodicRun()`**
|
||||
|
||||
A hook that is called periodically (every 1 second if user is active).
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onLoadSettings()`**
|
||||
|
||||
A hook that is called when the settings dialog has to be refreshed. Every `Extension` module that has configuration inputs in the settings dialog has to implement a listener for this event.
|
||||
|
||||
> Triggered by the `core` module. Only `Extension` modules can handle this event.
|
||||
|
||||
- **`onSaveSettings(newConfig, event)`**
|
||||
|
||||
A hook that is called when the settings dialog has to be validated. Every `Extension` module that has configuration inputs in the settings dialog has to implement a listener for this event.
|
||||
- `newConfig`: the new configuration object, deduced from the settings dialog inputs.
|
||||
- `event`: the submit event object. `stopPropagation` has to be called in case of an error when parsing settings dialog inputs.
|
||||
|
||||
> Triggered by the `core` module. Only `Extension` modules can handle this event.
|
||||
|
||||
- **`onInit()`**
|
||||
|
||||
A hook allowing enabled extensions to initialize.
|
||||
|
||||
> Triggered by the `eventMgr` module. Only `Extension` modules can handle this event.
|
||||
|
||||
> This event is triggered before `onReady` event and just after the `config` and `enabled` extensions properties have been set by the `eventMgr`.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### Module injection events
|
||||
|
||||
- **`onFileMgrCreated(fileMgr)`**
|
||||
|
||||
The `fileMgr` module has been created.
|
||||
- `fileMgr`: the `fileMgr` module.
|
||||
|
||||
> Triggered by the `fileMgr` module.
|
||||
|
||||
|
||||
- **`onSynchronizerCreated(synchronizer)`**
|
||||
|
||||
The `synchronizer` module has been created.
|
||||
- `synchronizer`: the `synchronizer` module.
|
||||
|
||||
> Triggered by the `synchronizer` module.
|
||||
|
||||
- **`onPublisherCreated(publisher)`**
|
||||
|
||||
The `publisher` module has been created.
|
||||
- `publisher`: the `publisher` module.
|
||||
|
||||
> Triggered by the `publisher` module.
|
||||
|
||||
- **`onEventMgrCreated()`**
|
||||
|
||||
The `eventMgr` module has been created.
|
||||
- `eventMgr`: the `eventMgr` module.
|
||||
|
||||
> Triggered by the `eventMgr` module.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### file operation events
|
||||
|
||||
- **`onFileCreated(fileDesc)`**
|
||||
|
||||
A [`FileDescriptor`][41] object has been created.
|
||||
- `fileDesc`: the [`FileDescriptor`][42] object.
|
||||
|
||||
> Triggered by the `fileMgr` module.
|
||||
|
||||
- **`onFileDeleted(fileDesc)`**
|
||||
|
||||
A [`FileDescriptor`][43] object has been removed from the `fileSystem` module.
|
||||
- `fileDesc`: the [`FileDescriptor`][44] object.
|
||||
|
||||
> Triggered by the `fileMgr` module.
|
||||
|
||||
- **`onFileSelected(fileDesc)`**
|
||||
|
||||
A [`FileDescriptor`][45] object has been selected.
|
||||
- `fileDesc`: the [`FileDescriptor`][46] object.
|
||||
|
||||
> Triggered by the `fileMgr` module. This event is triggered before `onFileClosed` (if another document is open) and `onFileOpen` events.
|
||||
|
||||
- **`onFileClosed(fileDesc)`**
|
||||
|
||||
The current [`FileDescriptor`][47] object is about to be detached from the editor.
|
||||
- `fileDesc`: the [`FileDescriptor`][48] object.
|
||||
|
||||
> Triggered by the `fileMgr` module. This event is triggered after `onFileSelected` event and before `onFileClosed` event.
|
||||
|
||||
- **`onFileOpen(fileDesc)`**
|
||||
|
||||
The selected [`FileDescriptor`][49] object has been attached to the editor.
|
||||
- `fileDesc`: the [`FileDescriptor`][50] object.
|
||||
|
||||
> Triggered by the `fileMgr` module. This event is triggered after `onFileSelected` and `onFileClosed` (if another document is open) events.
|
||||
|
||||
- **`onContentChanged(fileDesc)`**
|
||||
|
||||
The content of a [`FileDescriptor`][51] object has been modified.
|
||||
- `fileDesc`: the [`FileDescriptor`][52] object.
|
||||
|
||||
- **`onTitleChanged(fileDesc)`**
|
||||
|
||||
The content of a [`FileDescriptor`][53] object has been modified.
|
||||
- `fileDesc`: the [`FileDescriptor`][54] object.
|
||||
|
||||
- **`onFoldersChanged()`**
|
||||
|
||||
The folders structure has changed.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### Sync events
|
||||
|
||||
- **`onSyncRunning(isRunning)`**
|
||||
|
||||
A synchronization job has just started or stopped.
|
||||
- `isRunning`: true if started, false if stopped.
|
||||
|
||||
> Triggered by the `synchronizer` module.
|
||||
|
||||
> A synchronization job is the action to download and upload all detected changes for all sync locations of all documents.
|
||||
|
||||
- **`onSyncSuccess()`**
|
||||
|
||||
A synchronization job has successfully finished.
|
||||
|
||||
> Triggered by the `synchronizer` module.
|
||||
|
||||
> A synchronization job is the action to download and upload all detected changes for all sync locations of all documents.
|
||||
|
||||
- **`onSyncImportSuccess(fileDescList, provider)`**
|
||||
|
||||
The import of documents has successfully finished.
|
||||
- `fileDescList`: the list of [`FileDescriptor`][55] objects that have been created.
|
||||
- `provider`: the [`provider`][56] module that handled the import.
|
||||
|
||||
> Triggered by the [`provider`][57] module that handled the import.
|
||||
|
||||
> An import is the action to download multiple files and to create, for each, one [`FileDescriptor`][55] objects with one sync location.
|
||||
|
||||
- **`onSyncExportSuccess(fileDesc, syncAttributes)`**
|
||||
|
||||
The export of one document has successfully finished.
|
||||
- `fileDesc`: the [`FileDescriptor`][58] object that has been exported.
|
||||
- `syncAttributes`: the descriptor object of the new sync location.
|
||||
|
||||
> Triggered by the `synchronizer` module.
|
||||
|
||||
> An export is the action to upload one file and to create one new sync location associated with one existing `FileDescriptor`][55] object.
|
||||
|
||||
- **`onSyncRemoved(fileDesc, syncAttributes)`**
|
||||
|
||||
A sync location has been removed from a [`FileDescriptor`][59] object.
|
||||
- `fileDesc`: the [`FileDescriptor`][60] object.
|
||||
- `syncAttributes`: the descriptor object of the removed sync location.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### Publish events
|
||||
|
||||
- **`onPublishRunning(isRunning)`**
|
||||
|
||||
A document publication job has just started or stopped.
|
||||
- `isRunning`: true if started, false if stopped.
|
||||
|
||||
> Triggered by the `publisher` module.
|
||||
|
||||
> A publication job is the action to upload changes on multiple publish locations associated with one `FileDescriptor`][55] object.
|
||||
|
||||
- **`onPublishSuccess(fileDesc)`**
|
||||
|
||||
A document publication job has successfully finished.
|
||||
- `fileDesc`: the [`FileDescriptor`][60] object that has been published.
|
||||
|
||||
> Triggered by the `publisher` module.
|
||||
|
||||
> A publication job is the action to upload changes on multiple publish locations associated with one `FileDescriptor`][55] object.
|
||||
|
||||
- **`onNewPublishSuccess(fileDesc, publishAttributes)`**
|
||||
|
||||
A new publish location has been successfully created.
|
||||
- `fileDesc`: the [`FileDescriptor`][60] object that has been published.
|
||||
- `publishAttributes`: the descriptor object of the new publish location.
|
||||
|
||||
> Triggered by the `publisher` module.
|
||||
|
||||
- **`onPublishRemoved(fileDesc, publishAttributes)`**
|
||||
|
||||
A publish location has been removed from a [`FileDescriptor`][59] object.
|
||||
- `fileDesc`: the [`FileDescriptor`][60] object.
|
||||
- `publishAttributes`: the descriptor object of the removed publish location.
|
||||
|
||||
> Triggered by the `publisher` module.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### UI Layout events
|
||||
|
||||
- **`onLayoutConfigure(layoutConfig)`**
|
||||
|
||||
The layout is about to be configured.
|
||||
- `layoutConfig`: the configuration object of the UI Layout library.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onLayoutCreated(layout)`**
|
||||
|
||||
The layout has just been created.
|
||||
- `layout`: the layout object of the UI Layout library.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onLayoutResize(paneName)`**
|
||||
|
||||
One pane of the layout has been resized.
|
||||
- `paneName`: the name of the resized layout pane.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onCreateButton()`**
|
||||
|
||||
Allows extensions to add their own buttons in the navigation bar. Implemented listeners have to return an HTML button element. For example:
|
||||
|
||||
myExtension.onCreateButton = function() {
|
||||
var button = $('<button class="btn btn-success"><i class="icon-rocket"></i></button>');
|
||||
button.click(function() {
|
||||
eventMgr.onMessage('Booom!');
|
||||
});
|
||||
return button[0];
|
||||
};
|
||||
|
||||
> Triggered by the `eventMgr` module. Only `Extension` modules can handle this event.
|
||||
|
||||
- **`onCreateEditorButton()`**
|
||||
|
||||
Allows extensions to add their own buttons in the side bar. Implemented listeners have to return an HTML button element. See `onCreateButton` for a concrete example.
|
||||
|
||||
> Triggered by the `eventMgr` module. Only `Extension` modules can handle this event.
|
||||
|
||||
- **`onCreatePreviewButton()`**
|
||||
|
||||
Allows extensions to add their own buttons over the preview. Implemented listeners have to return an HTML button element. See `onCreateButton` for a concrete example.
|
||||
|
||||
> Triggered by the `eventMgr` module. Only `Extension` modules can handle this event.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### PageDown events
|
||||
|
||||
- **`onPagedownConfigure(editor)`**
|
||||
|
||||
The Pagedown editor is about to be created.
|
||||
- `editor`: the Pagedown editor object before `run` has been called.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
- **`onAsyncPreview(callback)`**
|
||||
|
||||
Called after Pagedown's synchronous rendering to trigger extra asynchronous rendering (such as MathJax). Implemented listeners have to call the callback parameter after processing in order other `onAsyncPreview` listeners to run.
|
||||
- `callback`: the callback to call at the end of the asynchronous processing.
|
||||
|
||||
> Triggered by the `eventMgr` module. Only `Extension` modules can handle this event.
|
||||
|
||||
- **`onPreviewFinished(html)`**
|
||||
|
||||
Called after every `onAsyncPreview` listeners have been called.
|
||||
- `html`: the finally rendered HTML.
|
||||
|
||||
- **`onSectionsCreated(sectionList)`**
|
||||
|
||||
The Markdown has been split into sections before rendering.
|
||||
- `sectionList`: the list of section objects. Each section object contains:
|
||||
- `text`: the markdown substring contained in the section.
|
||||
- `textWithDelimiter`: the text with an added delimiter.
|
||||
|
||||
> Triggered by the `markdownSectionParser` extension.
|
||||
|
||||
- **`onMarkdownTrim(offset)`**
|
||||
|
||||
The Markdown has been left trimmed by a certain number of character.
|
||||
- `offset`: the number of characters that have been removed.
|
||||
|
||||
> Triggered by the `yamlFrontMatterParser` extension.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
#### ACE events
|
||||
|
||||
- **`onAceCreated(aceEditor)`**
|
||||
|
||||
The ACE editor has just been created.
|
||||
- `aceEditor`: the ACE editor object.
|
||||
|
||||
> Triggered by the `core` module.
|
||||
|
||||
|
||||
|
||||
> Written with [StackEdit](https://stackedit.io/).
|
||||
|
||||
|
||||
[1]: http://git-scm.com/
|
||||
[2]: http://nodejs.org/
|
||||
[3]: http://gulpjs.com/
|
||||
[4]: http://bower.io/
|
||||
[5]: http://requirejs.org/ "RequireJS"
|
||||
[6]: http://en.wikipedia.org/wiki/Asynchronous_module_definition "Asynchronous module definition"
|
||||
[7]: http://bower.io/
|
||||
[8]: http://requirejs.org/ "RequireJS"
|
||||
[9]: https://github.com/benweet/stackedit-wordpress-proxy
|
||||
[10]: https://github.com/benweet/stackedit-tumblr-proxy
|
||||
[11]: https://github.com/prose/gatekeeper
|
||||
[12]: https://lh6.googleusercontent.com/-sr6zRtyaoUk/Un5qSakOzPI/AAAAAAAAFC0/oI5If5fI9Gw/s0/StackEdit%252520architecture%252520-%252520New%252520Page%252520%2525283%252529.png "StackEdit architecture"
|
||||
[13]: #module-injection
|
||||
[14]: http://layout.jquery-dev.net/ "UI Layout"
|
||||
[15]: http://ace.c9.io
|
||||
[16]: https://code.google.com/p/pagedown/ "PageDown"
|
||||
[17]: http://api.jquery.com/ready/
|
||||
[18]: http://requirejs.org/ "RequireJS"
|
||||
[19]: https://code.google.com/p/pagedown/ "PageDown"
|
||||
[20]: #filedescriptor
|
||||
[21]: #filedescriptor
|
||||
[22]: #filedescriptor
|
||||
[23]: #filesystem
|
||||
[24]: #filedescriptor
|
||||
[25]: #filesystem
|
||||
[26]: #filedescriptor
|
||||
[27]: #syncattributes
|
||||
[28]: #publishattributes
|
||||
[29]: #syncattributes
|
||||
[30]: #syncattributes
|
||||
[31]: #publishattributes
|
||||
[32]: #publishattributes
|
||||
[33]: #filedescriptor
|
||||
[34]: #provider
|
||||
[35]: #provider
|
||||
[36]: #provider
|
||||
[37]: #publishattributes
|
||||
[38]: #provider
|
||||
[39]: http://api.jquery.com/ready/
|
||||
[40]: http://requirejs.org/ "RequireJS"
|
||||
[41]: #filedescriptor
|
||||
[42]: #filedescriptor
|
||||
[43]: #filedescriptor
|
||||
[44]: #filedescriptor
|
||||
[45]: #filedescriptor
|
||||
[46]: #filedescriptor
|
||||
[47]: #filedescriptor
|
||||
[48]: #filedescriptor
|
||||
[49]: #filedescriptor
|
||||
[50]: #filedescriptor
|
||||
[51]: #filedescriptor
|
||||
[52]: #filedescriptor
|
||||
[53]: #filedescriptor
|
||||
[54]: #filedescriptor
|
||||
[55]: #filedescriptor
|
||||
[56]: #provider
|
||||
[57]: #provider
|
||||
[58]: #filedescriptor
|
||||
[59]: #filedescriptor
|
||||
[60]: #filedescriptor
|
Before Width: | Height: | Size: 30 KiB |
@ -1,34 +0,0 @@
|
||||
StackEdit theming guide
|
||||
=======================
|
||||
|
||||
In **StackEdit**, a theme is pretty much a [LESS][1] file that overrides the default look and feel.
|
||||
|
||||
### Create your special theme very quickly by following these steps
|
||||
|
||||
1. Fork **StackEdit** on [GitHub][2] and clone the repository localy.
|
||||
|
||||
2. Install the development tools as described in the [Developer guide][3].
|
||||
|
||||
3. In `res/themes`, create a LESS file, just like the other themes.
|
||||
|
||||
> You can put images in `res/img`.
|
||||
|
||||
4. Add an entry in `THEME_LIST` at the end of `public/res/constants.js` with the filename as a key and the name of your theme as a value.
|
||||
|
||||
> **Example:** `"cool": "The coolest ever"`
|
||||
|
||||
5. Run the application on your machine using the `?debug` flag. Basically:
|
||||
|
||||
http://localhost/stackedit/?debug
|
||||
|
||||
6. Go to `Settings -> Editor -> Theme` and select your theme. Check that everything is fine.
|
||||
|
||||
7. Commit, push, create a pull request and wait for publishing.
|
||||
|
||||
|
||||
> Written with [StackEdit](http://benweet.github.io/stackedit/).
|
||||
|
||||
|
||||
[1]: http://lesscss.org/
|
||||
[2]: https://github.com/benweet/stackedit
|
||||
[3]: https://github.com/benweet/stackedit/blob/master/doc/developer-guide.md#getting-started
|
10
docs/大文档导出PDF方式.md
Normal file
@ -0,0 +1,10 @@
|
||||
# 大文档导出PDF方式说明
|
||||
> 由于大文档导出PDF,需要消费非常多的服务器资源,而且很容易导致导出超时,故导出PDF的MD文档过大时,可以使用 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 工具导出。
|
||||
|
||||
# 操作步骤
|
||||
- 先在 **[StackEdit中文版](https://stackedit.cn/app)** 中使用 `导出为HTML` 功能导出MD文档,导出后可以得到一个HTML文档。
|
||||
- 到 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 官网下载安装程序。
|
||||
- 使用 wkhtmltopdf 的导出PDF的命令 `wkhtmltopdf [GLOBAL OPTION]... [OBJECT]... <output file>` 把HTML导出为PDF,如简单的导出命令:`wkhtmltopdf test.html test.pdf`,具体的 `GLOBAL OPTION` 参数说明可以通过 `wkhtmltopdf -H` 查看帮助文档。
|
||||
|
||||
|
||||
|
20
docs/部署之GitHub应用创建.md
Normal file
@ -0,0 +1,20 @@
|
||||
# GitHub应用配置说明
|
||||
|
||||
> StackEdit中文版部署如果需要支持GitHub,则需要到GitHub创建一个应用,并复制其中的clientId和clientSecret填充到环境变量 GITHUB_CLIENT_ID 和 GITHUB_CLIENT_SECRET 中。
|
||||
|
||||
|
||||
# 如何创建GitHub应用
|
||||
|
||||
按下面图的指示创建
|
||||
|
||||
|
||||
![](../images/github/github01.png)
|
||||
|
||||
![](../images/github/github02.png)
|
||||
|
||||
![](../images/github/github03.png)
|
||||
|
||||
![](../images/github/github04.png)
|
||||
|
||||
![](../images/github/github05.png)
|
||||
|
35
docs/部署之Gitea应用创建.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Gitea应用配置说明
|
||||
|
||||
> StackEdit中文版支持Gitea,则需要到Gitea创建一个应用,在StackEdit中文版绑定Gitea账号的时候填入。
|
||||
|
||||
|
||||
# 如何创建Gitea应用
|
||||
|
||||
按下面图的指示创建
|
||||
|
||||
|
||||
![](../images/gitea/gitea01.png)
|
||||
|
||||
![](../images/gitea/gitea02.png)
|
||||
|
||||
![](../images/gitea/gitea03.png)
|
||||
|
||||
![](../images/gitea/gitea04.png)
|
||||
|
||||
创建成功后即可看到应用ID 和 应用秘钥。
|
||||
|
||||
# Gitea跨域问题
|
||||
|
||||
由于StackEdit中文版是从浏览器直接访问Gitea接口,故个人部署的Gitea需要支持跨域,至于如何支持跨域,请参考官方文档:https://docs.gitea.io/en-us/config-cheat-sheet/#cors-cors (官方跨域的支持好像存在问题,我个人包括很多网友通过这个配置支持跨域都失败了,如果你也失败了,可以试试用nginx代理实现跨域)
|
||||
|
||||
nginx配置实现跨域的配置如下:
|
||||
|
||||
```
|
||||
add_header Access-Control-Allow-Headers *;
|
||||
add_header Access-Control-Allow-Origin $http_origin;
|
||||
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
|
||||
|
||||
if ($request_method = 'OPTIONS') {
|
||||
return 204;
|
||||
}
|
||||
```
|
19
docs/部署之Gitee应用创建.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Gitee应用配置说明
|
||||
|
||||
> StackEdit中文版部署如果需要支持Gitee,则需要到Gitee创建一个应用,并复制其中的clientId和clientSecret填充到环境变量 GITEE_CLIENT_ID 和 GITEE_CLIENT_SECRET 中。
|
||||
|
||||
|
||||
# 如何创建Gitee应用
|
||||
|
||||
按下面图的指示创建
|
||||
|
||||
|
||||
![](../images/gitee/gitee01.png)
|
||||
|
||||
![](../images/gitee/gitee02.png)
|
||||
|
||||
![](../images/gitee/gitee03.png)
|
||||
|
||||
![](../images/gitee/gitee04.png)
|
||||
|
||||
创建成功后即可看到client id 和 client secret。
|
20
gulpfile.js
Normal file
@ -0,0 +1,20 @@
|
||||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const concat = require('gulp-concat');
|
||||
|
||||
const prismScripts = [
|
||||
'prismjs/components/prism-core',
|
||||
'prismjs/components/prism-markup',
|
||||
'prismjs/components/prism-clike',
|
||||
'prismjs/components/prism-c',
|
||||
'prismjs/components/prism-javascript',
|
||||
'prismjs/components/prism-css',
|
||||
'prismjs/components/prism-ruby',
|
||||
'prismjs/components/prism-cpp',
|
||||
].map(require.resolve);
|
||||
prismScripts.push(
|
||||
path.join(path.dirname(require.resolve('prismjs/components/prism-core')), 'prism-!(*.min).js'));
|
||||
|
||||
gulp.task('build-prism', () => gulp.src(prismScripts)
|
||||
.pipe(concat('prism.js'))
|
||||
.pipe(gulp.dest(path.dirname(require.resolve('prismjs')))));
|
BIN
images/chatgpt.gif
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
images/dark.png
Normal file
After Width: | Height: | Size: 793 KiB |
BIN
images/fileSearch.png
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
images/gitea/gitea01.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
images/gitea/gitea02.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
images/gitea/gitea03.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/gitea/gitea04.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
images/gitee/gitee01.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
images/gitee/gitee02.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
images/gitee/gitee03.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
images/gitee/gitee04.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
images/github/github01.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
images/github/github02.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
images/github/github03.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
images/github/github04.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
images/github/github05.png
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
images/imageBed.png
Normal file
After Width: | Height: | Size: 339 KiB |
BIN
images/light.png
Normal file
After Width: | Height: | Size: 726 KiB |
BIN
images/qq.jpeg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
images/search.gif
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
images/theme.gif
Normal file
After Width: | Height: | Size: 937 KiB |
BIN
images/uploadimg.gif
Normal file
After Width: | Height: | Size: 761 KiB |
BIN
images/workspace.png
Normal file
After Width: | Height: | Size: 195 KiB |
31
index.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Markdown编辑器-JonyLee的设计导航</title>
|
||||
<link rel="canonical" href="https://md.jonylee.top">
|
||||
<meta name="description" content="StackEdit中文版,免费,开源,功能全面的Markdown编辑器。">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<!-- baidu统计 -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?dad4b4383b13eedea1ab45ee323df1c3";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
<!-- baidu统计结束 -->
|
||||
</body>
|
||||
|
||||
</html>
|
27
index.js
Normal file
@ -0,0 +1,27 @@
|
||||
const env = require('./config/prod.env');
|
||||
|
||||
Object.keys(env).forEach((key) => {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = JSON.parse(env[key]);
|
||||
}
|
||||
});
|
||||
|
||||
const http = require('http');
|
||||
const express = require('express');
|
||||
|
||||
const app = express();
|
||||
|
||||
require('./server')(app);
|
||||
|
||||
const port = parseInt(process.env.PORT || 8080, 10);
|
||||
const httpServer = http.createServer(app);
|
||||
httpServer.listen(port, null, () => {
|
||||
console.log(`HTTP server started: http://localhost:${port}`);
|
||||
});
|
||||
|
||||
// Handle graceful shutdown
|
||||
process.on('SIGTERM', () => {
|
||||
httpServer.close(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
22028
package-lock.json
generated
Normal file
172
package.json
@ -1,51 +1,141 @@
|
||||
{
|
||||
"name": "stackedit",
|
||||
"version": "4.3.22",
|
||||
"description": "StackEdit is a free, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.",
|
||||
"main": "res/main.js",
|
||||
"engines": {
|
||||
"node": "0.10.x"
|
||||
"version": "5.15.21",
|
||||
"description": "免费, 开源, 功能齐全的 Markdown 编辑器",
|
||||
"author": "Benoit Schweblin, 豆萁",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mafgwo/stackedit/issues"
|
||||
},
|
||||
"directories": {
|
||||
"doc": "doc"
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "gulp build-prism",
|
||||
"start": "node build/dev-server.js",
|
||||
"build": "node build/build.js && npm run build-style",
|
||||
"build-style": "webpack --config build/webpack.style.conf.js",
|
||||
"lint": "eslint --ext .js,.vue src server",
|
||||
"unit": "jest --config test/unit/jest.conf.js --runInBand",
|
||||
"unit-with-coverage": "jest --config test/unit/jest.conf.js --runInBand --coverage",
|
||||
"test": "npm run lint && npm run unit",
|
||||
"preversion": "npm run test",
|
||||
"postversion": "git push origin master --tags && npm publish",
|
||||
"patch": "npm version patch -m \"Tag v%s\"",
|
||||
"minor": "npm version minor -m \"Tag v%s\"",
|
||||
"major": "npm version major -m \"Tag v%s\"",
|
||||
"chart": "mkdir -p dist && rm -rf dist/stackedit && cp -r chart dist/stackedit && sed -i.bak -e s/STACKEDIT_VERSION/$npm_package_version/g dist/stackedit/*.yaml && rm dist/stackedit/*.yaml.bak"
|
||||
},
|
||||
"dependencies": {
|
||||
"bower": "~1.8.2",
|
||||
"compression": "~1.0.11",
|
||||
"ejs": "~0.8.4",
|
||||
"express": "~4.8.5",
|
||||
"request": "~2.40.0",
|
||||
"serve-static": "~1.6.5",
|
||||
"ssh2": "~0.3.5"
|
||||
"@vue/test-utils": "^1.0.0-beta.16",
|
||||
"abcjs": "^5.2.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"bezier-easing": "^1.1.0",
|
||||
"body-parser": "^1.18.2",
|
||||
"clipboard": "^1.7.1",
|
||||
"compression": "^1.7.0",
|
||||
"diff-match-patch": "^1.0.0",
|
||||
"file-saver": "^1.3.8",
|
||||
"handlebars": "^4.0.10",
|
||||
"indexeddbshim": "^3.6.2",
|
||||
"js-yaml": "^3.11.0",
|
||||
"katex": "^0.16.2",
|
||||
"markdown-it": "^8.4.1",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-deflist": "^2.0.2",
|
||||
"markdown-it-emoji": "^1.3.0",
|
||||
"markdown-it-footnote": "^3.0.1",
|
||||
"markdown-it-imsize": "^2.0.1",
|
||||
"markdown-it-mark": "^2.0.0",
|
||||
"markdown-it-pandoc-renderer": "1.1.3",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"mermaid": "^8.9.2",
|
||||
"mousetrap": "^1.6.1",
|
||||
"normalize-scss": "^7.0.1",
|
||||
"prismjs": "^1.6.0",
|
||||
"request": "^2.85.0",
|
||||
"serve-static": "^1.13.2",
|
||||
"tmp": "^0.0.33",
|
||||
"turndown": "^7.1.1",
|
||||
"vue": "^2.5.16",
|
||||
"vuex": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-requirejs": "~1.0.0",
|
||||
"gulp-jshint": "~1.8.4",
|
||||
"gulp-uglify": "~1.1.0",
|
||||
"gulp-less": "~1.3.5",
|
||||
"bower-requirejs": "~1.1.0",
|
||||
"gulp-inject": "git://github.com/benweet/gulp-inject.git#8bd702d143a578e3b44290d82612ab808ee17281",
|
||||
"run-sequence": "~0.3.6",
|
||||
"gulp-clean": "~0.3.1",
|
||||
"gulp-replace": "~0.4.0",
|
||||
"gulp-bump": "~0.1.11",
|
||||
"gulp-util": "~3.0.1",
|
||||
"knox": "~0.9.1",
|
||||
"mime": "~1.2.11",
|
||||
"event-stream": "~3.1.7"
|
||||
"autoprefixer": "^6.7.2",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-jest": "^21.0.2",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-dynamic-import-node": "^1.2.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"babel-register": "^6.22.0",
|
||||
"chalk": "^1.1.3",
|
||||
"connect-history-api-fallback": "^1.3.0",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"css-loader": "^0.28.11",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-import-resolver-webpack": "^0.9.0",
|
||||
"eslint-loader": "^2.0.0",
|
||||
"eslint-plugin-html": "^4.0.3",
|
||||
"eslint-plugin-import": "^2.11.0",
|
||||
"eventsource-polyfill": "^0.9.6",
|
||||
"express": "^4.16.3",
|
||||
"extract-text-webpack-plugin": "^2.0.0",
|
||||
"favicons-webpack-plugin": "^0.0.9",
|
||||
"file-loader": "^1.1.11",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"http-proxy-middleware": "^0.18.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"ignore-loader": "^0.1.2",
|
||||
"jest": "^23.0.0",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"jest-serializer-vue": "^0.3.0",
|
||||
"js-md5": "^0.7.3",
|
||||
"node-sass": "^4.0.0",
|
||||
"npm-bump": "^0.0.23",
|
||||
"offline-plugin": "^5.0.3",
|
||||
"opn": "^4.0.2",
|
||||
"optimize-css-assets-webpack-plugin": "^1.3.2",
|
||||
"ora": "^1.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"replace-in-file": "^4.1.0",
|
||||
"rimraf": "^2.6.0",
|
||||
"sass-loader": "^7.0.1",
|
||||
"semver": "^5.5.0",
|
||||
"shelljs": "^0.8.1",
|
||||
"string-replace-loader": "^2.1.1",
|
||||
"stylelint": "^9.2.0",
|
||||
"stylelint-config-standard": "^16.0.0",
|
||||
"stylelint-processor-html": "^1.0.0",
|
||||
"stylelint-webpack-plugin": "^0.10.4",
|
||||
"url-loader": "^1.0.1",
|
||||
"vue-jest": "^1.0.2",
|
||||
"vue-loader": "^15.0.9",
|
||||
"vue-style-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.5.16",
|
||||
"webpack": "^2.6.1",
|
||||
"webpack-bundle-analyzer": "^3.3.2",
|
||||
"webpack-dev-middleware": "^1.10.0",
|
||||
"webpack-hot-middleware": "^2.18.0",
|
||||
"webpack-merge": "^4.1.2",
|
||||
"webpack-pwa-manifest": "^3.7.1",
|
||||
"worker-loader": "^1.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "bower --allow-root install",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"engines": {
|
||||
"node": ">= 8.0.0",
|
||||
"npm": ">= 5.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/benweet/stackedit.git"
|
||||
},
|
||||
"author": "Benoit Schweblin",
|
||||
"license": "Apache License",
|
||||
"bugs": {
|
||||
"url": "https://github.com/benweet/stackedit/issues"
|
||||
}
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 10"
|
||||
]
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"curly": true,
|
||||
"browser": true,
|
||||
"devel": true,
|
||||
"indent": 4,
|
||||
"latedef": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"expr": true,
|
||||
"globals": {
|
||||
"define": false,
|
||||
"require": false
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
CACHE MANIFEST
|
||||
#Date Thu Feb 01 2018 23:51:19 GMT+0000 (WET)
|
||||
|
||||
CACHE:
|
||||
.
|
||||
editor
|
||||
viewer
|
||||
|
||||
# start_inject_resources
|
||||
res-min/main.js
|
||||
res-min/require.js
|
||||
res-min/font/PTSans-Bold-webfont.woff
|
||||
res-min/font/PTSans-BoldItalic-webfont.woff
|
||||
res-min/font/PTSans-Italic-webfont.woff
|
||||
res-min/font/PTSans-Regular-webfont.woff
|
||||
res-min/font/SourceCodePro-Bold-webfont.woff
|
||||
res-min/font/SourceCodePro-Regular-webfont.woff
|
||||
res-min/font/SourceSansPro-Bold-webfont.woff
|
||||
res-min/font/SourceSansPro-BoldItalic-webfont.woff
|
||||
res-min/font/SourceSansPro-Italic-webfont.woff
|
||||
res-min/font/SourceSansPro-Light-webfont.woff
|
||||
res-min/font/SourceSansPro-LightItalic-webfont.woff
|
||||
res-min/font/SourceSansPro-Regular-webfont.woff
|
||||
res-min/font/cursive_standard-webfont.woff
|
||||
res-min/font/fontello.svg
|
||||
res-min/font/fontello.woff
|
||||
res-min/img/button.svg
|
||||
res-min/img/code-block.png
|
||||
res-min/img/comments.png
|
||||
res-min/img/conflict.png
|
||||
res-min/img/diagram.png
|
||||
res-min/img/gittip.png
|
||||
res-min/img/icons.png
|
||||
res-min/img/icons2x.png
|
||||
res-min/img/live-preview.png
|
||||
res-min/img/logo-highres.png
|
||||
res-min/img/logo-ipad-retina.png
|
||||
res-min/img/logo.svg
|
||||
res-min/img/math.png
|
||||
res-min/img/menu-icon.png
|
||||
res-min/img/menu.png
|
||||
res-min/img/publish.png
|
||||
res-min/img/stackedit-32.ico
|
||||
res-min/img/syntax-highlighting.gif
|
||||
res-min/img/toc.gif
|
||||
res-min/themes/base.css
|
||||
res-min/themes/blue.css
|
||||
res-min/themes/default.css
|
||||
res-min/themes/gray.css
|
||||
res-min/themes/night.css
|
||||
res-min/themes/school.css
|
||||
res-min/themes/solarized-dark.css
|
||||
res-min/themes/solarized-light.css
|
||||
# end_inject_resources
|
||||
|
||||
|
||||
# start_inject_mathjax
|
||||
res/bower-libs/MathJax/MathJax.js?config=TeX-AMS_SVG
|
||||
res/bower-libs/MathJax/config/Safe.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/config/TeX-AMS_SVG.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/AssistiveMML.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/CHTML-preview.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/FontWarnings.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/HelpDialog.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MatchWebFonts.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MathEvents.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MathMenu.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MathZoom.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/Safe.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/asciimath2jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/fast-preview.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/jsMath2jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/mml2jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/tex2jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/toMathML.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/HTML-CSS/handle-floats.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MathML/content-mathml.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/MathML/mml3.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/AMScd.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/AMSmath.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/AMSsymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/HTML.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/action.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/autobold.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/autoload-all.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/bbox.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/begingroup.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/boldsymbol.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/cancel.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/color.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/enclose.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/extpfeil.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/mathchoice.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/mediawiki-texvc.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/mhchem.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/newcommand.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/noErrors.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/noUndefined.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/unicode.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/extensions/TeX/verb.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/jax.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/Arrows.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/CombDiactForSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/Dingbats.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/GeneralPunctuation.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/GeometricShapes.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/GreekAndCoptic.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/Latin1Supplement.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/LetterlikeSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/MathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/MiscMathSymbolsA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/MiscMathSymbolsB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/MiscSymbolsAndArrows.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/MiscTechnical.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/SpacingModLetters.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/SuppMathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/SupplementalArrowsA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/element/mml/optable/SupplementalArrowsB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/annotation-xml.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/maction.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/menclose.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/mglyph.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/mmultiscripts.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/ms.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/mtable.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/autoload/multiline.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Typewriter/Regular/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Typewriter/Regular/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Typewriter/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Typewriter/Regular/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Size4/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Size3/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/fontdata-extra.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/fontdata.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/Arrows.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/BoxDrawing.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/Dingbats.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/EnclosedAlphanum.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/GeneralPunctuation.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/GeometricShapes.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/GreekAndCoptic.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/Latin1Supplement.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/LatinExtendedA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/LetterlikeSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/MathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/MiscMathSymbolsB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/MiscSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/MiscTechnical.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/PUA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/SpacingModLetters.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/AMS/Regular/SuppMathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Caligraphic/Bold/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Caligraphic/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Bold/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Bold/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Bold/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Bold/PUA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Regular/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Regular/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Fraktur/Regular/PUA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/Arrows.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/CombDiactForSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/GeneralPunctuation.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/GeometricShapes.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/GreekAndCoptic.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/Latin1Supplement.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/LatinExtendedA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/LatinExtendedB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/LetterlikeSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/MathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/MiscMathSymbolsA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/MiscSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/MiscTechnical.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/SpacingModLetters.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/SuppMathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Bold/SupplementalArrowsA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/GeometricShapes.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/GreekAndCoptic.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/LatinExtendedA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/LatinExtendedB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/LetterlikeSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/MathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/MiscSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/SpacingModLetters.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Regular/SuppMathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/GeneralPunctuation.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/GreekAndCoptic.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/LatinExtendedA.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/LatinExtendedB.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/LetterlikeSymbols.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Main/Italic/MathOperators.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Math/BoldItalic/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Math/Italic/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Bold/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Bold/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Bold/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Bold/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Italic/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Italic/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Italic/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Italic/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Regular/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Regular/CombDiacritMarks.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/SansSerif/Regular/Other.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Script/Regular/BasicLatin.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Script/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Size2/Regular/Main.js?rev=2.6.1
|
||||
res/bower-libs/MathJax/jax/output/SVG/fonts/TeX/Size1/Regular/Main.js?rev=2.6.1
|
||||
# end_inject_mathjax
|
||||
|
||||
|
||||
NETWORK:
|
||||
*
|
@ -1 +0,0 @@
|
||||
google-site-verification: google4971b5a4d775691a.html
|
@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="../libs/dropbox.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
Dropbox.AuthDriver.Popup.oauthReceiver();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html manifest="cache.manifest">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
var redirectUrl = location.href.substring(0, location.href.indexOf("html/gdrive-action.html")) + 'editor';
|
||||
var state = decodeURI((/state=(.+?)(&|$)/
|
||||
.exec(location.search) || [ , null ])[1]);
|
||||
if(state) {
|
||||
localStorage["gdrive.state"] = state;
|
||||
}
|
||||
window.location.replace(redirectUrl);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
@ -1,27 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function getParameter(name) {
|
||||
var regex = new RegExp(name + "=(.+?)(&|$)");
|
||||
try {
|
||||
return decodeURI(regex.exec(location.search)[1]);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
var client_id = getParameter("client_id");
|
||||
var scope = getParameter("scope") || 'repo,gist';
|
||||
var code = getParameter("code");
|
||||
if (client_id) {
|
||||
window.location.href = "https://github.com/login/oauth/authorize?client_id="
|
||||
+ client_id + "&scope=" + scope;
|
||||
} else {
|
||||
if (code) {
|
||||
localStorage["githubCode"] = code;
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
</html>
|