├── .gitignore ├── show.jpg ├── start.bat ├── static ├── favicon.ico └── css │ ├── img │ ├── 32px.png │ ├── diy │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── 1_close.png │ │ └── 1_open.png │ ├── loading.gif │ ├── line_conn.gif │ ├── throbber.gif │ ├── zTreeStandard.gif │ └── zTreeStandard.png │ ├── font │ └── firacode │ │ ├── eot │ │ ├── FiraCode-Bold.eot │ │ ├── FiraCode-Light.eot │ │ ├── FiraCode-Medium.eot │ │ └── FiraCode-Regular.eot │ │ ├── ttf │ │ ├── FiraCode-Bold.ttf │ │ ├── FiraCode-Light.ttf │ │ ├── FiraCode-Medium.ttf │ │ ├── FiraCode-Retina.ttf │ │ └── FiraCode-Regular.ttf │ │ ├── woff │ │ ├── FiraCode-Bold.woff │ │ ├── FiraCode-Light.woff │ │ ├── FiraCode-Medium.woff │ │ └── FiraCode-Regular.woff │ │ └── woff2 │ │ ├── FiraCode-Bold.woff2 │ │ ├── FiraCode-Light.woff2 │ │ ├── FiraCode-Medium.woff2 │ │ └── FiraCode-Regular.woff2 │ ├── images │ ├── ui-icons_444444_256x240.png │ ├── ui-icons_555555_256x240.png │ ├── ui-icons_777620_256x240.png │ ├── ui-icons_777777_256x240.png │ ├── ui-icons_cc0000_256x240.png │ └── ui-icons_ffffff_256x240.png │ ├── themes │ ├── basic │ │ └── assets │ │ │ └── fonts │ │ │ ├── icons.eot │ │ │ ├── icons.ttf │ │ │ └── icons.woff │ ├── default │ │ └── assets │ │ │ ├── fonts │ │ │ ├── icons.eot │ │ │ ├── icons.otf │ │ │ ├── icons.ttf │ │ │ ├── icons.woff │ │ │ ├── icons.woff2 │ │ │ ├── brand-icons.eot │ │ │ ├── brand-icons.ttf │ │ │ ├── brand-icons.woff │ │ │ ├── brand-icons.woff2 │ │ │ ├── outline-icons.eot │ │ │ ├── outline-icons.ttf │ │ │ ├── outline-icons.woff │ │ │ └── outline-icons.woff2 │ │ │ └── images │ │ │ └── flags.png │ ├── github │ │ └── assets │ │ │ └── fonts │ │ │ ├── octicons.ttf │ │ │ ├── octicons.woff │ │ │ └── octicons-local.ttf │ └── material │ │ └── assets │ │ └── fonts │ │ ├── icons.eot │ │ ├── icons.ttf │ │ ├── icons.woff │ │ └── icons.woff2 │ ├── components │ ├── sticky.min.css │ ├── tab.min.css │ ├── breadcrumb.min.css │ ├── video.min.css │ ├── rail.min.css │ ├── nag.min.css │ ├── sticky.css │ ├── embed.min.css │ ├── container.min.css │ ├── ad.min.css │ ├── tab.css │ ├── site.min.css │ ├── shape.min.css │ ├── breadcrumb.css │ ├── reset.min.css │ ├── comment.min.css │ ├── video.css │ ├── rail.css │ ├── nag.css │ ├── dimmer.min.css │ ├── feed.min.css │ ├── image.min.css │ ├── container.css │ ├── embed.css │ ├── placeholder.min.css │ ├── shape.css │ ├── loader.min.css │ ├── site.css │ ├── rating.min.js │ ├── ad.css │ ├── nag.min.js │ ├── reveal.min.css │ ├── item.min.css │ ├── site.min.js │ ├── divider.min.css │ ├── video.min.js │ └── comment.css │ ├── railscasts.min.css │ ├── jquery.highlighttextarea.min.css │ ├── codemirror-theme-idea.css │ ├── codemirror-theme-monokai.css │ ├── jquery.splitter.css │ └── codemirror.min.css ├── requirements.txt ├── sync ├── sync_utils │ ├── __init__.py │ ├── gitee_sync_utils.py │ ├── base_sync_utils.py │ └── netdisk_sync_utils.py ├── __init__.py ├── model.py └── view.py ├── core ├── __init__.py └── model.py ├── share ├── github_share.py └── __init__.py ├── setup.py ├── test ├── test_github_sync_utils.py ├── batch_change_note_id.py ├── batch_delete_remote.py ├── test_local_metadata.py ├── test_catalogdb.py ├── load_note_content_to_db.py ├── test_github_apiv3.py ├── sync_by_sharding.py └── test_onedrive.py ├── templates ├── sync_note_view.html ├── change_history.html ├── editor.html ├── sync_note_list.html └── base.html ├── config.sample.yml ├── README.md ├── app.py ├── common ├── __init__.py └── utils.py └── onekey_install.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | __pycache__/ 3 | *.log 4 | config.yml -------------------------------------------------------------------------------- /show.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/show.jpg -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/start.bat -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/css/img/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/32px.png -------------------------------------------------------------------------------- /static/css/img/diy/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/2.png -------------------------------------------------------------------------------- /static/css/img/diy/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/3.png -------------------------------------------------------------------------------- /static/css/img/diy/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/4.png -------------------------------------------------------------------------------- /static/css/img/diy/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/5.png -------------------------------------------------------------------------------- /static/css/img/diy/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/6.png -------------------------------------------------------------------------------- /static/css/img/diy/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/7.png -------------------------------------------------------------------------------- /static/css/img/diy/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/8.png -------------------------------------------------------------------------------- /static/css/img/diy/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/9.png -------------------------------------------------------------------------------- /static/css/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/loading.gif -------------------------------------------------------------------------------- /static/css/img/line_conn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/line_conn.gif -------------------------------------------------------------------------------- /static/css/img/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/throbber.gif -------------------------------------------------------------------------------- /static/css/img/diy/1_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/1_close.png -------------------------------------------------------------------------------- /static/css/img/diy/1_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/diy/1_open.png -------------------------------------------------------------------------------- /static/css/img/zTreeStandard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/zTreeStandard.gif -------------------------------------------------------------------------------- /static/css/img/zTreeStandard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/img/zTreeStandard.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyYAML>=5.1.1 2 | requests>=2.22.0 3 | Flask>=1.0.3 4 | Flask-SQLAlchemy>=2.4.0 5 | pywin32 6 | colorama>=0.4.4 -------------------------------------------------------------------------------- /static/css/font/firacode/eot/FiraCode-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/eot/FiraCode-Bold.eot -------------------------------------------------------------------------------- /static/css/font/firacode/ttf/FiraCode-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/ttf/FiraCode-Bold.ttf -------------------------------------------------------------------------------- /static/css/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /static/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /static/css/themes/basic/assets/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/basic/assets/fonts/icons.eot -------------------------------------------------------------------------------- /static/css/themes/basic/assets/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/basic/assets/fonts/icons.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/eot/FiraCode-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/eot/FiraCode-Light.eot -------------------------------------------------------------------------------- /static/css/font/firacode/eot/FiraCode-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/eot/FiraCode-Medium.eot -------------------------------------------------------------------------------- /static/css/font/firacode/ttf/FiraCode-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/ttf/FiraCode-Light.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/ttf/FiraCode-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/ttf/FiraCode-Medium.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/ttf/FiraCode-Retina.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/ttf/FiraCode-Retina.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/woff/FiraCode-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff/FiraCode-Bold.woff -------------------------------------------------------------------------------- /static/css/themes/basic/assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/basic/assets/fonts/icons.woff -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/icons.eot -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/icons.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/icons.otf -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/icons.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/eot/FiraCode-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/eot/FiraCode-Regular.eot -------------------------------------------------------------------------------- /static/css/font/firacode/ttf/FiraCode-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/ttf/FiraCode-Regular.ttf -------------------------------------------------------------------------------- /static/css/font/firacode/woff/FiraCode-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff/FiraCode-Light.woff -------------------------------------------------------------------------------- /static/css/font/firacode/woff/FiraCode-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff/FiraCode-Medium.woff -------------------------------------------------------------------------------- /static/css/font/firacode/woff/FiraCode-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff/FiraCode-Regular.woff -------------------------------------------------------------------------------- /static/css/font/firacode/woff2/FiraCode-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff2/FiraCode-Bold.woff2 -------------------------------------------------------------------------------- /static/css/font/firacode/woff2/FiraCode-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff2/FiraCode-Light.woff2 -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/icons.woff -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/icons.woff2 -------------------------------------------------------------------------------- /static/css/themes/default/assets/images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/images/flags.png -------------------------------------------------------------------------------- /static/css/themes/github/assets/fonts/octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/github/assets/fonts/octicons.ttf -------------------------------------------------------------------------------- /static/css/themes/github/assets/fonts/octicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/github/assets/fonts/octicons.woff -------------------------------------------------------------------------------- /static/css/themes/material/assets/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/material/assets/fonts/icons.eot -------------------------------------------------------------------------------- /static/css/themes/material/assets/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/material/assets/fonts/icons.ttf -------------------------------------------------------------------------------- /static/css/themes/material/assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/material/assets/fonts/icons.woff -------------------------------------------------------------------------------- /static/css/themes/material/assets/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/material/assets/fonts/icons.woff2 -------------------------------------------------------------------------------- /static/css/font/firacode/woff2/FiraCode-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff2/FiraCode-Medium.woff2 -------------------------------------------------------------------------------- /static/css/font/firacode/woff2/FiraCode-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/font/firacode/woff2/FiraCode-Regular.woff2 -------------------------------------------------------------------------------- /sync/sync_utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : __init__.py.py 4 | # @Author: wangms 5 | # @Date : 2019/12/20 6 | 7 | -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/brand-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/brand-icons.eot -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/brand-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/brand-icons.ttf -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/brand-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/brand-icons.woff -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/brand-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/brand-icons.woff2 -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/outline-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/outline-icons.eot -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/outline-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/outline-icons.ttf -------------------------------------------------------------------------------- /static/css/themes/github/assets/fonts/octicons-local.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/github/assets/fonts/octicons-local.ttf -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/outline-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/outline-icons.woff -------------------------------------------------------------------------------- /static/css/themes/default/assets/fonts/outline-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmings/IdeaNote/HEAD/static/css/themes/default/assets/fonts/outline-icons.woff2 -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : __init__.py 4 | # @Author: wangms 5 | # @Date : 2018/8/7 6 | from flask import Blueprint 7 | 8 | core = Blueprint('core', __name__) 9 | 10 | from . import view -------------------------------------------------------------------------------- /sync/__init__.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : __init__.py 4 | # @Author: wangms 5 | # @Date : 2019/5/28 6 | 7 | from flask import Blueprint 8 | 9 | sync = Blueprint('sync', __name__) 10 | 11 | from . import view -------------------------------------------------------------------------------- /share/github_share.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : github_share.py 4 | # @Author: wangms 5 | # @Date : 2019/11/13 6 | 7 | class GithubShare(object): 8 | def __init__(self): 9 | pass 10 | 11 | def run(self): 12 | pass -------------------------------------------------------------------------------- /sync/sync_utils/gitee_sync_utils.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : gitee_sync_utils.py 4 | # @Author: wangms 5 | # @Date : 2019/12/20 6 | 7 | from .base_sync_utils import BaseSyncUtils 8 | 9 | class GiteeSyncUtils(BaseSyncUtils): 10 | def __init__(self): 11 | pass -------------------------------------------------------------------------------- /share/__init__.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : __init__.py.py 4 | # @Author: wangms 5 | # @Date : 2019/11/13 6 | import sys 7 | import utils 8 | 9 | 10 | @utils.oneday('yesterday') 11 | def main(dateStr): 12 | pass 13 | 14 | 15 | if __name__ == '__main__': 16 | sys.exit(main()) 17 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : setup.py 4 | # @Author: wangms 5 | # @Date : 2019/1/12 6 | from setuptools import find_packages, setup 7 | 8 | setup( 9 | name='IdeaNote', 10 | version='1.0.0', 11 | packages=find_packages(), 12 | include_package_data=True, 13 | zip_safe=False, 14 | install_requires=[ 15 | 'flask', 16 | 'Flask-SQLAlchemy' 17 | ], 18 | ) -------------------------------------------------------------------------------- /test/test_github_sync_utils.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : test_github_sync_utils.py 4 | # @Author: wangms 5 | # @Date : 2019/12/21 6 | import sys 7 | from sync.sync_utils.github_sync_utils import GithubSyncUtils 8 | 9 | if __name__ == '__main__': 10 | from common import conf 11 | sync_utils = GithubSyncUtils(conf.sync_connection_info) 12 | sync_utils.init_version_info() 13 | 14 | 15 | -------------------------------------------------------------------------------- /sync/model.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : model.py 4 | # @Author: wangms 5 | # @Date : 2019/12/18 6 | 7 | from app import db 8 | 9 | 10 | class SyncInfo(db.Model): 11 | __tablename__ = "t_sync_info" 12 | id = db.Column(db.Integer, primary_key=True) 13 | current_version = db.Column(db.Integer) 14 | latest_version = db.Column(db.Integer) 15 | modification_time = db.Column(db.DateTime) 16 | -------------------------------------------------------------------------------- /test/batch_change_note_id.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : batch_change_note_id.py 4 | # @Author: wangms 5 | # @Date : 2019/8/2 6 | 7 | from core.model import Catalog, db 8 | from uuid import uuid1 9 | 10 | def change_note_id(): 11 | for n in Catalog.query.all(): 12 | n.id = uuid1().hex 13 | db.session.commit() 14 | 15 | for n in Catalog.query.all(): 16 | pn = Catalog.query.filter_by(sha=n.parent_id).first() 17 | n.parent_id = getattr(pn, "id") if hasattr(pn, "id") else None 18 | 19 | db.session.commit() 20 | 21 | if __name__ == '__main__': 22 | change_note_id() -------------------------------------------------------------------------------- /static/css/components/sticky.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Sticky 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.sticky{position:static;-webkit-transition:none;transition:none;z-index:800}.ui.sticky.bound{position:absolute;left:auto;right:auto}.ui.sticky.fixed{position:fixed;left:auto;right:auto}.ui.sticky.bound.top,.ui.sticky.fixed.top{top:0;bottom:auto}.ui.sticky.bound.bottom,.ui.sticky.fixed.bottom{top:auto;bottom:0}.ui.native.sticky{position:-webkit-sticky;position:-moz-sticky;position:-ms-sticky;position:-o-sticky;position:sticky} -------------------------------------------------------------------------------- /templates/sync_note_view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

文本内容:

4 | 7 |
8 |
9 | {% for i in images %} 10 |
11 |

图片{{ loop.index }}:

12 | 13 |
14 | {% endfor %} 15 |
16 |
-------------------------------------------------------------------------------- /config.sample.yml: -------------------------------------------------------------------------------- 1 | IdeaNote: 2 | port: 5555 3 | hide_window: False 4 | auth_code: 123456 5 | sync: 6 | method: github 7 | connection: 8 | owner: xxxxxx 9 | email: 123456@xxx.yyy 10 | repo: xxxxxx 11 | access_token: 20a50aaxxxxxxxxxxxxxxxxxxd21781 12 | branch: master 13 | work_dir: D:\ideanote_sync 14 | db: 15 | config: 16 | SQLALCHEMY_ECHO: False 17 | CREATE_DB_IF_NOT_FOUND: True 18 | JSON_AS_ASCII: False 19 | SECRET_KEY: '123456789' 20 | SQLALCHEMY_DATABASE_URI: sqlite:///ideanote.db?check_same_thread=False 21 | SQLALCHEMY_TRACK_MODIFICATIONS: False 22 | log: 23 | directory: D:\log 24 | formatter: "%(asctime)s %(levelname)s %(filename)s %(lineno)d: %(message)s" 25 | urlmark: 26 | sync: True 27 | sync_file: D:\ideanote_sync\chrome_bookmark.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IdeaNote 2 | ============ 3 | IdeaNote是一款基于WEB的集树形目录管理、`Markdown`编辑、`免费增量离线`同步等众多优秀功能于一身的开源知识管理平台。 4 | > IdeaNote开发语言是Python3.7 + Flask框架 5 | 6 | ![DEMO](show.jpg) 7 | 8 | 9 | ### 一. 设计初衷 10 | 努力把`IdeaNote`打造成一款功能强大个人知识管理**平台**,是平台而不仅仅是笔记软件。 11 | 12 | ### 二. 功能列表: 13 | 1. 多电脑间快速`增量`数据`离线`同步,同步介质可以选择网盘、GitHub,也可以自己实现BaseSyncUtils类自定义同步 14 | 2. 树形目录管理,通过拖拽或者方向箭头调整笔记的排列顺序和层级 15 | 3. 自动文档大纲生成 16 | 4. 快捷键进入文档编辑模式、焦点编辑模式、返回阅读模式 17 | 5. 目录加密功能 18 | 6. 文章编辑历史查阅功能、同步列表和查看功能 19 | 20 | ### 三. 未来功能计划: 21 | 1. 增加更多同步方案, 如`GitHub`同步等 22 | 3. 支持思维导图 23 | 4. 支持`TODO`及提醒功能 24 | 5. 网页链接分享、PDF分享功能 25 | 6. 标题检索、全文检索功能 26 | 27 | ### 四. 安装说明 28 | 1. 安装Python3.7及以上版本 29 | 2. 运行`python onekey_install.py`根据提示创建和修改config.yml文件 30 | 3. 在浏览器访问http://localhost:5555 31 | 32 | > IdeaNote的启动方式是flask应用的开发环境的启动方式,用户可以根据自己需要修改启动方式 33 | 34 | > 如果在Windows上运行可以参考start.bat修改一下作为自己的启动脚本 -------------------------------------------------------------------------------- /static/css/railscasts.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:1em;background:#232323;color:#e6e1dc;border-radius: 4px;}.hljs-comment,.hljs-quote{color:#474b4e;}.hljs-keyword,.hljs-selector-tag{color:#c26230}.hljs-string,.hljs-number,.hljs-regexp,.hljs-variable,.hljs-template-variable{color:#a5c261}.hljs-subst{color:#519f50}.hljs-tag,.hljs-name{color:#e8bf6a}.hljs-type{color:#da4939}.hljs-symbol,.hljs-bullet,.hljs-built_in,.hljs-builtin-name,.hljs-attr,.hljs-link{color:#6d9cbe}.hljs-params{color:#d0d0ff}.hljs-attribute{color:#cda869}.hljs-meta{color:#9b859d}.hljs-title,.hljs-section{color:#ffc66d}.hljs-addition{background-color:#144212;color:#e6e1dc;display:inline-block;width:100%}.hljs-deletion{background-color:#600;color:#e6e1dc;display:inline-block;width:100%}.hljs-selector-class{color:#9b703f}.hljs-selector-id{color:#8b98ab}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-link{text-decoration:underline} -------------------------------------------------------------------------------- /static/css/jquery.highlighttextarea.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery highlightTextarea 3.1.3 3 | * Copyright 2014-2016 Damien "Mistic" Sorel (http://www.strangeplanet.fr) 4 | * Licensed under MIT (http://opensource.org/licenses/MIT) 5 | */ 6 | .highlightTextarea{position:relative}.highlightTextarea .highlightTextarea-container{position:absolute;margin:0;overflow:hidden}.highlightTextarea .highlightTextarea-highlighter{position:relative;border:none;padding:0;margin:0;color:transparent;cursor:text;overflow:hidden;white-space:pre-wrap;word-wrap:break-word}.highlightTextarea.debug .highlightTextarea-highlighter{color:red;border:1px solid red;margin:-1px}.highlightTextarea mark{line-height:inherit;color:transparent;margin:0;padding:0}.highlightTextarea input,.highlightTextarea textarea{position:absolute;left:0;top:0;resize:none;white-space:pre-wrap;word-wrap:break-word}.highlightTextarea .ui-wrapper{margin:0!important}.highlightTextarea .ui-resizable-se{bottom:15px;right:0} -------------------------------------------------------------------------------- /test/batch_delete_remote.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : batch_delete_remote.py 4 | # @Author: wangms 5 | # @Date : 2019/8/8 6 | import requests 7 | import json 8 | 9 | def test_batch_delete_remote(): 10 | url = "https://api.github.com/repos/bmark-sync/notesync/contents" 11 | resp = requests.get(url, data={ 12 | "ref": "master" 13 | }) 14 | for v in resp.json(): 15 | print(v) 16 | if v["type"] == "file" and v["name"] != "README.md": 17 | url = "https://api.github.com/repos/bmark-sync/notesync/contens/{}".format(v["name"]) 18 | resp = requests.delete(url, data=json.dumps({ 19 | "message": "delete a file or folder", 20 | "sha": v["sha"], 21 | "branch": "master" 22 | }), params={ 23 | "access_token": "c64b06c644660e1819f9077163f5f670c680dad7" 24 | }) 25 | 26 | print(resp.json()) 27 | 28 | 29 | -------------------------------------------------------------------------------- /static/css/components/tab.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Tab 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.tab{display:none}.ui.tab.active,.ui.tab.open{display:block}.ui.tab.loading{position:relative;overflow:hidden;display:block;min-height:250px}.ui.tab.loading *{position:relative!important;left:-10000px!important}.ui.tab.loading.segment:before,.ui.tab.loading:before{position:absolute;content:'';top:100px;left:50%;margin:-1.25em 0 0 -1.25em;width:2.5em;height:2.5em;border-radius:500rem;border:.2em solid rgba(0,0,0,.1)}.ui.tab.loading.segment:after,.ui.tab.loading:after{position:absolute;content:'';top:100px;left:50%;margin:-1.25em 0 0 -1.25em;width:2.5em;height:2.5em;-webkit-animation:button-spin .6s linear;animation:button-spin .6s linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;border-radius:500rem;border-color:#767676 transparent transparent;border-style:solid;border-width:.2em;-webkit-box-shadow:0 0 0 1px transparent;box-shadow:0 0 0 1px transparent} -------------------------------------------------------------------------------- /test/test_local_metadata.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : test_local_metadata.py 4 | # @Author: wangms 5 | # @Date : 2019/8/1 6 | 7 | from dataclasses import dataclass 8 | import sqlite3 9 | 10 | 11 | @dataclass 12 | class MetaData(object): 13 | id: int 14 | title: str 15 | parent_id: int 16 | seq_no: int 17 | status: int 18 | creation_time: str 19 | modification_time: str 20 | 21 | 22 | def main(): 23 | local_metadata = {} 24 | with sqlite3.connect("E:\\MyNote\\ideanote.db") as conn: 25 | cursor = conn.cursor() 26 | cursor.execute("select id,title,parent_id,seq_no,status,creation_time,modification_time from t_catalog") 27 | for id,title,parent_id,seq_no,status,creation_time,modification_time in cursor: 28 | local_metadata[id] = { 29 | "title": title, 30 | "parent_id": parent_id, 31 | "seq_no": seq_no, 32 | "status": status, 33 | "creation_time": str(creation_time), 34 | "modification_time": str(modification_time) 35 | } 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /templates/change_history.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | {% for n in notes %} 5 |
8 |
9 | {{ n.title }} 10 |
11 | {{ n.status }}, 同步状态: {{ n.sync_status }} 12 | {% if n.sync_status == "未同步" %} 13 | 14 | {% endif %}, 修改时间: {{ n.change_time }} 15 |
16 |
17 |
18 | {% endfor %} 19 |
20 | 21 |
22 | 29 | -------------------------------------------------------------------------------- /static/css/components/breadcrumb.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Breadcrumb 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.breadcrumb{line-height:1;display:inline-block;margin:0 0;vertical-align:middle}.ui.breadcrumb:first-child{margin-top:0}.ui.breadcrumb:last-child{margin-bottom:0}.ui.breadcrumb .divider{display:inline-block;opacity:.7;margin:0 .21428571rem 0;font-size:.92857143em;color:rgba(0,0,0,.4);vertical-align:baseline}.ui.breadcrumb a{color:#4183c4}.ui.breadcrumb a:hover{color:#1e70bf}.ui.breadcrumb .icon.divider{font-size:.85714286em;vertical-align:baseline}.ui.breadcrumb a.section{cursor:pointer}.ui.breadcrumb .section{display:inline-block;margin:0;padding:0}.ui.breadcrumb.segment{display:inline-block;padding:.78571429em 1em}.ui.breadcrumb .active.section{font-weight:700}.ui.mini.breadcrumb{font-size:.78571429rem}.ui.tiny.breadcrumb{font-size:.85714286rem}.ui.small.breadcrumb{font-size:.92857143rem}.ui.breadcrumb{font-size:1rem}.ui.large.breadcrumb{font-size:1.14285714rem}.ui.big.breadcrumb{font-size:1.28571429rem}.ui.huge.breadcrumb{font-size:1.42857143rem}.ui.massive.breadcrumb{font-size:1.71428571rem} -------------------------------------------------------------------------------- /sync/sync_utils/base_sync_utils.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : base_sync_utils.py 4 | # @Author: wangms 5 | # @Date : 2019/12/19 6 | 7 | from abc import ABC, abstractmethod 8 | 9 | 10 | class BaseSyncUtils(ABC): 11 | @abstractmethod 12 | def is_online(self): 13 | pass 14 | 15 | @abstractmethod 16 | def init_version_info(self): 17 | pass 18 | 19 | @abstractmethod 20 | def load_version_info(self) -> dict: 21 | pass 22 | 23 | @abstractmethod 24 | def dump_version_info(self, version_info: dict) -> bool: 25 | pass 26 | 27 | @abstractmethod 28 | def load_note_info(self, version: int) -> dict: 29 | pass 30 | 31 | @abstractmethod 32 | def load_latest_note_info(self, note_id) -> dict: 33 | pass 34 | 35 | @abstractmethod 36 | def load_note_info_by_version_note_id(self,version, note_id) -> dict: 37 | pass 38 | 39 | @abstractmethod 40 | def dump_note_info(self, note_info: dict) -> bool: 41 | pass 42 | 43 | @abstractmethod 44 | def fetch_sync_note_list(self): 45 | pass 46 | 47 | @abstractmethod 48 | def delete_obsolete_change(self, day:int=30): 49 | pass 50 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : control.py 4 | # @Author: wangms 5 | # @Date : 2018/8/6 6 | import os, platform 7 | from flask import Flask, send_from_directory 8 | from flask_sqlalchemy import SQLAlchemy 9 | from common import conf, fetch_logger 10 | 11 | if platform.system() == "Windows" and conf.hide_window: 12 | import win32api, win32gui 13 | 14 | ct = win32api.GetConsoleTitle() 15 | hd = win32gui.FindWindow(0, ct) 16 | win32gui.ShowWindow(hd, 0) 17 | 18 | app = Flask(__name__) 19 | app.config.from_mapping(conf.db_config) 20 | app.config['SECRET_KEY'] = "12345" 21 | 22 | logger = fetch_logger(logger_name="IdeaNote", log_filename="idea_note.log") 23 | app.logger.handlers = logger.handlers 24 | 25 | db = SQLAlchemy(app) 26 | 27 | 28 | @app.route('/static/js/', methods=["GET"]) 29 | def send_js(path): 30 | return send_from_directory('static/js', path, mimetype="application/javascript") 31 | 32 | 33 | from sync import sync 34 | 35 | app.register_blueprint(sync) 36 | 37 | from core import core 38 | 39 | app.register_blueprint(core) 40 | 41 | # app.app_context().push() 42 | # db.drop_all() 43 | # db.create_all() 44 | 45 | 46 | if __name__ == '__main__': 47 | app.run(port=conf.app_port, threaded=True) 48 | -------------------------------------------------------------------------------- /static/css/components/video.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.0.0 - Video 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Copyright 2014 Contributors 7 | * Released under the MIT license 8 | * http://opensource.org/licenses/MIT 9 | * 10 | */.ui.video{background-color:#ddd;position:relative;max-width:100%;padding-bottom:56.25%;height:0;overflow:hidden}.ui.video .placeholder{background-color:#333}.ui.video .play{cursor:pointer;position:absolute;top:0;left:0;z-index:10;width:100%;height:100%;background:0 0;-webkit-transition:background .2s ease;transition:background .2s ease}.ui.video .play.icon:before{position:absolute;top:50%;left:50%;z-index:11;-webkit-transform:translateX(-50%)translateY(-50%);-ms-transform:translateX(-50%)translateY(-50%);transform:translateX(-50%)translateY(-50%);color:rgba(255,255,255,.7);font-size:7rem;text-shadow:2px 2px 0 rgba(0,0,0,.15);-webkit-transition:color .2s ease;transition:color .2s ease}.ui.video .placeholder{position:absolute;top:0;left:0;display:block;width:100%;height:100%}.ui.video .embed embed,.ui.video .embed iframe,.ui.video .embed object{position:absolute;border:none;width:100%;height:100%;top:0;left:0;margin:0;padding:0}.ui.video .play:hover{background:0 0}.ui.video .play:hover:before{color:#fff}.ui.active.video .placeholder,.ui.active.video .play{display:none}.ui.active.video .embed{display:inline} -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : __init__.py.py 4 | # @Author: wangms 5 | # @Date : 2019/7/23 6 | from enum import IntEnum 7 | from common.utils import conf, timestamp_from_str, timestamp_to_str, timestamp_max, fetch_logger, Resp 8 | 9 | 10 | class SyncStatusEnum(IntEnum): 11 | has_sync = 1 12 | need_sync = 2 13 | 14 | 15 | class NoteStatusEnum(IntEnum): 16 | create = 1 17 | update_title = 2 18 | update_content = 3 19 | update_position = 4 20 | update_lock = 5 21 | need_merge = 6 22 | manual_sync = 7 23 | delete = -1 24 | 25 | 26 | class PasswordStatusEnum(IntEnum): 27 | no_password = 0 28 | has_password = 1 29 | 30 | 31 | class Result(object): 32 | def __init__(self, status, content=None): 33 | self.status = status 34 | self.content = content 35 | 36 | 37 | status_text_mapping = { 38 | NoteStatusEnum.create.value: "新建笔记", 39 | NoteStatusEnum.update_title.value: "更新标题", 40 | NoteStatusEnum.update_content.value: "更新内容", 41 | NoteStatusEnum.update_lock.value: "更新密码", 42 | NoteStatusEnum.update_position.value: "更新顺序", 43 | NoteStatusEnum.manual_sync.value: "手工同步", 44 | NoteStatusEnum.delete.value: "删除笔记" 45 | } 46 | 47 | __all__ = ("Result", "conf", "timestamp_from_str", "timestamp_to_str", "timestamp_max", "fetch_logger", "Resp") 48 | -------------------------------------------------------------------------------- /static/css/components/rail.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Rail 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.rail{position:absolute;top:0;width:300px;height:100%}.ui.left.rail{left:auto;right:100%;padding:0 2rem 0 0;margin:0 2rem 0 0}.ui.right.rail{left:100%;right:auto;padding:0 0 0 2rem;margin:0 0 0 2rem}.ui.left.internal.rail{left:0;right:auto;padding:0 0 0 2rem;margin:0 0 0 2rem}.ui.right.internal.rail{left:auto;right:0;padding:0 2rem 0 0;margin:0 2rem 0 0}.ui.dividing.rail{width:302.5px}.ui.left.dividing.rail{padding:0 2.5rem 0 0;margin:0 2.5rem 0 0;border-right:1px solid rgba(34,36,38,.15)}.ui.right.dividing.rail{border-left:1px solid rgba(34,36,38,.15);padding:0 0 0 2.5rem;margin:0 0 0 2.5rem}.ui.close.rail{width:calc(300px + 1em)}.ui.close.left.rail{padding:0 1em 0 0;margin:0 1em 0 0}.ui.close.right.rail{padding:0 0 0 1em;margin:0 0 0 1em}.ui.very.close.rail{width:calc(300px + .5em)}.ui.very.close.left.rail{padding:0 .5em 0 0;margin:0 .5em 0 0}.ui.very.close.right.rail{padding:0 0 0 .5em;margin:0 0 0 .5em}.ui.attached.left.rail,.ui.attached.right.rail{padding:0;margin:0}.ui.mini.rail{font-size:.78571429rem}.ui.tiny.rail{font-size:.85714286rem}.ui.small.rail{font-size:.92857143rem}.ui.rail{font-size:1rem}.ui.large.rail{font-size:1.14285714rem}.ui.big.rail{font-size:1.28571429rem}.ui.huge.rail{font-size:1.42857143rem}.ui.massive.rail{font-size:1.71428571rem} -------------------------------------------------------------------------------- /static/css/components/nag.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Nag 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.nag{display:none;opacity:.95;position:relative;top:0;left:0;z-index:999;min-height:0;width:100%;margin:0;padding:.75em 1em;background:#555;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.2);box-shadow:0 1px 2px 0 rgba(0,0,0,.2);font-size:1rem;text-align:center;color:rgba(0,0,0,.87);border-radius:0 0 .28571429rem .28571429rem;-webkit-transition:.2s background ease;transition:.2s background ease}a.ui.nag{cursor:pointer}.ui.nag>.title{display:inline-block;margin:0 .5em;color:#fff}.ui.nag>.close.icon{cursor:pointer;opacity:.4;position:absolute;top:50%;right:1em;font-size:1em;margin:-.5em 0 0;color:#fff;-webkit-transition:opacity .2s ease;transition:opacity .2s ease}.ui.nag:hover{background:#555;opacity:1}.ui.nag .close:hover{opacity:1}.ui.overlay.nag{position:absolute;display:block}.ui.fixed.nag{position:fixed}.ui.bottom.nag,.ui.bottom.nags{border-radius:.28571429rem .28571429rem 0 0;top:auto;bottom:0}.ui.inverted.nag,.ui.inverted.nags .nag{background-color:#f3f4f5;color:rgba(0,0,0,.85)}.ui.inverted.nag .close,.ui.inverted.nag .title,.ui.inverted.nags .nag .close,.ui.inverted.nags .nag .title{color:rgba(0,0,0,.4)}.ui.nags .nag{border-radius:0!important}.ui.nags .nag:last-child{border-radius:0 0 .28571429rem .28571429rem}.ui.bottom.nags .nag:last-child{border-radius:.28571429rem .28571429rem 0 0} -------------------------------------------------------------------------------- /static/css/components/sticky.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Sticky 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Sticky 14 | *******************************/ 15 | 16 | .ui.sticky { 17 | position: static; 18 | -webkit-transition: none; 19 | transition: none; 20 | z-index: 800; 21 | } 22 | 23 | 24 | /******************************* 25 | States 26 | *******************************/ 27 | 28 | 29 | /* Bound */ 30 | .ui.sticky.bound { 31 | position: absolute; 32 | left: auto; 33 | right: auto; 34 | } 35 | 36 | /* Fixed */ 37 | .ui.sticky.fixed { 38 | position: fixed; 39 | left: auto; 40 | right: auto; 41 | } 42 | 43 | /* Bound/Fixed Position */ 44 | .ui.sticky.bound.top, 45 | .ui.sticky.fixed.top { 46 | top: 0px; 47 | bottom: auto; 48 | } 49 | .ui.sticky.bound.bottom, 50 | .ui.sticky.fixed.bottom { 51 | top: auto; 52 | bottom: 0px; 53 | } 54 | 55 | 56 | /******************************* 57 | Types 58 | *******************************/ 59 | 60 | .ui.native.sticky { 61 | position: -webkit-sticky; 62 | position: -moz-sticky; 63 | position: -ms-sticky; 64 | position: -o-sticky; 65 | position: sticky; 66 | } 67 | 68 | 69 | /******************************* 70 | Theme Overrides 71 | *******************************/ 72 | 73 | 74 | 75 | /******************************* 76 | Site Overrides 77 | *******************************/ 78 | 79 | -------------------------------------------------------------------------------- /test/test_catalogdb.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : test_catalogdb.py 4 | # @Author: wangms 5 | # @Date : 2019/5/10 6 | 7 | 8 | from catalogdb import DBOperator 9 | from catalogdb.model import Item,User 10 | from datetime import datetime 11 | 12 | class app(): 13 | pass 14 | 15 | app.config = {} 16 | app.config["JSON_DB_FILE"] = "d:\\" 17 | app.config["CREATE_DB_IF_NOT_FOUND"] = True 18 | catalog = DBOperator(app) 19 | 20 | class TestCatalogDB(): 21 | 22 | def test_insert_item(self): 23 | catalog.insert_item(Item( 24 | title="test10", 25 | parent_id=0, 26 | children=[], 27 | icon_path="", 28 | file_hash="", 29 | file_path="", 30 | status=1, 31 | creation_time=datetime.now(), 32 | modification_time=datetime.now() 33 | )) 34 | 35 | def test_update_item(self): 36 | item = catalog.select_item_by_id(1) 37 | item.title="test3" 38 | catalog.update_item(item) 39 | 40 | def test_delete_item(self): 41 | item = catalog.select_item_by_id(1) 42 | catalog.delete_item(item) 43 | 44 | def test_select_item_by_id(self): 45 | print(catalog.select_item_by_id(2)) 46 | 47 | def test_insert_user(self): 48 | user = User( 49 | username='w', 50 | password='w', 51 | regist_time= datetime.now() 52 | ) 53 | catalog.insert_user(user) 54 | 55 | def test_update_user(self): 56 | user = catalog.select_user_by_username("w") 57 | user.edit_item_id = 2 58 | catalog.update_user(user) 59 | 60 | -------------------------------------------------------------------------------- /static/css/components/embed.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Video 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.embed{position:relative;max-width:100%;height:0;overflow:hidden;background:#dcddde;padding-bottom:56.25%}.ui.embed embed,.ui.embed iframe,.ui.embed object{position:absolute;border:none;width:100%;height:100%;top:0;left:0;margin:0;padding:0}.ui.embed>.embed{display:none}.ui.embed>.placeholder{position:absolute;cursor:pointer;top:0;left:0;display:block;width:100%;height:100%;background-color:radial-gradient(transparent 45%,rgba(0,0,0,.3))}.ui.embed>.icon{cursor:pointer;position:absolute;top:0;left:0;width:100%;height:100%;z-index:2}.ui.embed>.icon:after{position:absolute;top:0;left:0;width:100%;height:100%;z-index:3;content:'';background:-webkit-radial-gradient(transparent 45%,rgba(0,0,0,.3));background:radial-gradient(transparent 45%,rgba(0,0,0,.3));opacity:.5;-webkit-transition:opacity .5s ease;transition:opacity .5s ease}.ui.embed>.icon:before{position:absolute;top:50%;left:50%;z-index:4;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);color:#fff;font-size:6rem;text-shadow:0 2px 10px rgba(34,36,38,.2);-webkit-transition:opacity .5s ease,color .5s ease;transition:opacity .5s ease,color .5s ease;z-index:10}.ui.embed .icon:hover:after{background:-webkit-radial-gradient(transparent 45%,rgba(0,0,0,.3));background:radial-gradient(transparent 45%,rgba(0,0,0,.3));opacity:1}.ui.embed .icon:hover:before{color:#fff}.ui.active.embed>.icon,.ui.active.embed>.placeholder{display:none}.ui.active.embed>.embed{display:block}.ui.square.embed{padding-bottom:100%}.ui[class*="4:3"].embed{padding-bottom:75%}.ui[class*="16:9"].embed{padding-bottom:56.25%}.ui[class*="21:9"].embed{padding-bottom:42.85714286%} -------------------------------------------------------------------------------- /static/css/codemirror-theme-idea.css: -------------------------------------------------------------------------------- 1 | /** 2 | Name: IDEA default theme 3 | From IntelliJ IDEA by JetBrains 4 | */ 5 | 6 | .cm-s-idea span.cm-meta { color: #808000; } 7 | .cm-s-idea span.cm-number { color: #0000FF; } 8 | .cm-s-idea span.cm-keyword { line-height: 1em; font-weight: bold; color: #000080; } 9 | .cm-s-idea span.cm-atom { font-weight: bold; color: #000080; } 10 | .cm-s-idea span.cm-def { color: #000000; } 11 | .cm-s-idea span.cm-variable { color: black; } 12 | .cm-s-idea span.cm-variable-2 { color: black; } 13 | .cm-s-idea span.cm-variable-3, .cm-s-idea span.cm-type { color: black; } 14 | .cm-s-idea span.cm-property { color: black; } 15 | .cm-s-idea span.cm-operator { color: black; } 16 | .cm-s-idea span.cm-comment { color: #808080; } 17 | .cm-s-idea span.cm-string { color: #008000; } 18 | .cm-s-idea span.cm-string-2 { color: #008000; } 19 | .cm-s-idea span.cm-qualifier { color: #555; } 20 | .cm-s-idea span.cm-error { color: #FF0000; } 21 | .cm-s-idea span.cm-attribute { color: #0000FF; } 22 | .cm-s-idea span.cm-tag { color: #000080; } 23 | .cm-s-idea span.cm-link { color: #0000FF; } 24 | .cm-s-idea .CodeMirror-activeline-background { background: #FFFAE3; } 25 | 26 | .cm-s-idea span.cm-builtin { color: #30a; } 27 | .cm-s-idea span.cm-bracket { color: #cc7; } 28 | .cm-s-idea { font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;} 29 | 30 | 31 | .cm-s-idea .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } 32 | 33 | .CodeMirror-hints.idea { 34 | font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; 35 | color: #616569; 36 | background-color: #ebf3fd !important; 37 | } 38 | 39 | .CodeMirror-hints.idea .CodeMirror-hint-active { 40 | background-color: #a2b8c9 !important; 41 | color: #5c6065 !important; 42 | } -------------------------------------------------------------------------------- /core/model.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : model.py 4 | # @Author: wangms 5 | # @Date : 2019/7/31 6 | from app import db 7 | from uuid import uuid1 8 | from datetime import datetime 9 | from common import NoteStatusEnum, SyncStatusEnum, PasswordStatusEnum 10 | 11 | 12 | class Catalog(db.Model): 13 | __tablename__ = "t_catalog" 14 | id = db.Column(db.String, primary_key=True, default=lambda: uuid1().hex) 15 | title = db.Column(db.String(100)) 16 | icon = db.Column(db.Binary) 17 | parent_id = db.Column(db.String) 18 | content = db.Column(db.Binary) 19 | remote_content = db.Column(db.Binary) 20 | seq_no = db.Column(db.Integer, autoincrement=True) 21 | with_passwd = db.Column(db.Integer, default=PasswordStatusEnum.no_password.value) 22 | status = db.Column(db.Integer, default=NoteStatusEnum.create.value) 23 | sync_status = db.Column(db.Integer, default=SyncStatusEnum.need_sync.value) 24 | creation_time = db.Column(db.DateTime, default=datetime.now()) 25 | modification_time = db.Column(db.DateTime) 26 | 27 | 28 | class Image(db.Model): 29 | __tablename__ = "t_note_reference_image" 30 | id = db.Column(db.String, primary_key=True, default=lambda: uuid1().hex) 31 | note_id = db.Column(db.String, db.ForeignKey('t_catalog.id')) 32 | image = db.Column(db.Binary) 33 | mime_type = db.Column(db.String) 34 | status = db.Column(db.Integer, default=NoteStatusEnum.create.value) 35 | creation_time = db.Column(db.DateTime, default=datetime.now()) 36 | modification_time = db.Column(db.DateTime) 37 | 38 | 39 | class SyncRecord(db.Model): 40 | __tablename__ = "t_sync_log" 41 | id = db.Column(db.Integer, primary_key=True, autoincrement=True) 42 | sync_sha = db.Column(db.String(100)) 43 | creation_time = db.Column(db.DateTime, default=datetime.now()) 44 | modification_time = db.Column(db.DateTime) 45 | -------------------------------------------------------------------------------- /static/css/components/container.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Container 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.container{display:block;max-width:100%!important}@media only screen and (max-width:767px){.ui.container{width:auto!important;margin-left:1em!important;margin-right:1em!important}.ui.grid.container{width:auto!important}.ui.relaxed.grid.container{width:auto!important}.ui.very.relaxed.grid.container{width:auto!important}}@media only screen and (min-width:768px) and (max-width:991px){.ui.container{width:723px;margin-left:auto!important;margin-right:auto!important}.ui.grid.container{width:calc(723px + 2rem)!important}.ui.relaxed.grid.container{width:calc(723px + 3rem)!important}.ui.very.relaxed.grid.container{width:calc(723px + 5rem)!important}}@media only screen and (min-width:992px) and (max-width:1199px){.ui.container{width:933px;margin-left:auto!important;margin-right:auto!important}.ui.grid.container{width:calc(933px + 2rem)!important}.ui.relaxed.grid.container{width:calc(933px + 3rem)!important}.ui.very.relaxed.grid.container{width:calc(933px + 5rem)!important}}@media only screen and (min-width:1200px){.ui.container{width:1127px;margin-left:auto!important;margin-right:auto!important}.ui.grid.container{width:calc(1127px + 2rem)!important}.ui.relaxed.grid.container{width:calc(1127px + 3rem)!important}.ui.very.relaxed.grid.container{width:calc(1127px + 5rem)!important}}.ui.text.container{font-family:Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;max-width:700px!important;line-height:1.5}.ui.text.container{font-size:1.14285714rem}.ui.fluid.container{width:100%}.ui[class*="left aligned"].container{text-align:left}.ui[class*="center aligned"].container{text-align:center}.ui[class*="right aligned"].container{text-align:right}.ui.justified.container{text-align:justify;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto} -------------------------------------------------------------------------------- /static/css/components/ad.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Ad 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Copyright 2013 Contributors 7 | * Released under the MIT license 8 | * http://opensource.org/licenses/MIT 9 | * 10 | */.ui.ad{display:block;overflow:hidden;margin:1em 0}.ui.ad:first-child{margin:0}.ui.ad:last-child{margin:0}.ui.ad iframe{margin:0;padding:0;border:none;overflow:hidden}.ui.leaderboard.ad{width:728px;height:90px}.ui[class*="medium rectangle"].ad{width:300px;height:250px}.ui[class*="large rectangle"].ad{width:336px;height:280px}.ui[class*="half page"].ad{width:300px;height:600px}.ui.square.ad{width:250px;height:250px}.ui[class*="small square"].ad{width:200px;height:200px}.ui[class*="small rectangle"].ad{width:180px;height:150px}.ui[class*="vertical rectangle"].ad{width:240px;height:400px}.ui.button.ad{width:120px;height:90px}.ui[class*="square button"].ad{width:125px;height:125px}.ui[class*="small button"].ad{width:120px;height:60px}.ui.skyscraper.ad{width:120px;height:600px}.ui[class*="wide skyscraper"].ad{width:160px}.ui.banner.ad{width:468px;height:60px}.ui[class*="vertical banner"].ad{width:120px;height:240px}.ui[class*="top banner"].ad{width:930px;height:180px}.ui[class*="half banner"].ad{width:234px;height:60px}.ui[class*="large leaderboard"].ad{width:970px;height:90px}.ui.billboard.ad{width:970px;height:250px}.ui.panorama.ad{width:980px;height:120px}.ui.netboard.ad{width:580px;height:400px}.ui[class*="large mobile banner"].ad{width:320px;height:100px}.ui[class*="mobile leaderboard"].ad{width:320px;height:50px}.ui.mobile.ad{display:none}@media only screen and (max-width:767px){.ui.mobile.ad{display:block}}.ui.centered.ad{margin-left:auto;margin-right:auto}.ui.test.ad{position:relative;background:#545454}.ui.test.ad:after{position:absolute;top:50%;left:50%;width:100%;text-align:center;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);content:'Ad';color:#fff;font-size:1em;font-weight:700}.ui.mobile.test.ad:after{font-size:.85714286em}.ui.test.ad[data-text]:after{content:attr(data-text)} -------------------------------------------------------------------------------- /static/css/components/tab.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Tab 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | UI Tabs 14 | *******************************/ 15 | 16 | .ui.tab { 17 | display: none; 18 | } 19 | 20 | 21 | /******************************* 22 | States 23 | *******************************/ 24 | 25 | 26 | /*-------------------- 27 | Active 28 | ---------------------*/ 29 | 30 | .ui.tab.active, 31 | .ui.tab.open { 32 | display: block; 33 | } 34 | 35 | /*-------------------- 36 | Loading 37 | ---------------------*/ 38 | 39 | .ui.tab.loading { 40 | position: relative; 41 | overflow: hidden; 42 | display: block; 43 | min-height: 250px; 44 | } 45 | .ui.tab.loading * { 46 | position: relative !important; 47 | left: -10000px !important; 48 | } 49 | .ui.tab.loading:before, 50 | .ui.tab.loading.segment:before { 51 | position: absolute; 52 | content: ''; 53 | top: 100px; 54 | left: 50%; 55 | margin: -1.25em 0em 0em -1.25em; 56 | width: 2.5em; 57 | height: 2.5em; 58 | border-radius: 500rem; 59 | border: 0.2em solid rgba(0, 0, 0, 0.1); 60 | } 61 | .ui.tab.loading:after, 62 | .ui.tab.loading.segment:after { 63 | position: absolute; 64 | content: ''; 65 | top: 100px; 66 | left: 50%; 67 | margin: -1.25em 0em 0em -1.25em; 68 | width: 2.5em; 69 | height: 2.5em; 70 | -webkit-animation: button-spin 0.6s linear; 71 | animation: button-spin 0.6s linear; 72 | -webkit-animation-iteration-count: infinite; 73 | animation-iteration-count: infinite; 74 | border-radius: 500rem; 75 | border-color: #767676 transparent transparent; 76 | border-style: solid; 77 | border-width: 0.2em; 78 | -webkit-box-shadow: 0px 0px 0px 1px transparent; 79 | box-shadow: 0px 0px 0px 1px transparent; 80 | } 81 | 82 | 83 | /******************************* 84 | Tab Overrides 85 | *******************************/ 86 | 87 | 88 | 89 | /******************************* 90 | User Overrides 91 | *******************************/ 92 | 93 | -------------------------------------------------------------------------------- /test/load_note_content_to_db.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : load_note_content_to_db.py 4 | # @Author: wangms 5 | # @Date : 2019/8/1 6 | 7 | import os 8 | import sqlite3 9 | import zlib 10 | 11 | class LoadData(object): 12 | def __init__(self): 13 | self.files_dict = { 14 | "E:\\MyNote": 0 15 | } 16 | 17 | 18 | def run(self): 19 | for parent, dirs, files in os.walk("E:\MyNote"): 20 | # print(parent, dirs, files) 21 | if parent.endswith(".img"): 22 | print(files) 23 | continue 24 | 25 | if "init.md" in files: 26 | title = os.path.basename(parent) 27 | path = parent 28 | with open(os.path.join(parent, "init.md"), "r", encoding="utf8") as f: 29 | content = f.read() 30 | pid = self.files_dict.get(str(os.path.dirname(path))) 31 | note_id = self.write(title, pid, content) 32 | self.files_dict[path] = note_id 33 | else: 34 | continue 35 | 36 | for f in files: 37 | if f.endswith(".md") and f != "init.md": 38 | title = f.replace(".md", "") 39 | path = os.path.join(parent, f) 40 | else: 41 | continue 42 | 43 | with open(os.path.join(parent, f), "r", encoding="utf8") as f: 44 | content = f.read() 45 | 46 | pid = self.files_dict.get(str(os.path.dirname(path))) 47 | note_id = self.write(title, pid, content) 48 | self.files_dict[path] = note_id 49 | 50 | 51 | def write(self, title, pid, content): 52 | with sqlite3.connect("E:\\MyNote\\ideanote.db") as conn: 53 | cursor = conn.cursor() 54 | print(title, pid, content) 55 | cursor.execute("insert into t_catalog (title, parent_id, content) values (?, ?, ?)", (title, pid, zlib.compress(content.encode("utf8")))) 56 | note_id = cursor.lastrowid 57 | conn.commit() 58 | return note_id 59 | 60 | if __name__ == '__main__': 61 | l = LoadData() 62 | l.run() 63 | # l.write("test", 0, "test") -------------------------------------------------------------------------------- /static/css/codemirror-theme-monokai.css: -------------------------------------------------------------------------------- 1 | /* Based on Sublime Text's Monokai theme */ 2 | 3 | .cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; } 4 | .cm-s-monokai div.CodeMirror-selected { background: #49483E; } 5 | .cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); } 6 | .cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); } 7 | .cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; } 8 | .cm-s-monokai .CodeMirror-guttermarker { color: white; } 9 | .cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } 10 | .cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; } 11 | .cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } 12 | 13 | .cm-s-monokai span.cm-comment { color: #75715e; } 14 | .cm-s-monokai span.cm-atom { color: #ae81ff; } 15 | .cm-s-monokai span.cm-number { color: #ae81ff; } 16 | 17 | .cm-s-monokai span.cm-comment.cm-attribute { color: #97b757; } 18 | .cm-s-monokai span.cm-comment.cm-def { color: #bc9262; } 19 | .cm-s-monokai span.cm-comment.cm-tag { color: #bc6283; } 20 | .cm-s-monokai span.cm-comment.cm-type { color: #5998a6; } 21 | 22 | .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; } 23 | .cm-s-monokai span.cm-keyword { color: #f92672; } 24 | .cm-s-monokai span.cm-builtin { color: #66d9ef; } 25 | .cm-s-monokai span.cm-string { color: #e6db74; } 26 | 27 | .cm-s-monokai span.cm-variable { color: #f8f8f2; } 28 | .cm-s-monokai span.cm-variable-2 { color: #9effff; } 29 | .cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; } 30 | .cm-s-monokai span.cm-def { color: #fd971f; } 31 | .cm-s-monokai span.cm-bracket { color: #f8f8f2; } 32 | .cm-s-monokai span.cm-tag { color: #f92672; } 33 | .cm-s-monokai span.cm-header { color: #ae81ff; } 34 | .cm-s-monokai span.cm-link { color: #ae81ff; } 35 | .cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; } 36 | 37 | .cm-s-monokai .CodeMirror-activeline-background { background: #373831; } 38 | .cm-s-monokai .CodeMirror-matchingbracket { 39 | text-decoration: underline; 40 | color: white !important; 41 | } 42 | -------------------------------------------------------------------------------- /static/css/jquery.splitter.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * StyleSheet for JQuery splitter Plugin version 0.27.1 3 | * Copyright (C) 2010-2018 Jakub Jankiewicz 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program. If not, see . 17 | */ 18 | .splitter_panel { 19 | position: relative; 20 | } 21 | .splitter_panel .vsplitter { 22 | background-color: grey; 23 | cursor: col-resize; 24 | z-index:900; 25 | width: 7px; 26 | } 27 | 28 | .splitter_panel .hsplitter { 29 | background-color: #5F5F5F; 30 | cursor: row-resize; 31 | z-index: 800; 32 | height: 7px; 33 | } 34 | .splitter_panel .vsplitter.splitter-invisible, 35 | .splitter_panel .hsplitter.splitter-invisible { 36 | background: none; 37 | } 38 | .splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel, 39 | .splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel { 40 | position: absolute; 41 | overflow: auto; 42 | } 43 | .splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel { 44 | height: 100%; 45 | } 46 | .splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel { 47 | width: 100%; 48 | } 49 | .splitter_panel .top_panel, .splitter_panel .left_panel, .splitter_panel .vsplitter { 50 | top: 0; 51 | } 52 | .splitter_panel .top_panel, .splitter_panel .bottom_panel, .splitter_panel .left_panel, .splitter_panel .hsplitter { 53 | left: 0; 54 | } 55 | .splitter_panel .bottom_panel { 56 | bottom: 0; 57 | } 58 | .splitter_panel .right_panel { 59 | right: 0; 60 | } 61 | .splitterMask { 62 | position: absolute; 63 | left: 0; 64 | top: 0; 65 | right: 0; 66 | bottom: 0; 67 | z-index: 1000; 68 | } 69 | -------------------------------------------------------------------------------- /static/css/components/site.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Site 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin);body,html{height:100%}html{font-size:14px}body{margin:0;padding:0;overflow-x:hidden;min-width:320px;background:#fff;font-family:Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;font-size:14px;line-height:1.4285em;color:rgba(0,0,0,.87);font-smoothing:antialiased}h1,h2,h3,h4,h5{font-family:Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;line-height:1.28571429em;margin:calc(2rem - .14285714em) 0 1rem;font-weight:700;padding:0}h1{min-height:1rem;font-size:2rem}h2{font-size:1.71428571rem}h3{font-size:1.28571429rem}h4{font-size:1.07142857rem}h5{font-size:1rem}h1:first-child,h2:first-child,h3:first-child,h4:first-child,h5:first-child{margin-top:0}h1:last-child,h2:last-child,h3:last-child,h4:last-child,h5:last-child{margin-bottom:0}p{margin:0 0 1em;line-height:1.4285em}p:first-child{margin-top:0}p:last-child{margin-bottom:0}a{color:#4183c4;text-decoration:none}a:hover{color:#1e70bf;text-decoration:none}::-webkit-selection{background-color:#cce2ff;color:rgba(0,0,0,.87)}::-moz-selection{background-color:#cce2ff;color:rgba(0,0,0,.87)}::selection{background-color:#cce2ff;color:rgba(0,0,0,.87)}input::-webkit-selection,textarea::-webkit-selection{background-color:rgba(100,100,100,.4);color:rgba(0,0,0,.87)}input::-moz-selection,textarea::-moz-selection{background-color:rgba(100,100,100,.4);color:rgba(0,0,0,.87)}input::selection,textarea::selection{background-color:rgba(100,100,100,.4);color:rgba(0,0,0,.87)}body ::-webkit-scrollbar{-webkit-appearance:none;width:10px;height:10px}body ::-webkit-scrollbar-track{background:rgba(0,0,0,.1);border-radius:0}body ::-webkit-scrollbar-thumb{cursor:pointer;border-radius:5px;background:rgba(0,0,0,.25);-webkit-transition:color .2s ease;transition:color .2s ease}body ::-webkit-scrollbar-thumb:window-inactive{background:rgba(0,0,0,.15)}body ::-webkit-scrollbar-thumb:hover{background:rgba(128,135,139,.8)}body .ui.inverted::-webkit-scrollbar-track{background:rgba(255,255,255,.1)}body .ui.inverted::-webkit-scrollbar-thumb{background:rgba(255,255,255,.25)}body .ui.inverted::-webkit-scrollbar-thumb:window-inactive{background:rgba(255,255,255,.15)}body .ui.inverted::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.35)} -------------------------------------------------------------------------------- /static/css/components/shape.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Shape 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.shape{position:relative;vertical-align:top;display:inline-block;-webkit-perspective:2000px;perspective:2000px;-webkit-transition:left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out;transition:left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out,left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out;transition:transform .6s ease-in-out,left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out}.ui.shape .sides{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.ui.shape .side{opacity:1;width:100%;margin:0!important;-webkit-backface-visibility:hidden;backface-visibility:hidden}.ui.shape .side{display:none}.ui.shape .side *{-webkit-backface-visibility:visible!important;backface-visibility:visible!important}.ui.cube.shape .side{min-width:15em;height:15em;padding:2em;background-color:#e6e6e6;color:rgba(0,0,0,.87);-webkit-box-shadow:0 0 2px rgba(0,0,0,.3);box-shadow:0 0 2px rgba(0,0,0,.3)}.ui.cube.shape .side>.content{width:100%;height:100%;display:table;text-align:center;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ui.cube.shape .side>.content>div{display:table-cell;vertical-align:middle;font-size:2em}.ui.text.shape.animating .sides{position:static}.ui.text.shape .side{white-space:nowrap}.ui.text.shape .side>*{white-space:normal}.ui.loading.shape{position:absolute;top:-9999px;left:-9999px}.ui.shape .animating.side{position:absolute;top:0;left:0;display:block;z-index:100}.ui.shape .hidden.side{opacity:.6}.ui.shape.animating .sides{position:absolute}.ui.shape.animating .sides{-webkit-transition:left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out;transition:left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out,left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out;transition:transform .6s ease-in-out,left .6s ease-in-out,width .6s ease-in-out,height .6s ease-in-out,-webkit-transform .6s ease-in-out}.ui.shape.animating .side{-webkit-transition:opacity .6s ease-in-out;transition:opacity .6s ease-in-out}.ui.shape .active.side{display:block} -------------------------------------------------------------------------------- /static/css/components/breadcrumb.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Breadcrumb 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Breadcrumb 14 | *******************************/ 15 | 16 | .ui.breadcrumb { 17 | line-height: 1; 18 | display: inline-block; 19 | margin: 0em 0em; 20 | vertical-align: middle; 21 | } 22 | .ui.breadcrumb:first-child { 23 | margin-top: 0em; 24 | } 25 | .ui.breadcrumb:last-child { 26 | margin-bottom: 0em; 27 | } 28 | 29 | 30 | /******************************* 31 | Content 32 | *******************************/ 33 | 34 | 35 | /* Divider */ 36 | .ui.breadcrumb .divider { 37 | display: inline-block; 38 | opacity: 0.7; 39 | margin: 0em 0.21428571rem 0em; 40 | font-size: 0.92857143em; 41 | color: rgba(0, 0, 0, 0.4); 42 | vertical-align: baseline; 43 | } 44 | 45 | /* Link */ 46 | .ui.breadcrumb a { 47 | color: #4183C4; 48 | } 49 | .ui.breadcrumb a:hover { 50 | color: #1e70bf; 51 | } 52 | 53 | /* Icon Divider */ 54 | .ui.breadcrumb .icon.divider { 55 | font-size: 0.85714286em; 56 | vertical-align: baseline; 57 | } 58 | 59 | /* Section */ 60 | .ui.breadcrumb a.section { 61 | cursor: pointer; 62 | } 63 | .ui.breadcrumb .section { 64 | display: inline-block; 65 | margin: 0em; 66 | padding: 0em; 67 | } 68 | 69 | /* Loose Coupling */ 70 | .ui.breadcrumb.segment { 71 | display: inline-block; 72 | padding: 0.78571429em 1em; 73 | } 74 | 75 | 76 | /******************************* 77 | States 78 | *******************************/ 79 | 80 | .ui.breadcrumb .active.section { 81 | font-weight: bold; 82 | } 83 | 84 | 85 | /******************************* 86 | Variations 87 | *******************************/ 88 | 89 | .ui.mini.breadcrumb { 90 | font-size: 0.78571429rem; 91 | } 92 | .ui.tiny.breadcrumb { 93 | font-size: 0.85714286rem; 94 | } 95 | .ui.small.breadcrumb { 96 | font-size: 0.92857143rem; 97 | } 98 | .ui.breadcrumb { 99 | font-size: 1rem; 100 | } 101 | .ui.large.breadcrumb { 102 | font-size: 1.14285714rem; 103 | } 104 | .ui.big.breadcrumb { 105 | font-size: 1.28571429rem; 106 | } 107 | .ui.huge.breadcrumb { 108 | font-size: 1.42857143rem; 109 | } 110 | .ui.massive.breadcrumb { 111 | font-size: 1.71428571rem; 112 | } 113 | 114 | 115 | /******************************* 116 | Theme Overrides 117 | *******************************/ 118 | 119 | 120 | 121 | /******************************* 122 | Site Overrides 123 | *******************************/ 124 | 125 | -------------------------------------------------------------------------------- /static/css/components/reset.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Reset 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */*,:after,:before{-webkit-box-sizing:inherit;box-sizing:inherit}html{-webkit-box-sizing:border-box;box-sizing:border-box}input[type=email],input[type=password],input[type=search],input[type=text]{-webkit-appearance:none;-moz-appearance:none}/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none} -------------------------------------------------------------------------------- /static/css/components/comment.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Comment 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.comments{margin:1.5em 0;max-width:650px}.ui.comments:first-child{margin-top:0}.ui.comments:last-child{margin-bottom:0}.ui.comments .comment{position:relative;background:0 0;margin:.5em 0 0;padding:.5em 0 0;border:none;border-top:none;line-height:1.2}.ui.comments .comment:first-child{margin-top:0;padding-top:0}.ui.comments .comment .comments{margin:0 0 .5em .5em;padding:1em 0 1em 1em}.ui.comments .comment .comments:before{position:absolute;top:0;left:0}.ui.comments .comment .comments .comment{border:none;border-top:none;background:0 0}.ui.comments .comment .avatar{display:block;width:2.5em;height:auto;float:left;margin:.2em 0 0}.ui.comments .comment .avatar img,.ui.comments .comment img.avatar{display:block;margin:0 auto;width:100%;height:100%;border-radius:.25rem}.ui.comments .comment>.content{display:block}.ui.comments .comment>.avatar~.content{margin-left:3.5em}.ui.comments .comment .author{font-size:1em;color:rgba(0,0,0,.87);font-weight:700}.ui.comments .comment a.author{cursor:pointer}.ui.comments .comment a.author:hover{color:#1e70bf}.ui.comments .comment .metadata{display:inline-block;margin-left:.5em;color:rgba(0,0,0,.4);font-size:.875em}.ui.comments .comment .metadata>*{display:inline-block;margin:0 .5em 0 0}.ui.comments .comment .metadata>:last-child{margin-right:0}.ui.comments .comment .text{margin:.25em 0 .5em;font-size:1em;word-wrap:break-word;color:rgba(0,0,0,.87);line-height:1.3}.ui.comments .comment .actions{font-size:.875em}.ui.comments .comment .actions a{cursor:pointer;display:inline-block;margin:0 .75em 0 0;color:rgba(0,0,0,.4)}.ui.comments .comment .actions a:last-child{margin-right:0}.ui.comments .comment .actions a.active,.ui.comments .comment .actions a:hover{color:rgba(0,0,0,.8)}.ui.comments>.reply.form{margin-top:1em}.ui.comments .comment .reply.form{width:100%;margin-top:1em}.ui.comments .reply.form textarea{font-size:1em;height:12em}.ui.collapsed.comments,.ui.comments .collapsed.comment,.ui.comments .collapsed.comments{display:none}.ui.threaded.comments .comment .comments{margin:-1.5em 0 -1em 1.25em;padding:3em 0 2em 2.25em;-webkit-box-shadow:-1px 0 0 rgba(34,36,38,.15);box-shadow:-1px 0 0 rgba(34,36,38,.15)}.ui.minimal.comments .comment .actions{opacity:0;position:absolute;top:0;right:0;left:auto;-webkit-transition:opacity .2s ease;transition:opacity .2s ease;-webkit-transition-delay:.1s;transition-delay:.1s}.ui.minimal.comments .comment>.content:hover>.actions{opacity:1}.ui.mini.comments{font-size:.78571429rem}.ui.tiny.comments{font-size:.85714286rem}.ui.small.comments{font-size:.92857143rem}.ui.comments{font-size:1rem}.ui.large.comments{font-size:1.14285714rem}.ui.big.comments{font-size:1.28571429rem}.ui.huge.comments{font-size:1.42857143rem}.ui.massive.comments{font-size:1.71428571rem} -------------------------------------------------------------------------------- /static/css/components/video.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.0.0 - Video 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Copyright 2014 Contributors 7 | * Released under the MIT license 8 | * http://opensource.org/licenses/MIT 9 | * 10 | */ 11 | 12 | 13 | /******************************* 14 | Video 15 | *******************************/ 16 | 17 | .ui.video { 18 | background-color: #dddddd; 19 | position: relative; 20 | max-width: 100%; 21 | padding-bottom: 56.25%; 22 | height: 0px; 23 | overflow: hidden; 24 | } 25 | 26 | /*-------------- 27 | Content 28 | ---------------*/ 29 | 30 | 31 | /* Placeholder Image */ 32 | .ui.video .placeholder { 33 | background-color: #333333; 34 | } 35 | 36 | /* Play Icon Overlay */ 37 | .ui.video .play { 38 | cursor: pointer; 39 | position: absolute; 40 | top: 0px; 41 | left: 0px; 42 | z-index: 10; 43 | width: 100%; 44 | height: 100%; 45 | background: transparent; 46 | -webkit-transition: background 0.2s ease; 47 | transition: background 0.2s ease; 48 | } 49 | .ui.video .play.icon:before { 50 | position: absolute; 51 | top: 50%; 52 | left: 50%; 53 | z-index: 11; 54 | -webkit-transform: translateX(-50%) translateY(-50%); 55 | -ms-transform: translateX(-50%) translateY(-50%); 56 | transform: translateX(-50%) translateY(-50%); 57 | color: rgba(255, 255, 255, 0.7); 58 | font-size: 7rem; 59 | text-shadow: 2px 2px 0px rgba(0, 0, 0, 0.15); 60 | -webkit-transition: color 0.2s ease; 61 | transition: color 0.2s ease; 62 | } 63 | .ui.video .placeholder { 64 | position: absolute; 65 | top: 0px; 66 | left: 0px; 67 | display: block; 68 | width: 100%; 69 | height: 100%; 70 | } 71 | 72 | /* IFrame Embed */ 73 | .ui.video .embed iframe, 74 | .ui.video .embed embed, 75 | .ui.video .embed object { 76 | position: absolute; 77 | border: none; 78 | width: 100%; 79 | height: 100%; 80 | top: 0px; 81 | left: 0px; 82 | margin: 0em; 83 | padding: 0em; 84 | } 85 | 86 | 87 | /******************************* 88 | States 89 | *******************************/ 90 | 91 | 92 | /*-------------- 93 | Hover 94 | ---------------*/ 95 | 96 | .ui.video .play:hover { 97 | background: rgba(0, 0, 0, 0); 98 | } 99 | .ui.video .play:hover:before { 100 | color: #ffffff; 101 | } 102 | 103 | /*-------------- 104 | Active 105 | ---------------*/ 106 | 107 | .ui.active.video .play, 108 | .ui.active.video .placeholder { 109 | display: none; 110 | } 111 | .ui.active.video .embed { 112 | display: inline; 113 | } 114 | 115 | 116 | /******************************* 117 | Video Overrides 118 | *******************************/ 119 | 120 | 121 | 122 | /******************************* 123 | Site Overrides 124 | *******************************/ 125 | 126 | -------------------------------------------------------------------------------- /templates/editor.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block cssdefine %} 4 | 5 | 6 | 7 | 8 | 9 | {% endblock %} 10 | 11 | {% block jsdefinebefore %} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | {% endblock %} 24 | 25 | 26 | 27 | {% block centerframe %} 28 | 29 | 30 | {% endblock %} 31 | 32 | 33 | {% block jsdefineafter %} 34 | 72 | {% endblock %} -------------------------------------------------------------------------------- /static/css/components/rail.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Rail 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Rails 14 | *******************************/ 15 | 16 | .ui.rail { 17 | position: absolute; 18 | top: 0%; 19 | width: 300px; 20 | height: 100%; 21 | } 22 | .ui.left.rail { 23 | left: auto; 24 | right: 100%; 25 | padding: 0em 2rem 0em 0em; 26 | margin: 0em 2rem 0em 0em; 27 | } 28 | .ui.right.rail { 29 | left: 100%; 30 | right: auto; 31 | padding: 0em 0em 0em 2rem; 32 | margin: 0em 0em 0em 2rem; 33 | } 34 | 35 | 36 | /******************************* 37 | Variations 38 | *******************************/ 39 | 40 | 41 | /*-------------- 42 | Internal 43 | ---------------*/ 44 | 45 | .ui.left.internal.rail { 46 | left: 0%; 47 | right: auto; 48 | padding: 0em 0em 0em 2rem; 49 | margin: 0em 0em 0em 2rem; 50 | } 51 | .ui.right.internal.rail { 52 | left: auto; 53 | right: 0%; 54 | padding: 0em 2rem 0em 0em; 55 | margin: 0em 2rem 0em 0em; 56 | } 57 | 58 | /*-------------- 59 | Dividing 60 | ---------------*/ 61 | 62 | .ui.dividing.rail { 63 | width: 302.5px; 64 | } 65 | .ui.left.dividing.rail { 66 | padding: 0em 2.5rem 0em 0em; 67 | margin: 0em 2.5rem 0em 0em; 68 | border-right: 1px solid rgba(34, 36, 38, 0.15); 69 | } 70 | .ui.right.dividing.rail { 71 | border-left: 1px solid rgba(34, 36, 38, 0.15); 72 | padding: 0em 0em 0em 2.5rem; 73 | margin: 0em 0em 0em 2.5rem; 74 | } 75 | 76 | /*-------------- 77 | Distance 78 | ---------------*/ 79 | 80 | .ui.close.rail { 81 | width: calc( 300px + 1em ); 82 | } 83 | .ui.close.left.rail { 84 | padding: 0em 1em 0em 0em; 85 | margin: 0em 1em 0em 0em; 86 | } 87 | .ui.close.right.rail { 88 | padding: 0em 0em 0em 1em; 89 | margin: 0em 0em 0em 1em; 90 | } 91 | .ui.very.close.rail { 92 | width: calc( 300px + 0.5em ); 93 | } 94 | .ui.very.close.left.rail { 95 | padding: 0em 0.5em 0em 0em; 96 | margin: 0em 0.5em 0em 0em; 97 | } 98 | .ui.very.close.right.rail { 99 | padding: 0em 0em 0em 0.5em; 100 | margin: 0em 0em 0em 0.5em; 101 | } 102 | 103 | /*-------------- 104 | Attached 105 | ---------------*/ 106 | 107 | .ui.attached.left.rail, 108 | .ui.attached.right.rail { 109 | padding: 0em; 110 | margin: 0em; 111 | } 112 | 113 | /*-------------- 114 | Sizing 115 | ---------------*/ 116 | 117 | .ui.mini.rail { 118 | font-size: 0.78571429rem; 119 | } 120 | .ui.tiny.rail { 121 | font-size: 0.85714286rem; 122 | } 123 | .ui.small.rail { 124 | font-size: 0.92857143rem; 125 | } 126 | .ui.rail { 127 | font-size: 1rem; 128 | } 129 | .ui.large.rail { 130 | font-size: 1.14285714rem; 131 | } 132 | .ui.big.rail { 133 | font-size: 1.28571429rem; 134 | } 135 | .ui.huge.rail { 136 | font-size: 1.42857143rem; 137 | } 138 | .ui.massive.rail { 139 | font-size: 1.71428571rem; 140 | } 141 | 142 | 143 | /******************************* 144 | Theme Overrides 145 | *******************************/ 146 | 147 | 148 | 149 | /******************************* 150 | Site Overrides 151 | *******************************/ 152 | 153 | -------------------------------------------------------------------------------- /static/css/components/nag.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Nag 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Nag 14 | *******************************/ 15 | 16 | .ui.nag { 17 | display: none; 18 | opacity: 0.95; 19 | position: relative; 20 | top: 0em; 21 | left: 0px; 22 | z-index: 999; 23 | min-height: 0em; 24 | width: 100%; 25 | margin: 0em; 26 | padding: 0.75em 1em; 27 | background: #555555; 28 | -webkit-box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.2); 29 | box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.2); 30 | font-size: 1rem; 31 | text-align: center; 32 | color: rgba(0, 0, 0, 0.87); 33 | border-radius: 0em 0em 0.28571429rem 0.28571429rem; 34 | -webkit-transition: 0.2s background ease; 35 | transition: 0.2s background ease; 36 | } 37 | a.ui.nag { 38 | cursor: pointer; 39 | } 40 | .ui.nag > .title { 41 | display: inline-block; 42 | margin: 0em 0.5em; 43 | color: #FFFFFF; 44 | } 45 | .ui.nag > .close.icon { 46 | cursor: pointer; 47 | opacity: 0.4; 48 | position: absolute; 49 | top: 50%; 50 | right: 1em; 51 | font-size: 1em; 52 | margin: -0.5em 0em 0em; 53 | color: #FFFFFF; 54 | -webkit-transition: opacity 0.2s ease; 55 | transition: opacity 0.2s ease; 56 | } 57 | 58 | 59 | /******************************* 60 | States 61 | *******************************/ 62 | 63 | 64 | /* Hover */ 65 | .ui.nag:hover { 66 | background: #555555; 67 | opacity: 1; 68 | } 69 | .ui.nag .close:hover { 70 | opacity: 1; 71 | } 72 | 73 | 74 | /******************************* 75 | Variations 76 | *******************************/ 77 | 78 | 79 | /*-------------- 80 | Static 81 | ---------------*/ 82 | 83 | .ui.overlay.nag { 84 | position: absolute; 85 | display: block; 86 | } 87 | 88 | /*-------------- 89 | Fixed 90 | ---------------*/ 91 | 92 | .ui.fixed.nag { 93 | position: fixed; 94 | } 95 | 96 | /*-------------- 97 | Bottom 98 | ---------------*/ 99 | 100 | .ui.bottom.nags, 101 | .ui.bottom.nag { 102 | border-radius: 0.28571429rem 0.28571429rem 0em 0em; 103 | top: auto; 104 | bottom: 0em; 105 | } 106 | 107 | /*-------------- 108 | White 109 | ---------------*/ 110 | 111 | .ui.inverted.nags .nag, 112 | .ui.inverted.nag { 113 | background-color: #F3F4F5; 114 | color: rgba(0, 0, 0, 0.85); 115 | } 116 | .ui.inverted.nags .nag .close, 117 | .ui.inverted.nags .nag .title, 118 | .ui.inverted.nag .close, 119 | .ui.inverted.nag .title { 120 | color: rgba(0, 0, 0, 0.4); 121 | } 122 | 123 | 124 | /******************************* 125 | Groups 126 | *******************************/ 127 | 128 | .ui.nags .nag { 129 | border-radius: 0em !important; 130 | } 131 | .ui.nags .nag:last-child { 132 | border-radius: 0em 0em 0.28571429rem 0.28571429rem; 133 | } 134 | .ui.bottom.nags .nag:last-child { 135 | border-radius: 0.28571429rem 0.28571429rem 0em 0em; 136 | } 137 | 138 | 139 | /******************************* 140 | Theme Overrides 141 | *******************************/ 142 | 143 | 144 | 145 | /******************************* 146 | User Overrides 147 | *******************************/ 148 | 149 | -------------------------------------------------------------------------------- /static/css/components/dimmer.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Dimmer 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.dimmable:not(body){position:relative}.ui.dimmer{display:none;position:absolute;top:0!important;left:0!important;width:100%;height:100%;text-align:center;vertical-align:middle;padding:1em;background-color:rgba(0,0,0,.85);opacity:0;line-height:1;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-transition:background-color .5s linear;transition:background-color .5s linear;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;will-change:opacity;z-index:1000}.ui.dimmer>.content{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;color:#fff}.ui.segment>.ui.dimmer{border-radius:inherit!important}.ui.dimmer:not(.inverted)::-webkit-scrollbar-track{background:rgba(255,255,255,.1)}.ui.dimmer:not(.inverted)::-webkit-scrollbar-thumb{background:rgba(255,255,255,.25)}.ui.dimmer:not(.inverted)::-webkit-scrollbar-thumb:window-inactive{background:rgba(255,255,255,.15)}.ui.dimmer:not(.inverted)::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.35)}.animating.dimmable:not(body),.dimmed.dimmable:not(body){overflow:hidden}.dimmed.dimmable>.ui.animating.dimmer,.dimmed.dimmable>.ui.visible.dimmer,.ui.active.dimmer{display:-webkit-box;display:-ms-flexbox;display:flex;opacity:1}.ui.disabled.dimmer{width:0!important;height:0!important}.dimmed.dimmable>.ui.animating.legacy.dimmer,.dimmed.dimmable>.ui.visible.legacy.dimmer,.ui.active.legacy.dimmer{display:block}.ui[class*="top aligned"].dimmer{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.ui[class*="bottom aligned"].dimmer{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.ui.page.dimmer{position:fixed;-webkit-transform-style:'';transform-style:'';-webkit-perspective:2000px;perspective:2000px;-webkit-transform-origin:center center;transform-origin:center center}body.animating.in.dimmable,body.dimmed.dimmable{overflow:hidden}body.dimmable>.dimmer{position:fixed}.blurring.dimmable>:not(.dimmer){-webkit-filter:blur(0) grayscale(0);filter:blur(0) grayscale(0);-webkit-transition:.8s -webkit-filter ease;transition:.8s -webkit-filter ease;transition:.8s filter ease;transition:.8s filter ease,.8s -webkit-filter ease}.blurring.dimmed.dimmable>:not(.dimmer){-webkit-filter:blur(5px) grayscale(.7);filter:blur(5px) grayscale(.7)}.blurring.dimmable>.dimmer{background-color:rgba(0,0,0,.6)}.blurring.dimmable>.inverted.dimmer{background-color:rgba(255,255,255,.6)}.ui.dimmer>.top.aligned.content>*{vertical-align:top}.ui.dimmer>.bottom.aligned.content>*{vertical-align:bottom}.ui.inverted.dimmer{background-color:rgba(255,255,255,.85)}.ui.inverted.dimmer>.content>*{color:#fff}.ui.simple.dimmer{display:block;overflow:hidden;opacity:1;width:0%;height:0%;z-index:-100;background-color:rgba(0,0,0,0)}.dimmed.dimmable>.ui.simple.dimmer{overflow:visible;opacity:1;width:100%;height:100%;background-color:rgba(0,0,0,.85);z-index:1}.ui.simple.inverted.dimmer{background-color:rgba(255,255,255,0)}.dimmed.dimmable>.ui.simple.inverted.dimmer{background-color:rgba(255,255,255,.85)} -------------------------------------------------------------------------------- /sync/view.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : view.py 4 | # @Author: wangms 5 | # @Date : 2019/12/20 6 | 7 | import pickle 8 | import zlib 9 | import traceback 10 | from base64 import b64encode 11 | from common import conf 12 | from threading import Thread 13 | from .service import SyncService 14 | from .sync_utils.netdisk_sync_utils import NetDiskSyncUtils 15 | from .sync_utils.github_sync_utils import GithubSyncUtils 16 | from .model import SyncInfo 17 | from sync import sync 18 | from flask import request, current_app, Response, render_template 19 | 20 | if conf.sync_method == "github": 21 | sync_utils = GithubSyncUtils(conf.sync_connection_info) 22 | else: 23 | sync_utils = NetDiskSyncUtils(conf.sync_work_dir) 24 | 25 | sync_service = SyncService(sync_utils) 26 | sync_thread = Thread(target=sync_service.run) 27 | sync_thread.daemon = True 28 | sync_thread.start() 29 | 30 | @sync.route('/sync/note/list') 31 | def fetch_sync_note_list(): 32 | try: 33 | result = sync_utils.fetch_sync_note_list() 34 | local_version_info = SyncInfo.query.first() 35 | except Exception as e: 36 | current_app.logger.error(e) 37 | traceback.print_exc() 38 | return Response(str(e), status=500) 39 | return render_template('sync_note_list.html', note_list=result, local_version_id=local_version_info.current_version) 40 | 41 | 42 | @sync.route("/sync/view/note") 43 | def view_sync_note_content(): 44 | try: 45 | note_id = request.args.get("note_id") 46 | version_id = request.args.get("version_id") 47 | note_info = sync_utils.load_note_info_by_version_note_id(version_id, note_id) 48 | note = pickle.loads(note_info.get("note")) 49 | content = zlib.decompress(note.content).decode("utf8") 50 | images = [zlib.decompress(pickle.loads(i).image) for i in note_info.get("images")] 51 | base64_images = [b64encode(i).decode() for i in images] 52 | except Exception as e: 53 | current_app.logger.error(e) 54 | traceback.print_exc() 55 | return Response(str(e), status=500) 56 | return render_template('sync_note_view.html', content=content, images=base64_images) 57 | 58 | 59 | @sync.route("/sync/apply/note", methods=["POST"]) 60 | def apply_sync_note_change(): 61 | try: 62 | note_id = request.form.get("note_id") 63 | version_id = request.form.get("version_id") 64 | note_info = sync_utils.load_note_info_by_version_note_id(version_id, note_id) 65 | sync_service.apply_change(note_info) 66 | except Exception as e: 67 | current_app.logger.error(e) 68 | traceback.print_exc() 69 | return Response(str(e), status=500) 70 | 71 | return Response(status=200) 72 | 73 | @sync.route("/sync/view/latest-version") 74 | def view_latest_version_info(): 75 | try: 76 | info = sync_utils.load_version_info() 77 | result = ", ".join((f"{k}={v}" for k, v in info.items())) 78 | except Exception as e: 79 | current_app.logger.error(e) 80 | traceback.print_exc() 81 | return Response(str(e), status=500) 82 | 83 | return Response(result, status=200) 84 | 85 | 86 | @sync.route("/sync/delete/obsolete", methods=["POST"]) 87 | def delete_obsolete_change(): 88 | try: 89 | sync_utils.delete_obsolete_change() 90 | except Exception as e: 91 | current_app.logger.error(e) 92 | traceback.print_exc() 93 | return Response(str(e), status=500) 94 | 95 | return Response(status=200) 96 | 97 | -------------------------------------------------------------------------------- /static/css/components/feed.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Feed 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.feed{margin:1em 0}.ui.feed:first-child{margin-top:0}.ui.feed:last-child{margin-bottom:0}.ui.feed>.event{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;width:100%;padding:.21428571rem 0;margin:0;background:0 0;border-top:none}.ui.feed>.event:first-child{border-top:0;padding-top:0}.ui.feed>.event:last-child{padding-bottom:0}.ui.feed>.event>.label{display:block;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;width:2.5em;height:auto;-ms-flex-item-align:stretch;align-self:stretch;text-align:left}.ui.feed>.event>.label .icon{opacity:1;font-size:1.5em;width:100%;padding:.25em;background:0 0;border:none;border-radius:none;color:rgba(0,0,0,.6)}.ui.feed>.event>.label img{width:100%;height:auto;border-radius:500rem}.ui.feed>.event>.label+.content{margin:.5em 0 .35714286em 1.14285714em}.ui.feed>.event>.content{display:block;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;-ms-flex-item-align:stretch;align-self:stretch;text-align:left;word-wrap:break-word}.ui.feed>.event:last-child>.content{padding-bottom:0}.ui.feed>.event>.content a{cursor:pointer}.ui.feed>.event>.content .date{margin:-.5rem 0 0;padding:0;font-weight:400;font-size:1em;font-style:normal;color:rgba(0,0,0,.4)}.ui.feed>.event>.content .summary{margin:0;font-size:1em;font-weight:700;color:rgba(0,0,0,.87)}.ui.feed>.event>.content .summary img{display:inline-block;width:auto;height:10em;margin:-.25em .25em 0 0;border-radius:.25em;vertical-align:middle}.ui.feed>.event>.content .user{display:inline-block;font-weight:700;margin-right:0;vertical-align:baseline}.ui.feed>.event>.content .user img{margin:-.25em .25em 0 0;width:auto;height:10em;vertical-align:middle}.ui.feed>.event>.content .summary>.date{display:inline-block;float:none;font-weight:400;font-size:.85714286em;font-style:normal;margin:0 0 0 .5em;padding:0;color:rgba(0,0,0,.4)}.ui.feed>.event>.content .extra{margin:.5em 0 0;background:0 0;padding:0;color:rgba(0,0,0,.87)}.ui.feed>.event>.content .extra.images img{display:inline-block;margin:0 .25em 0 0;width:6em}.ui.feed>.event>.content .extra.text{padding:0;border-left:none;font-size:1em;max-width:500px;line-height:1.4285em}.ui.feed>.event>.content .meta{display:inline-block;font-size:.85714286em;margin:.5em 0 0;background:0 0;border:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none;padding:0;color:rgba(0,0,0,.6)}.ui.feed>.event>.content .meta>*{position:relative;margin-left:.75em}.ui.feed>.event>.content .meta>:after{content:'';color:rgba(0,0,0,.2);top:0;left:-1em;opacity:1;position:absolute;vertical-align:top}.ui.feed>.event>.content .meta .like{color:'';-webkit-transition:.2s color ease;transition:.2s color ease}.ui.feed>.event>.content .meta .like:hover .icon{color:#ff2733}.ui.feed>.event>.content .meta .active.like .icon{color:#ef404a}.ui.feed>.event>.content .meta>:first-child{margin-left:0}.ui.feed>.event>.content .meta>:first-child::after{display:none}.ui.feed>.event>.content .meta a,.ui.feed>.event>.content .meta>.icon{cursor:pointer;opacity:1;color:rgba(0,0,0,.5);-webkit-transition:color .1s ease;transition:color .1s ease}.ui.feed>.event>.content .meta a:hover,.ui.feed>.event>.content .meta a:hover .icon,.ui.feed>.event>.content .meta>.icon:hover{color:rgba(0,0,0,.95)}.ui.small.feed{font-size:.92857143rem}.ui.feed{font-size:1rem}.ui.large.feed{font-size:1.14285714rem} -------------------------------------------------------------------------------- /onekey_install.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : onekey_install.py.py 4 | # @Author: wangms 5 | # @Date : 2019/11/14 6 | import logging 7 | import os 8 | import sys 9 | from colorama import init as cmd_color_init, Fore, Back 10 | 11 | 12 | welcome = """# 欢迎使用IdeaNote - 助你打造自己的知识平台 13 | ============ 14 | 使用技巧: 15 | - 右键`MyNote`即可创建新笔记 16 | - 通过鼠标拖拽或者上下左右方向键可以调整笔记的位置 17 | - 通过CTRL + i 进入文章编辑模式 18 | - 通过ESC返回阅读模式 19 | - 通过Shift + s 切换目录管理窗口 20 | - 拖动窗口分界线可以调整各个窗口的大小 21 | - 编辑窗口还可以直接粘贴图片哦 22 | 23 | > 如在使用过程中有任何奇思妙想都可以在Github上发起issue,同时也期待你加入我们的开发团队。 24 | """ 25 | logging.getLogger(name="IdeaNoteSync").disabled = True 26 | 27 | cmd_color_init(autoreset=True) 28 | 29 | print(Fore.RED + "注意:该脚本是IdeaNote的初始化安装脚本,一旦继续会清除IdeaNote的笔记数据!!") 30 | v = input("是否需要继续(Y:继续,N:退出):") 31 | if v.upper() != "Y": 32 | sys.exit(0) 33 | 34 | current_dir = os.path.dirname(os.path.abspath(__file__)) 35 | 36 | print("1. 安装依赖包") 37 | 38 | import platform 39 | requirements_file = os.path.join(current_dir, "requirements.txt") 40 | with open(requirements_file, "r", encoding="utf8") as f: 41 | requirements = [i.strip() for i in f.readlines()] 42 | if platform.system() != "Windows": 43 | requirements.remove("pywin32") 44 | 45 | import subprocess 46 | for line in requirements: 47 | print(f"安装{line}") 48 | completed = subprocess.run(f"pip install {line}", shell=True, 49 | stdout=subprocess.PIPE, 50 | stderr=subprocess.PIPE, encoding="utf8") 51 | if completed.returncode != 0: 52 | print(Fore.RED + completed.stderr) 53 | sys.exit(1) 54 | print(">>>>>>完成!\n") 55 | 56 | print("2. 检查配置文件") 57 | config_file = os.path.join(current_dir, "config.yml") 58 | if not os.path.exists(config_file): 59 | print(Fore.RED + f"{config_file}文件不存在, 请复制config.sample.yml为config.yml,并修改其中的必要配置信息") 60 | sys.exit(1) 61 | print(">>>>>>通过!\n") 62 | 63 | from common import conf 64 | print("3. 初始化同步目录") 65 | if conf.sync_method == "github": 66 | from sync.sync_utils.github_sync_utils import GithubSyncUtils 67 | GithubSyncUtils(conf.sync_connection_info).init_version_info() 68 | elif conf.sync_method == "netdisk": 69 | from sync.sync_utils.netdisk_sync_utils import NetDiskSyncUtils 70 | NetDiskSyncUtils(conf.sync_work_dir).init_version_info() 71 | else: 72 | print(Fore.RED + "错误的同步方式配置,请正确填写config.yml中的sync_method的值") 73 | sys.exit(1) 74 | 75 | print(">>>>>>通过!\n") 76 | 77 | print("4. 检查日志目录") 78 | if not os.path.exists(conf.log_directory): 79 | print(Fore.RED + "请在config.yml文件中正确指定log_directory的路径") 80 | sys.exit(1) 81 | print(">>>>>>通过!\n") 82 | 83 | print("5. 初始化DB") 84 | import zlib 85 | import sqlalchemy 86 | from sqlalchemy.orm import sessionmaker 87 | from core.model import Catalog, Image, SyncRecord 88 | from sync.model import SyncInfo 89 | 90 | 91 | db_file = conf.db_config.get("SQLALCHEMY_DATABASE_URI") 92 | db = sqlalchemy.create_engine(db_file) 93 | session = sessionmaker(bind=db)() 94 | for t in [Catalog, Image, SyncRecord, SyncInfo]: 95 | t.metadata.drop_all(db.engine) 96 | t.metadata.create_all(db.engine) 97 | root_node = Catalog(title="MyNote", parent_id="self", content=zlib.compress(welcome.encode("utf8")), status=1) 98 | session.add(root_node) 99 | sync_init = SyncInfo(current_version=0, latest_version=0) 100 | session.add(sync_init) 101 | session.commit() 102 | print(">>>>>>完成!\n") 103 | print("安装成功,手工执行以下命令启动IdeaNote:") 104 | print(Fore.GREEN + f"python {os.path.join(current_dir, 'app.py')} ") 105 | 106 | 107 | input("回车退出...\n") 108 | 109 | -------------------------------------------------------------------------------- /static/css/components/image.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Image 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.image{position:relative;display:inline-block;vertical-align:middle;max-width:100%;background-color:transparent}img.ui.image{display:block}.ui.image img,.ui.image svg{display:block;max-width:100%;height:auto}.ui.hidden.image,.ui.hidden.images{display:none}.ui.hidden.transition.image,.ui.hidden.transition.images{display:block;visibility:hidden}.ui.images>.hidden.transition{display:inline-block;visibility:hidden}.ui.disabled.image,.ui.disabled.images{cursor:default;opacity:.45}.ui.inline.image,.ui.inline.image img,.ui.inline.image svg{display:inline-block}.ui.top.aligned.image,.ui.top.aligned.image img,.ui.top.aligned.image svg,.ui.top.aligned.images .image{display:inline-block;vertical-align:top}.ui.middle.aligned.image,.ui.middle.aligned.image img,.ui.middle.aligned.image svg,.ui.middle.aligned.images .image{display:inline-block;vertical-align:middle}.ui.bottom.aligned.image,.ui.bottom.aligned.image img,.ui.bottom.aligned.image svg,.ui.bottom.aligned.images .image{display:inline-block;vertical-align:bottom}.ui.rounded.image,.ui.rounded.image>*,.ui.rounded.images .image,.ui.rounded.images .image>*{border-radius:.3125em}.ui.bordered.image img,.ui.bordered.image svg,.ui.bordered.images .image,.ui.bordered.images img,.ui.bordered.images svg,img.ui.bordered.image{border:1px solid rgba(0,0,0,.1)}.ui.circular.image,.ui.circular.images{overflow:hidden}.ui.circular.image,.ui.circular.image>*,.ui.circular.images .image,.ui.circular.images .image>*{border-radius:500rem}.ui.fluid.image,.ui.fluid.image img,.ui.fluid.image svg,.ui.fluid.images,.ui.fluid.images img,.ui.fluid.images svg{display:block;width:100%;height:auto}.ui.avatar.image,.ui.avatar.image img,.ui.avatar.image svg,.ui.avatar.images .image,.ui.avatar.images img,.ui.avatar.images svg{margin-right:.25em;display:inline-block;width:2em;height:2em;border-radius:500rem}.ui.spaced.image{display:inline-block!important;margin-left:.5em;margin-right:.5em}.ui[class*="left spaced"].image{margin-left:.5em;margin-right:0}.ui[class*="right spaced"].image{margin-left:0;margin-right:.5em}.ui.floated.image,.ui.floated.images{float:left;margin-right:1em;margin-bottom:1em}.ui.right.floated.image,.ui.right.floated.images{float:right;margin-right:0;margin-bottom:1em;margin-left:1em}.ui.floated.image:last-child,.ui.floated.images:last-child{margin-bottom:0}.ui.centered.image,.ui.centered.images{margin-left:auto;margin-right:auto}.ui.mini.image,.ui.mini.images .image,.ui.mini.images img,.ui.mini.images svg{width:35px;height:auto;font-size:.78571429rem}.ui.tiny.image,.ui.tiny.images .image,.ui.tiny.images img,.ui.tiny.images svg{width:80px;height:auto;font-size:.85714286rem}.ui.small.image,.ui.small.images .image,.ui.small.images img,.ui.small.images svg{width:150px;height:auto;font-size:.92857143rem}.ui.medium.image,.ui.medium.images .image,.ui.medium.images img,.ui.medium.images svg{width:300px;height:auto;font-size:1rem}.ui.large.image,.ui.large.images .image,.ui.large.images img,.ui.large.images svg{width:450px;height:auto;font-size:1.14285714rem}.ui.big.image,.ui.big.images .image,.ui.big.images img,.ui.big.images svg{width:600px;height:auto;font-size:1.28571429rem}.ui.huge.image,.ui.huge.images .image,.ui.huge.images img,.ui.huge.images svg{width:800px;height:auto;font-size:1.42857143rem}.ui.massive.image,.ui.massive.images .image,.ui.massive.images img,.ui.massive.images svg{width:960px;height:auto;font-size:1.71428571rem}.ui.images{font-size:0;margin:0 -.25rem 0}.ui.images .image,.ui.images>img,.ui.images>svg{display:inline-block;margin:0 .25rem .5rem} -------------------------------------------------------------------------------- /test/test_github_apiv3.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : test_github_apiv3.py 4 | # @Author: wangms 5 | # @Date : 2019/7/28 6 | import requests 7 | import json 8 | from base64 import b64decode, b64encode 9 | 10 | def test_list_folder(): 11 | url = "https://api.github.com/repos/bmark-sync/test_github_api/contents" 12 | resp = requests.get(url, data={ 13 | "ref": "master" 14 | }) 15 | print(json.dumps(resp.json(), indent=4)) 16 | 17 | def test_create_folder(): 18 | url = "https://api.github.com/repos/sync-repo/note-sync/contents/version" 19 | content = b64encode("abcdef".encode("utf8")).decode("utf8") 20 | resp = requests.put(url, data=json.dumps({ 21 | "message": "创建idea目录及内容文件", 22 | "committer": { 23 | "name": "bmark-sync", 24 | "email": "thankall@yeah.net" 25 | }, 26 | "content": f"{content}", 27 | "branch": "master" 28 | }), params={ 29 | "access_token": "38d6f2b08b84d86a2fa64fd77dc2357638ffde02" 30 | }) 31 | 32 | print(json.dumps(resp.json(), indent=4)) 33 | 34 | def test_delete_folder(): 35 | test_delete_file() 36 | 37 | def test_create_file(): 38 | test_create_folder() 39 | 40 | def test_delete_file(): 41 | file_list = [ 42 | "Docker.md", 43 | ".img/cd33eef0b8e011e99880a402b9518744" 44 | ] 45 | for filename in file_list: 46 | url = "https://api.github.com/repos/bmark-sync/notesync/contents/{}".format(filename) 47 | resp = requests.get(url, data={ 48 | "ref": "master" 49 | }) 50 | url = "https://api.github.com/repos/bmark-sync/notesync/contents/{}".format(filename) 51 | sha = resp.json()["sha"] 52 | resp = requests.delete(url, data=json.dumps({ 53 | "message": "delete a file or folder", 54 | "sha": f"{sha}", 55 | "branch": "master" 56 | }), params={ 57 | "access_token": "c64b06c644660e1819f9077163f5f670c680dad7" 58 | }) 59 | print(resp.json()) 60 | 61 | def test_read_content(): 62 | url = "https://api.github.com/repos/bmark-sync/note-sync-2/contents/ideanote.json" 63 | resp = requests.get(url, data={ 64 | "ref": "master" 65 | }, params={ 66 | "access_token": "20a50aa67bfb987a0743a0068c4e3ddb76d21780" 67 | }) 68 | print(json.dumps(resp.json(), indent=4)) 69 | return resp.json() 70 | 71 | def test_fetch_file_sha(): 72 | return test_read_content()["sha"] 73 | 74 | def test_update_content(): 75 | url = "https://api.github.com/repos/bmark-sync/test_github_api/contents/idea/init.md" 76 | content = b64encode("cde".encode("utf8")).decode("utf8") 77 | print("\ncontent: " + content) 78 | sha = test_fetch_file_sha() 79 | resp = requests.put(url, data=json.dumps({ 80 | "message": "更新文件内容", 81 | "committer": { 82 | "name": "bmark-sync", 83 | "email": "thankall@yeah.net" 84 | }, 85 | "sha": f"{sha}", 86 | "content": f"{content}", 87 | "branch": "master" 88 | }), params={ 89 | "access_token": "be96fbcac43d1f6a6af2ec1a03e78d1557f1bd32" 90 | }) 91 | 92 | print(json.dumps(resp.json(), indent=4)) 93 | 94 | def test_create_image(): 95 | "GET /repos/:owner/:repo/git/blobs/:file_sha" 96 | url = "https://api.github.com/repos/xmings/JobFlow/contents/static/image/abc.png" 97 | resp = requests.get(url, data={ 98 | "ref": "master" 99 | }) 100 | print(json.dumps(resp.json(), indent=4)) 101 | return resp.json() 102 | 103 | 104 | if __name__ == '__main__': 105 | test_create_file() -------------------------------------------------------------------------------- /static/css/components/container.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Container 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Container 14 | *******************************/ 15 | 16 | 17 | /* All Sizes */ 18 | .ui.container { 19 | display: block; 20 | max-width: 100% !important; 21 | } 22 | 23 | /* Mobile */ 24 | @media only screen and (max-width: 767px) { 25 | .ui.container { 26 | width: auto !important; 27 | margin-left: 1em !important; 28 | margin-right: 1em !important; 29 | } 30 | .ui.grid.container { 31 | width: auto !important; 32 | } 33 | .ui.relaxed.grid.container { 34 | width: auto !important; 35 | } 36 | .ui.very.relaxed.grid.container { 37 | width: auto !important; 38 | } 39 | } 40 | 41 | /* Tablet */ 42 | @media only screen and (min-width: 768px) and (max-width: 991px) { 43 | .ui.container { 44 | width: 723px; 45 | margin-left: auto !important; 46 | margin-right: auto !important; 47 | } 48 | .ui.grid.container { 49 | width: calc( 723px + 2rem ) !important; 50 | } 51 | .ui.relaxed.grid.container { 52 | width: calc( 723px + 3rem ) !important; 53 | } 54 | .ui.very.relaxed.grid.container { 55 | width: calc( 723px + 5rem ) !important; 56 | } 57 | } 58 | 59 | /* Small Monitor */ 60 | @media only screen and (min-width: 992px) and (max-width: 1199px) { 61 | .ui.container { 62 | width: 933px; 63 | margin-left: auto !important; 64 | margin-right: auto !important; 65 | } 66 | .ui.grid.container { 67 | width: calc( 933px + 2rem ) !important; 68 | } 69 | .ui.relaxed.grid.container { 70 | width: calc( 933px + 3rem ) !important; 71 | } 72 | .ui.very.relaxed.grid.container { 73 | width: calc( 933px + 5rem ) !important; 74 | } 75 | } 76 | 77 | /* Large Monitor */ 78 | @media only screen and (min-width: 1200px) { 79 | .ui.container { 80 | width: 1127px; 81 | margin-left: auto !important; 82 | margin-right: auto !important; 83 | } 84 | .ui.grid.container { 85 | width: calc( 1127px + 2rem ) !important; 86 | } 87 | .ui.relaxed.grid.container { 88 | width: calc( 1127px + 3rem ) !important; 89 | } 90 | .ui.very.relaxed.grid.container { 91 | width: calc( 1127px + 5rem ) !important; 92 | } 93 | } 94 | 95 | 96 | /******************************* 97 | Types 98 | *******************************/ 99 | 100 | 101 | /* Text Container */ 102 | .ui.text.container { 103 | font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif; 104 | max-width: 700px !important; 105 | line-height: 1.5; 106 | } 107 | .ui.text.container { 108 | font-size: 1.14285714rem; 109 | } 110 | 111 | /* Fluid */ 112 | .ui.fluid.container { 113 | width: 100%; 114 | } 115 | 116 | 117 | /******************************* 118 | Variations 119 | *******************************/ 120 | 121 | .ui[class*="left aligned"].container { 122 | text-align: left; 123 | } 124 | .ui[class*="center aligned"].container { 125 | text-align: center; 126 | } 127 | .ui[class*="right aligned"].container { 128 | text-align: right; 129 | } 130 | .ui.justified.container { 131 | text-align: justify; 132 | -webkit-hyphens: auto; 133 | -ms-hyphens: auto; 134 | hyphens: auto; 135 | } 136 | 137 | 138 | /******************************* 139 | Theme Overrides 140 | *******************************/ 141 | 142 | 143 | 144 | /******************************* 145 | Site Overrides 146 | *******************************/ 147 | 148 | -------------------------------------------------------------------------------- /static/css/components/embed.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Video 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Types 14 | *******************************/ 15 | 16 | .ui.embed { 17 | position: relative; 18 | max-width: 100%; 19 | height: 0px; 20 | overflow: hidden; 21 | background: #DCDDDE; 22 | padding-bottom: 56.25%; 23 | } 24 | 25 | /*----------------- 26 | Embedded Content 27 | ------------------*/ 28 | 29 | .ui.embed iframe, 30 | .ui.embed embed, 31 | .ui.embed object { 32 | position: absolute; 33 | border: none; 34 | width: 100%; 35 | height: 100%; 36 | top: 0px; 37 | left: 0px; 38 | margin: 0em; 39 | padding: 0em; 40 | } 41 | 42 | /*----------------- 43 | Embed 44 | ------------------*/ 45 | 46 | .ui.embed > .embed { 47 | display: none; 48 | } 49 | 50 | /*-------------- 51 | Placeholder 52 | ---------------*/ 53 | 54 | .ui.embed > .placeholder { 55 | position: absolute; 56 | cursor: pointer; 57 | top: 0px; 58 | left: 0px; 59 | display: block; 60 | width: 100%; 61 | height: 100%; 62 | background-color: radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3)); 63 | } 64 | 65 | /*-------------- 66 | Icon 67 | ---------------*/ 68 | 69 | .ui.embed > .icon { 70 | cursor: pointer; 71 | position: absolute; 72 | top: 0px; 73 | left: 0px; 74 | width: 100%; 75 | height: 100%; 76 | z-index: 2; 77 | } 78 | .ui.embed > .icon:after { 79 | position: absolute; 80 | top: 0%; 81 | left: 0%; 82 | width: 100%; 83 | height: 100%; 84 | z-index: 3; 85 | content: ''; 86 | background: -webkit-radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3)); 87 | background: radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3)); 88 | opacity: 0.5; 89 | -webkit-transition: opacity 0.5s ease; 90 | transition: opacity 0.5s ease; 91 | } 92 | .ui.embed > .icon:before { 93 | position: absolute; 94 | top: 50%; 95 | left: 50%; 96 | z-index: 4; 97 | -webkit-transform: translateX(-50%) translateY(-50%); 98 | transform: translateX(-50%) translateY(-50%); 99 | color: #FFFFFF; 100 | font-size: 6rem; 101 | text-shadow: 0px 2px 10px rgba(34, 36, 38, 0.2); 102 | -webkit-transition: opacity 0.5s ease, color 0.5s ease; 103 | transition: opacity 0.5s ease, color 0.5s ease; 104 | z-index: 10; 105 | } 106 | 107 | 108 | /******************************* 109 | States 110 | *******************************/ 111 | 112 | 113 | /*-------------- 114 | Hover 115 | ---------------*/ 116 | 117 | .ui.embed .icon:hover:after { 118 | background: -webkit-radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3)); 119 | background: radial-gradient(transparent 45%, rgba(0, 0, 0, 0.3)); 120 | opacity: 1; 121 | } 122 | .ui.embed .icon:hover:before { 123 | color: #FFFFFF; 124 | } 125 | 126 | /*-------------- 127 | Active 128 | ---------------*/ 129 | 130 | .ui.active.embed > .icon, 131 | .ui.active.embed > .placeholder { 132 | display: none; 133 | } 134 | .ui.active.embed > .embed { 135 | display: block; 136 | } 137 | 138 | 139 | /******************************* 140 | Video Overrides 141 | *******************************/ 142 | 143 | 144 | 145 | /******************************* 146 | Site Overrides 147 | *******************************/ 148 | 149 | 150 | 151 | /******************************* 152 | Variations 153 | *******************************/ 154 | 155 | .ui.square.embed { 156 | padding-bottom: 100%; 157 | } 158 | .ui[class*="4:3"].embed { 159 | padding-bottom: 75%; 160 | } 161 | .ui[class*="16:9"].embed { 162 | padding-bottom: 56.25%; 163 | } 164 | .ui[class*="21:9"].embed { 165 | padding-bottom: 42.85714286%; 166 | } 167 | -------------------------------------------------------------------------------- /test/sync_by_sharding.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : sync_by_sharding.py 4 | # @Author: wangms 5 | # @Date : 2019/8/6 6 | 7 | import tempfile 8 | import os 9 | import zlib 10 | from hashlib import sha1 11 | from base64 import b64encode, b64decode 12 | 13 | import requests 14 | import json 15 | 16 | 17 | class Sharding(object): 18 | def __init__(self): 19 | self.block_size = 102400 20 | self.block_header = "wmsok".encode() 21 | self.datafile = "D:\\ideanote.db" 22 | self.work_dir = tempfile.mkdtemp() 23 | 24 | def slice(self): 25 | with open(self.datafile, "rb") as f: 26 | data = f.read() 27 | 28 | block_count = int(len(data) / self.block_size) 29 | for i in range(block_count): 30 | part = data[i * self.block_size: (i + 1) * self.block_size] 31 | yield f"file{i}", part 32 | 33 | yield f"file{block_count}", data[(block_count-1)*self.block_size:] 34 | 35 | def pull_block(self, name): 36 | url = f"https://api.github.com/repos/bmark-sync/test_github_api/contents/{name}" 37 | resp = requests.get(url, data={ 38 | "ref": "master" 39 | }) 40 | return b64decode(resp.json()["content"].encode()) 41 | 42 | def push_block(self, name, content, sha=None): 43 | url = f"https://api.github.com/repos/bmark-sync/test_github_api/contents/file{name}" 44 | data = { 45 | "message": "创建idea目录及内容文件", 46 | "committer": { 47 | "name": "bmark-sync", 48 | "email": "thankall@yeah.net" 49 | }, 50 | "content": f"{b64encode(content).decode('utf8')}", 51 | "branch": "master" 52 | } 53 | 54 | if sha: 55 | data["sha"] = sha 56 | resp = requests.put(url, data=json.dumps(data), params={ 57 | "access_token": "4e4c78b66abba6bdfa86ccf2f46cf87aeeb40046" 58 | }) 59 | assert resp.ok == True 60 | 61 | 62 | def calc_block_sha1(self, content): 63 | if isinstance(content, str): 64 | content = content.encode() 65 | 66 | s1 = sha1() 67 | s1.update(b"blob " + str(len(content)).encode() + b"\0" + content) 68 | return s1.hexdigest() 69 | 70 | 71 | def fetch_block_sha1(self, name): 72 | url = f"https://api.github.com/repos/bmark-sync/test_github_api/contents/{name}" 73 | resp = requests.get(url, data={ 74 | "ref": "master" 75 | }) 76 | return resp.json()["sha"] 77 | 78 | def push(self): 79 | url = "https://api.github.com/repos/bmark-sync/test_github_api/contents" 80 | resp = requests.get(url, data={ 81 | "ref": "master" 82 | }) 83 | remote_file_list = {} 84 | 85 | for i in resp.json(): 86 | if i["name"].startswith("file"): 87 | remote_file_list[i["name"]] = i["sha"] 88 | 89 | for filename, part in self.slice(): 90 | calc_sha1 = self.calc_block_sha1(part) 91 | remote_sha1 = remote_file_list.get(filename) 92 | if remote_sha1: 93 | if calc_sha1 != remote_sha1: 94 | print(f"update: {filename}") 95 | self.push_block(filename, part, remote_sha1) 96 | else: 97 | print(f"not change: {filename}") 98 | else: 99 | print(f"add: {filename}") 100 | self.push_block(filename, part) 101 | 102 | def pull(self): 103 | url = "https://api.github.com/repos/bmark-sync/test_github_api/contents" 104 | resp = requests.get(url, data={ 105 | "ref": "master" 106 | }) 107 | 108 | with open("d:\\ideanote.db", "ab") as f: 109 | for i in resp.json(): 110 | if i["name"].startswith("file"): 111 | f.write(self.pull_block(i["name"])) 112 | 113 | 114 | if __name__ == '__main__': 115 | s = Sharding() 116 | #s.push() 117 | s.pull() -------------------------------------------------------------------------------- /static/css/components/placeholder.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Loader 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.placeholder{position:static;overflow:hidden;-webkit-animation:placeholderShimmer 2s linear;animation:placeholderShimmer 2s linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;background-color:#fff;background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.08)),color-stop(15%,rgba(0,0,0,.15)),color-stop(30%,rgba(0,0,0,.08)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.08) 0,rgba(0,0,0,.15) 15%,rgba(0,0,0,.08) 30%);background-image:linear-gradient(to right,rgba(0,0,0,.08) 0,rgba(0,0,0,.15) 15%,rgba(0,0,0,.08) 30%);background-size:1200px 100%;max-width:30rem}@-webkit-keyframes placeholderShimmer{0%{background-position:-1200px 0}100%{background-position:1200px 0}}@keyframes placeholderShimmer{0%{background-position:-1200px 0}100%{background-position:1200px 0}}.ui.placeholder+.ui.placeholder{margin-top:2rem}.ui.placeholder+.ui.placeholder{-webkit-animation-delay:.15s;animation-delay:.15s}.ui.placeholder+.ui.placeholder+.ui.placeholder{-webkit-animation-delay:.3s;animation-delay:.3s}.ui.placeholder+.ui.placeholder+.ui.placeholder+.ui.placeholder{-webkit-animation-delay:.45s;animation-delay:.45s}.ui.placeholder+.ui.placeholder+.ui.placeholder+.ui.placeholder+.ui.placeholder{-webkit-animation-delay:.6s;animation-delay:.6s}.ui.placeholder,.ui.placeholder .image.header:after,.ui.placeholder .line,.ui.placeholder .line:after,.ui.placeholder>:before{background-color:#fff}.ui.placeholder .image:not(.header):not(.ui){height:100px}.ui.placeholder .square.image:not(.header){height:0;overflow:hidden;padding-top:100%}.ui.placeholder .rectangular.image:not(.header){height:0;overflow:hidden;padding-top:75%}.ui.placeholder .line{position:relative;height:.85714286em}.ui.placeholder .line:after,.ui.placeholder .line:before{top:100%;position:absolute;content:'';background-color:inherit}.ui.placeholder .line:before{left:0}.ui.placeholder .line:after{right:0}.ui.placeholder .line{margin-bottom:.5em}.ui.placeholder .line:after,.ui.placeholder .line:before{height:.5em}.ui.placeholder .line:not(:first-child){margin-top:.5em}.ui.placeholder .header{position:relative;overflow:hidden}.ui.placeholder .line:nth-child(1):after{width:0%}.ui.placeholder .line:nth-child(2):after{width:50%}.ui.placeholder .line:nth-child(3):after{width:10%}.ui.placeholder .line:nth-child(4):after{width:35%}.ui.placeholder .line:nth-child(5):after{width:65%}.ui.placeholder .header .line{margin-bottom:.64285714em}.ui.placeholder .header .line:after,.ui.placeholder .header .line:before{height:.64285714em}.ui.placeholder .header .line:not(:first-child){margin-top:.64285714em}.ui.placeholder .header .line:after{width:20%}.ui.placeholder .header .line:nth-child(2):after{width:60%}.ui.placeholder .image.header .line{margin-left:3em}.ui.placeholder .image.header .line:before{width:.71428571rem}.ui.placeholder .image.header:after{display:block;height:.85714286em;content:'';margin-left:3em}.ui.placeholder .header .line:first-child,.ui.placeholder .image .line:first-child,.ui.placeholder .paragraph .line:first-child{height:.01px}.ui.placeholder .header:not(:first-child):before,.ui.placeholder .image:not(:first-child):before,.ui.placeholder .paragraph:not(:first-child):before{height:1.42857143em;content:'';display:block}.ui.inverted.placeholder{background-image:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,.08)),color-stop(15%,rgba(255,255,255,.14)),color-stop(30%,rgba(255,255,255,.08)));background-image:-webkit-linear-gradient(left,rgba(255,255,255,.08) 0,rgba(255,255,255,.14) 15%,rgba(255,255,255,.08) 30%);background-image:linear-gradient(to right,rgba(255,255,255,.08) 0,rgba(255,255,255,.14) 15%,rgba(255,255,255,.08) 30%)}.ui.inverted.placeholder,.ui.inverted.placeholder .image.header:after,.ui.inverted.placeholder .line,.ui.inverted.placeholder .line:after,.ui.inverted.placeholder>:before{background-color:#1b1c1d}.ui.placeholder .full.line.line.line:after{width:0%}.ui.placeholder .very.long.line.line.line:after{width:10%}.ui.placeholder .long.line.line.line:after{width:35%}.ui.placeholder .medium.line.line.line:after{width:50%}.ui.placeholder .short.line.line.line:after{width:65%}.ui.placeholder .very.short.line.line.line:after{width:80%}.ui.fluid.placeholder{max-width:none} -------------------------------------------------------------------------------- /templates/sync_note_list.html: -------------------------------------------------------------------------------- 1 |
2 |
删除过期变更日志
3 |
4 | 5 |
6 | {% for i in note_list|sort(attribute='version_id', reverse=true) %} 7 |
10 |
11 | {{ i.version_id }} - {{ i.title }} 12 |
13 | {{ i.status }}, 来自: {{ i.from_client }}, 修改时间: {{ i.timestamp }} 14 | 15 | 查看 17 | 重应用 19 |
20 |
21 |
22 | {% endfor %} 23 |
24 | 25 | 33 | 34 | 103 | -------------------------------------------------------------------------------- /static/css/components/shape.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.0 - Shape 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Shape 14 | *******************************/ 15 | 16 | .ui.shape { 17 | position: relative; 18 | vertical-align: top; 19 | display: inline-block; 20 | -webkit-perspective: 2000px; 21 | perspective: 2000px; 22 | -webkit-transition: left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 23 | transition: left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 24 | transition: transform 0.6s ease-in-out, left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out; 25 | transition: transform 0.6s ease-in-out, left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 26 | } 27 | .ui.shape .sides { 28 | -webkit-transform-style: preserve-3d; 29 | transform-style: preserve-3d; 30 | } 31 | .ui.shape .side { 32 | opacity: 1; 33 | width: 100%; 34 | margin: 0em !important; 35 | -webkit-backface-visibility: hidden; 36 | backface-visibility: hidden; 37 | } 38 | .ui.shape .side { 39 | display: none; 40 | } 41 | .ui.shape .side * { 42 | -webkit-backface-visibility: visible !important; 43 | backface-visibility: visible !important; 44 | } 45 | 46 | 47 | /******************************* 48 | Types 49 | *******************************/ 50 | 51 | .ui.cube.shape .side { 52 | min-width: 15em; 53 | height: 15em; 54 | padding: 2em; 55 | background-color: #E6E6E6; 56 | color: rgba(0, 0, 0, 0.87); 57 | -webkit-box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.3); 58 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.3); 59 | } 60 | .ui.cube.shape .side > .content { 61 | width: 100%; 62 | height: 100%; 63 | display: table; 64 | text-align: center; 65 | -webkit-user-select: text; 66 | -moz-user-select: text; 67 | -ms-user-select: text; 68 | user-select: text; 69 | } 70 | .ui.cube.shape .side > .content > div { 71 | display: table-cell; 72 | vertical-align: middle; 73 | font-size: 2em; 74 | } 75 | 76 | 77 | /******************************* 78 | Variations 79 | *******************************/ 80 | 81 | .ui.text.shape.animating .sides { 82 | position: static; 83 | } 84 | .ui.text.shape .side { 85 | white-space: nowrap; 86 | } 87 | .ui.text.shape .side > * { 88 | white-space: normal; 89 | } 90 | 91 | 92 | /******************************* 93 | States 94 | *******************************/ 95 | 96 | 97 | /*-------------- 98 | Loading 99 | ---------------*/ 100 | 101 | .ui.loading.shape { 102 | position: absolute; 103 | top: -9999px; 104 | left: -9999px; 105 | } 106 | 107 | /*-------------- 108 | Animating 109 | ---------------*/ 110 | 111 | .ui.shape .animating.side { 112 | position: absolute; 113 | top: 0px; 114 | left: 0px; 115 | display: block; 116 | z-index: 100; 117 | } 118 | .ui.shape .hidden.side { 119 | opacity: 0.6; 120 | } 121 | 122 | /*-------------- 123 | CSS 124 | ---------------*/ 125 | 126 | .ui.shape.animating .sides { 127 | position: absolute; 128 | } 129 | .ui.shape.animating .sides { 130 | -webkit-transition: left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 131 | transition: left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 132 | transition: transform 0.6s ease-in-out, left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out; 133 | transition: transform 0.6s ease-in-out, left 0.6s ease-in-out, width 0.6s ease-in-out, height 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out; 134 | } 135 | .ui.shape.animating .side { 136 | -webkit-transition: opacity 0.6s ease-in-out; 137 | transition: opacity 0.6s ease-in-out; 138 | } 139 | 140 | /*-------------- 141 | Active 142 | ---------------*/ 143 | 144 | .ui.shape .active.side { 145 | display: block; 146 | } 147 | 148 | 149 | /******************************* 150 | Theme Overrides 151 | *******************************/ 152 | 153 | 154 | 155 | /******************************* 156 | User Overrides 157 | *******************************/ 158 | 159 | -------------------------------------------------------------------------------- /static/css/components/loader.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Loader 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.loader{display:none;position:absolute;top:50%;left:50%;margin:0;text-align:center;z-index:1000;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.ui.loader:before{position:absolute;content:'';top:0;left:50%;width:100%;height:100%;border-radius:500rem;border:.2em solid rgba(0,0,0,.1)}.ui.loader:after{position:absolute;content:'';top:0;left:50%;width:100%;height:100%;-webkit-animation:loader .6s linear;animation:loader .6s linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;border-radius:500rem;border-color:#767676 transparent transparent;border-style:solid;border-width:.2em;-webkit-box-shadow:0 0 0 1px transparent;box-shadow:0 0 0 1px transparent}@-webkit-keyframes loader{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loader{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.ui.mini.loader:after,.ui.mini.loader:before{width:1rem;height:1rem;margin:0 0 0 -.5rem}.ui.tiny.loader:after,.ui.tiny.loader:before{width:1.14285714rem;height:1.14285714rem;margin:0 0 0 -.57142857rem}.ui.small.loader:after,.ui.small.loader:before{width:1.71428571rem;height:1.71428571rem;margin:0 0 0 -.85714286rem}.ui.loader:after,.ui.loader:before{width:2.28571429rem;height:2.28571429rem;margin:0 0 0 -1.14285714rem}.ui.large.loader:after,.ui.large.loader:before{width:3.42857143rem;height:3.42857143rem;margin:0 0 0 -1.71428571rem}.ui.big.loader:after,.ui.big.loader:before{width:3.71428571rem;height:3.71428571rem;margin:0 0 0 -1.85714286rem}.ui.huge.loader:after,.ui.huge.loader:before{width:4.14285714rem;height:4.14285714rem;margin:0 0 0 -2.07142857rem}.ui.massive.loader:after,.ui.massive.loader:before{width:4.57142857rem;height:4.57142857rem;margin:0 0 0 -2.28571429rem}.ui.dimmer .loader{display:block}.ui.dimmer .ui.loader{color:rgba(255,255,255,.9)}.ui.dimmer .ui.loader:before{border-color:rgba(255,255,255,.15)}.ui.dimmer .ui.loader:after{border-color:#fff transparent transparent}.ui.inverted.dimmer .ui.loader{color:rgba(0,0,0,.87)}.ui.inverted.dimmer .ui.loader:before{border-color:rgba(0,0,0,.1)}.ui.inverted.dimmer .ui.loader:after{border-color:#767676 transparent transparent}.ui.text.loader{width:auto!important;height:auto!important;text-align:center;font-style:normal}.ui.indeterminate.loader:after{animation-direction:reverse;-webkit-animation-duration:1.2s;animation-duration:1.2s}.ui.loader.active,.ui.loader.visible{display:block}.ui.loader.disabled,.ui.loader.hidden{display:none}.ui.inverted.dimmer .ui.mini.loader,.ui.mini.loader{width:1rem;height:1rem;font-size:.78571429em}.ui.inverted.dimmer .ui.tiny.loader,.ui.tiny.loader{width:1.14285714rem;height:1.14285714rem;font-size:.85714286em}.ui.inverted.dimmer .ui.small.loader,.ui.small.loader{width:1.71428571rem;height:1.71428571rem;font-size:.92857143em}.ui.inverted.dimmer .ui.loader,.ui.loader{width:2.28571429rem;height:2.28571429rem;font-size:1em}.ui.inverted.dimmer .ui.large.loader,.ui.large.loader{width:3.42857143rem;height:3.42857143rem;font-size:1.14285714em}.ui.big.loader,.ui.inverted.dimmer .ui.big.loader{width:3.71428571rem;height:3.71428571rem;font-size:1.28571429em}.ui.huge.loader,.ui.inverted.dimmer .ui.huge.loader{width:4.14285714rem;height:4.14285714rem;font-size:1.42857143em}.ui.inverted.dimmer .ui.massive.loader,.ui.massive.loader{width:4.57142857rem;height:4.57142857rem;font-size:1.71428571em}.ui.mini.text.loader{min-width:1rem;padding-top:1.78571429rem}.ui.tiny.text.loader{min-width:1.14285714rem;padding-top:1.92857143rem}.ui.small.text.loader{min-width:1.71428571rem;padding-top:2.5rem}.ui.text.loader{min-width:2.28571429rem;padding-top:3.07142857rem}.ui.large.text.loader{min-width:3.42857143rem;padding-top:4.21428571rem}.ui.big.text.loader{min-width:3.71428571rem;padding-top:4.5rem}.ui.huge.text.loader{min-width:4.14285714rem;padding-top:4.92857143rem}.ui.massive.text.loader{min-width:4.57142857rem;padding-top:5.35714286rem}.ui.inverted.loader{color:rgba(255,255,255,.9)}.ui.inverted.loader:before{border-color:rgba(255,255,255,.15)}.ui.inverted.loader:after{border-top-color:#fff}.ui.inline.loader{position:relative;vertical-align:middle;margin:0;left:0;top:0;-webkit-transform:none;transform:none}.ui.inline.loader.active,.ui.inline.loader.visible{display:inline-block}.ui.centered.inline.loader.active,.ui.centered.inline.loader.visible{display:block;margin-left:auto;margin-right:auto} -------------------------------------------------------------------------------- /sync/sync_utils/netdisk_sync_utils.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : netdisk_sync_utils.py 4 | # @Author: wangms 5 | # @Date : 2019/8/8 6 | 7 | import json 8 | import os 9 | import socket 10 | import pickle 11 | from datetime import datetime, timedelta 12 | from sync.sync_utils.base_sync_utils import BaseSyncUtils 13 | from common import status_text_mapping 14 | 15 | 16 | class NetDiskSyncUtils(BaseSyncUtils): 17 | def __init__(self, work_dir): 18 | self.work_dir = work_dir 19 | self.version_info_file = os.path.join(self.work_dir, "version_info.json") 20 | self.note_info_file_suffix = ".note" 21 | 22 | def is_online(self): 23 | try: 24 | socket.getaddrinfo("www.baidu.com", 80) 25 | except: 26 | return False 27 | return True 28 | 29 | def init_version_info(self): 30 | with open(self.version_info_file, "w", encoding="utf8") as f: 31 | f.write(json.dumps({ 32 | "latest_version": 0, 33 | "client_id": socket.gethostname(), 34 | "change_time": datetime.now().isoformat() 35 | }, ensure_ascii=False, indent=4)) 36 | 37 | def load_version_info(self) -> dict: 38 | with open(self.version_info_file, "r", encoding="utf8") as f: 39 | return json.loads(f.read()) 40 | 41 | def dump_version_info(self, version_info: dict) -> bool: 42 | with open(self.version_info_file, "w", encoding="utf8") as f: 43 | f.write(json.dumps(version_info, ensure_ascii=False, indent=4)) 44 | return True 45 | 46 | def load_note_info(self, version: int) -> dict: 47 | for filename in os.listdir(self.work_dir): 48 | if filename.endswith(self.note_info_file_suffix): 49 | version_id, note_id = os.path.splitext(filename)[0].split("-") 50 | if version == int(version_id): 51 | note_info_file = os.path.join(self.work_dir, filename) 52 | with open(note_info_file, "rb") as f: 53 | return pickle.loads(f.read()) 54 | return {} 55 | 56 | def load_latest_note_info(self, note_id) -> dict: 57 | latest_note_version = 0 58 | for filename in os.listdir(self.work_dir): 59 | if filename.find(note_id)>0 and filename.endswith(self.note_info_file_suffix): 60 | version_id, note_id = os.path.splitext(filename)[0].split("-") 61 | latest_note_version = max(version_id, latest_note_version) 62 | 63 | note_info_file = os.path.join(self.work_dir, f"{latest_note_version}-{note_id}{self.note_info_file_suffix}") 64 | 65 | if os.path.isfile(note_info_file): 66 | with open(note_info_file, "rb") as f: 67 | return pickle.loads(f.read()) 68 | return {} 69 | 70 | def load_note_info_by_version_note_id(self, version, note_id) -> dict: 71 | note_info_file = os.path.join(self.work_dir, f"{version}-{note_id}{self.note_info_file_suffix}") 72 | if os.path.isfile(note_info_file): 73 | with open(note_info_file, "rb") as f: 74 | return pickle.loads(f.read()) 75 | return {} 76 | 77 | def dump_note_info(self, note_info: dict) -> bool: 78 | filename = f"{note_info.get('version')}-{note_info.get('id')}{self.note_info_file_suffix}" 79 | note_info_file = os.path.join(self.work_dir, filename) 80 | with open(note_info_file, "wb") as f: 81 | f.write(pickle.dumps(note_info)) 82 | return True 83 | 84 | def fetch_sync_note_list(self): 85 | result = [] 86 | 87 | for filename in [i for i in os.listdir(self.work_dir) if i.endswith(self.note_info_file_suffix)]: 88 | version_id, note_id = filename[:-len(self.note_info_file_suffix)].split("-") 89 | note = self.load_note_info_by_version_note_id(version_id, note_id) 90 | result.append({ 91 | "version_id": note.get("version"), 92 | "note_id": note.get("id"), 93 | "filename": filename, 94 | "title": note.get("title"), 95 | "status": status_text_mapping.get(note.get("status")), 96 | "from_client": note.get("client_id"), 97 | "timestamp": note.get("timestamp") 98 | }) 99 | return result 100 | 101 | def delete_obsolete_change(self, day:int=30): 102 | for i in self.fetch_sync_note_list(): 103 | if i.get("timestamp") + timedelta(days=day) < datetime.now(): 104 | os.remove(os.path.join(self.work_dir, i.get("filename"))) 105 | return True 106 | -------------------------------------------------------------------------------- /static/css/components/site.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Site 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Page 14 | *******************************/ 15 | 16 | @import url('https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin'); 17 | html, 18 | body { 19 | height: 100%; 20 | } 21 | html { 22 | font-size: 14px; 23 | } 24 | body { 25 | margin: 0px; 26 | padding: 0px; 27 | overflow-x: hidden; 28 | min-width: 320px; 29 | background: #FFFFFF; 30 | font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif; 31 | font-size: 14px; 32 | line-height: 1.4285em; 33 | color: rgba(0, 0, 0, 0.87); 34 | font-smoothing: antialiased; 35 | } 36 | 37 | 38 | /******************************* 39 | Headers 40 | *******************************/ 41 | 42 | h1, 43 | h2, 44 | h3, 45 | h4, 46 | h5 { 47 | font-family: 'Lato', 'Helvetica Neue', Arial, Helvetica, sans-serif; 48 | line-height: 1.28571429em; 49 | margin: calc(2rem - 0.14285714em ) 0em 1rem; 50 | font-weight: bold; 51 | padding: 0em; 52 | } 53 | h1 { 54 | min-height: 1rem; 55 | font-size: 2rem; 56 | } 57 | h2 { 58 | font-size: 1.71428571rem; 59 | } 60 | h3 { 61 | font-size: 1.28571429rem; 62 | } 63 | h4 { 64 | font-size: 1.07142857rem; 65 | } 66 | h5 { 67 | font-size: 1rem; 68 | } 69 | h1:first-child, 70 | h2:first-child, 71 | h3:first-child, 72 | h4:first-child, 73 | h5:first-child { 74 | margin-top: 0em; 75 | } 76 | h1:last-child, 77 | h2:last-child, 78 | h3:last-child, 79 | h4:last-child, 80 | h5:last-child { 81 | margin-bottom: 0em; 82 | } 83 | 84 | 85 | /******************************* 86 | Text 87 | *******************************/ 88 | 89 | p { 90 | margin: 0em 0em 1em; 91 | line-height: 1.4285em; 92 | } 93 | p:first-child { 94 | margin-top: 0em; 95 | } 96 | p:last-child { 97 | margin-bottom: 0em; 98 | } 99 | 100 | /*------------------- 101 | Links 102 | --------------------*/ 103 | 104 | a { 105 | color: #4183C4; 106 | text-decoration: none; 107 | } 108 | a:hover { 109 | color: #1e70bf; 110 | text-decoration: none; 111 | } 112 | 113 | 114 | /******************************* 115 | Scrollbars 116 | *******************************/ 117 | 118 | 119 | 120 | /******************************* 121 | Highlighting 122 | *******************************/ 123 | 124 | 125 | /* Site */ 126 | ::-webkit-selection { 127 | background-color: #CCE2FF; 128 | color: rgba(0, 0, 0, 0.87); 129 | } 130 | ::-moz-selection { 131 | background-color: #CCE2FF; 132 | color: rgba(0, 0, 0, 0.87); 133 | } 134 | ::selection { 135 | background-color: #CCE2FF; 136 | color: rgba(0, 0, 0, 0.87); 137 | } 138 | 139 | /* Form */ 140 | textarea::-webkit-selection, 141 | input::-webkit-selection { 142 | background-color: rgba(100, 100, 100, 0.4); 143 | color: rgba(0, 0, 0, 0.87); 144 | } 145 | textarea::-moz-selection, 146 | input::-moz-selection { 147 | background-color: rgba(100, 100, 100, 0.4); 148 | color: rgba(0, 0, 0, 0.87); 149 | } 150 | textarea::selection, 151 | input::selection { 152 | background-color: rgba(100, 100, 100, 0.4); 153 | color: rgba(0, 0, 0, 0.87); 154 | } 155 | 156 | /* Force Simple Scrollbars */ 157 | body ::-webkit-scrollbar { 158 | -webkit-appearance: none; 159 | width: 10px; 160 | height: 10px; 161 | } 162 | body ::-webkit-scrollbar-track { 163 | background: rgba(0, 0, 0, 0.1); 164 | border-radius: 0px; 165 | } 166 | body ::-webkit-scrollbar-thumb { 167 | cursor: pointer; 168 | border-radius: 5px; 169 | background: rgba(0, 0, 0, 0.25); 170 | -webkit-transition: color 0.2s ease; 171 | transition: color 0.2s ease; 172 | } 173 | body ::-webkit-scrollbar-thumb:window-inactive { 174 | background: rgba(0, 0, 0, 0.15); 175 | } 176 | body ::-webkit-scrollbar-thumb:hover { 177 | background: rgba(128, 135, 139, 0.8); 178 | } 179 | 180 | /* Inverted UI */ 181 | body .ui.inverted::-webkit-scrollbar-track { 182 | background: rgba(255, 255, 255, 0.1); 183 | } 184 | body .ui.inverted::-webkit-scrollbar-thumb { 185 | background: rgba(255, 255, 255, 0.25); 186 | } 187 | body .ui.inverted::-webkit-scrollbar-thumb:window-inactive { 188 | background: rgba(255, 255, 255, 0.15); 189 | } 190 | body .ui.inverted::-webkit-scrollbar-thumb:hover { 191 | background: rgba(255, 255, 255, 0.35); 192 | } 193 | 194 | 195 | /******************************* 196 | Global Overrides 197 | *******************************/ 198 | 199 | 200 | 201 | /******************************* 202 | Site Overrides 203 | *******************************/ 204 | 205 | -------------------------------------------------------------------------------- /common/utils.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : utils.py 4 | # @Author: wangms 5 | # @Date : 2019/7/27 6 | import os 7 | from dataclasses import dataclass, field 8 | from datetime import datetime, date 9 | from logging import getLogger, INFO, DEBUG, Formatter, StreamHandler, basicConfig 10 | from logging.handlers import TimedRotatingFileHandler 11 | import yaml 12 | import json 13 | 14 | 15 | def timestamp_from_str(s): 16 | if s: 17 | return datetime.fromisoformat(s) 18 | return None 19 | 20 | 21 | def timestamp_to_str(ts): 22 | if ts: 23 | return str(ts) 24 | return None 25 | 26 | 27 | def timestamp_max(ts1, ts2): 28 | if ts1 is None: 29 | return ts2 30 | elif ts2 is None: 31 | return ts1 32 | return max(ts1, ts2) 33 | 34 | 35 | class ConfigLoader(object): 36 | def __init__(self): 37 | project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 38 | with open(os.path.join(project_root, "config.yml"), "r", encoding="utf8") as f: 39 | self.config = yaml.load(f.read(), Loader=yaml.FullLoader) 40 | 41 | @property 42 | def sync_method(self): 43 | return self.config.get("IdeaNote").get("sync").get("method") 44 | 45 | @property 46 | def sync_connection_info(self): 47 | return self.config.get("IdeaNote").get("sync").get("connection") 48 | 49 | @property 50 | def sync_work_dir(self): 51 | return self.config.get("IdeaNote").get("sync").get("work_dir") 52 | 53 | @property 54 | def metadata_file(self): 55 | return self.config.get("IdeaNote").get("metadata_file") 56 | 57 | @property 58 | def note_data_path(self): 59 | return self.config.get("IdeaNote").get("note_data_path") 60 | 61 | @property 62 | def flask_config(self): 63 | return self.config.get("IdeaNote").get("flask").get("config") 64 | 65 | @property 66 | def db_config(self): 67 | return self.config.get("IdeaNote").get("db").get("config") 68 | 69 | @property 70 | def log_directory(self): 71 | return self.config.get("IdeaNote").get("log").get("directory") 72 | 73 | @property 74 | def log_formatter(self): 75 | return self.config.get("IdeaNote").get("log").get("formatter") 76 | 77 | @property 78 | def app_port(self): 79 | return self.config.get("IdeaNote").get("port") 80 | 81 | @property 82 | def hide_window(self): 83 | return self.config.get("IdeaNote").get("hide_window") 84 | 85 | @property 86 | def urlmark_sync(self): 87 | return self.config.get("IdeaNote").get("urlmark").get("sync") 88 | 89 | @property 90 | def urlmark_file(self): 91 | return self.config.get("IdeaNote").get("urlmark").get("sync_file") 92 | 93 | @property 94 | def auth_code(self): 95 | return self.config.get("IdeaNote").get("auth_code") 96 | 97 | 98 | conf = ConfigLoader() 99 | 100 | 101 | @dataclass(order=True) 102 | class Item(object): 103 | id: int 104 | title: str 105 | parent_id: int 106 | children: list = field(repr=False, default_factory=list) 107 | 108 | 109 | class JsonEncoderForFrontEnd(json.JSONEncoder): 110 | def default(self, o): 111 | if isinstance(o, Item): 112 | if o.children: 113 | return { 114 | "id": o.id, 115 | "name": o.title, 116 | "open": False, 117 | "children": o.children 118 | } 119 | return { 120 | "id": o.id, 121 | "name": o.title, 122 | "open": False 123 | } 124 | return super().default(o) 125 | 126 | 127 | basicConfig(format=conf.log_formatter, datefmt=None) 128 | 129 | 130 | def fetch_logger(logger_name, log_filename): 131 | logger = getLogger(logger_name) 132 | logger.setLevel(DEBUG) 133 | logger.propagate = False 134 | 135 | if len(logger.handlers) == 0: 136 | file_handler = TimedRotatingFileHandler( 137 | filename=os.path.join(conf.log_directory, log_filename), 138 | when="midnight", 139 | encoding="utf8" 140 | ) 141 | file_handler.setLevel(INFO) 142 | file_handler.setFormatter(Formatter(conf.log_formatter)) 143 | 144 | console_handler = StreamHandler() 145 | console_handler.setLevel(DEBUG) 146 | console_handler.setFormatter(Formatter(conf.log_formatter)) 147 | 148 | logger.addHandler(file_handler) 149 | logger.addHandler(console_handler) 150 | return logger 151 | 152 | 153 | class Resp(object): 154 | def __init__(self, status, content): 155 | self.status = status 156 | self.content = content 157 | -------------------------------------------------------------------------------- /static/css/components/rating.min.js: -------------------------------------------------------------------------------- 1 | !function(C,e,n,T){"use strict";e=void 0!==e&&e.Math==Math?e:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")(),C.fn.rating=function(m){var f,v=C(this),p=v.selector||"",b=(new Date).getTime(),h=[],y=m,x="string"==typeof y,R=[].slice.call(arguments,1);return v.each(function(){var e,i,a=C.isPlainObject(m)?C.extend(!0,{},C.fn.rating.settings,m):C.extend({},C.fn.rating.settings),n=a.namespace,o=a.className,t=a.metadata,r=a.selector,s=(a.error,"."+n),l="module-"+n,c=this,u=C(this).data(l),d=C(this),g=d.find(r.icon);i={initialize:function(){i.verbose("Initializing rating module",a),0===g.length&&i.setup.layout(),a.interactive?i.enable():i.disable(),i.set.initialLoad(),i.set.rating(i.get.initialRating()),i.remove.initialLoad(),i.instantiate()},instantiate:function(){i.verbose("Instantiating module",a),u=i,d.data(l,i)},destroy:function(){i.verbose("Destroying previous instance",u),i.remove.events(),d.removeData(l)},refresh:function(){g=d.find(r.icon)},setup:{layout:function(){var e=i.get.maxRating(),n=C.fn.rating.settings.templates.icon(e);i.debug("Generating icon html dynamically"),d.html(n),i.refresh()}},event:{mouseenter:function(){var e=C(this);e.nextAll().removeClass(o.selected),d.addClass(o.selected),e.addClass(o.selected).prevAll().addClass(o.selected)},mouseleave:function(){d.removeClass(o.selected),g.removeClass(o.selected)},click:function(){var e=C(this),n=i.get.rating(),t=g.index(e)+1;("auto"==a.clearable?1===g.length:a.clearable)&&n==t?i.clearRating():i.set.rating(t)}},clearRating:function(){i.debug("Clearing current rating"),i.set.rating(0)},bind:{events:function(){i.verbose("Binding events"),d.on("mouseenter"+s,r.icon,i.event.mouseenter).on("mouseleave"+s,r.icon,i.event.mouseleave).on("click"+s,r.icon,i.event.click)}},remove:{events:function(){i.verbose("Removing events"),d.off(s)},initialLoad:function(){e=!1}},enable:function(){i.debug("Setting rating to interactive mode"),i.bind.events(),d.removeClass(o.disabled)},disable:function(){i.debug("Setting rating to read-only mode"),i.remove.events(),d.addClass(o.disabled)},is:{initialLoad:function(){return e}},get:{initialRating:function(){return d.data(t.rating)!==T?(d.removeData(t.rating),d.data(t.rating)):a.initialRating},maxRating:function(){return d.data(t.maxRating)!==T?(d.removeData(t.maxRating),d.data(t.maxRating)):a.maxRating},rating:function(){var e=g.filter("."+o.active).length;return i.verbose("Current rating retrieved",e),e}},set:{rating:function(e){var n=0<=e-1?e-1:0,t=g.eq(n);d.removeClass(o.selected),g.removeClass(o.selected).removeClass(o.active),0',n++;return t}}}}(jQuery,window,document); -------------------------------------------------------------------------------- /static/css/components/ad.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Ad 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Copyright 2013 Contributors 7 | * Released under the MIT license 8 | * http://opensource.org/licenses/MIT 9 | * 10 | */ 11 | 12 | 13 | /******************************* 14 | Advertisement 15 | *******************************/ 16 | 17 | .ui.ad { 18 | display: block; 19 | overflow: hidden; 20 | margin: 1em 0em; 21 | } 22 | .ui.ad:first-child { 23 | margin: 0em; 24 | } 25 | .ui.ad:last-child { 26 | margin: 0em; 27 | } 28 | .ui.ad iframe { 29 | margin: 0em; 30 | padding: 0em; 31 | border: none; 32 | overflow: hidden; 33 | } 34 | 35 | /*-------------- 36 | Common 37 | ---------------*/ 38 | 39 | 40 | /* Leaderboard */ 41 | .ui.leaderboard.ad { 42 | width: 728px; 43 | height: 90px; 44 | } 45 | 46 | /* Medium Rectangle */ 47 | .ui[class*="medium rectangle"].ad { 48 | width: 300px; 49 | height: 250px; 50 | } 51 | 52 | /* Large Rectangle */ 53 | .ui[class*="large rectangle"].ad { 54 | width: 336px; 55 | height: 280px; 56 | } 57 | 58 | /* Half Page */ 59 | .ui[class*="half page"].ad { 60 | width: 300px; 61 | height: 600px; 62 | } 63 | 64 | /*-------------- 65 | Square 66 | ---------------*/ 67 | 68 | 69 | /* Square */ 70 | .ui.square.ad { 71 | width: 250px; 72 | height: 250px; 73 | } 74 | 75 | /* Small Square */ 76 | .ui[class*="small square"].ad { 77 | width: 200px; 78 | height: 200px; 79 | } 80 | 81 | /*-------------- 82 | Rectangle 83 | ---------------*/ 84 | 85 | 86 | /* Small Rectangle */ 87 | .ui[class*="small rectangle"].ad { 88 | width: 180px; 89 | height: 150px; 90 | } 91 | 92 | /* Vertical Rectangle */ 93 | .ui[class*="vertical rectangle"].ad { 94 | width: 240px; 95 | height: 400px; 96 | } 97 | 98 | /*-------------- 99 | Button 100 | ---------------*/ 101 | 102 | .ui.button.ad { 103 | width: 120px; 104 | height: 90px; 105 | } 106 | .ui[class*="square button"].ad { 107 | width: 125px; 108 | height: 125px; 109 | } 110 | .ui[class*="small button"].ad { 111 | width: 120px; 112 | height: 60px; 113 | } 114 | 115 | /*-------------- 116 | Skyscrapers 117 | ---------------*/ 118 | 119 | 120 | /* Skyscraper */ 121 | .ui.skyscraper.ad { 122 | width: 120px; 123 | height: 600px; 124 | } 125 | 126 | /* Wide Skyscraper */ 127 | .ui[class*="wide skyscraper"].ad { 128 | width: 160px; 129 | } 130 | 131 | /*-------------- 132 | Banners 133 | ---------------*/ 134 | 135 | 136 | /* Banner */ 137 | .ui.banner.ad { 138 | width: 468px; 139 | height: 60px; 140 | } 141 | 142 | /* Vertical Banner */ 143 | .ui[class*="vertical banner"].ad { 144 | width: 120px; 145 | height: 240px; 146 | } 147 | 148 | /* Top Banner */ 149 | .ui[class*="top banner"].ad { 150 | width: 930px; 151 | height: 180px; 152 | } 153 | 154 | /* Half Banner */ 155 | .ui[class*="half banner"].ad { 156 | width: 234px; 157 | height: 60px; 158 | } 159 | 160 | /*-------------- 161 | Boards 162 | ---------------*/ 163 | 164 | 165 | /* Leaderboard */ 166 | .ui[class*="large leaderboard"].ad { 167 | width: 970px; 168 | height: 90px; 169 | } 170 | 171 | /* Billboard */ 172 | .ui.billboard.ad { 173 | width: 970px; 174 | height: 250px; 175 | } 176 | 177 | /*-------------- 178 | Panorama 179 | ---------------*/ 180 | 181 | 182 | /* Panorama */ 183 | .ui.panorama.ad { 184 | width: 980px; 185 | height: 120px; 186 | } 187 | 188 | /*-------------- 189 | Netboard 190 | ---------------*/ 191 | 192 | 193 | /* Netboard */ 194 | .ui.netboard.ad { 195 | width: 580px; 196 | height: 400px; 197 | } 198 | 199 | /*-------------- 200 | Mobile 201 | ---------------*/ 202 | 203 | 204 | /* Large Mobile Banner */ 205 | .ui[class*="large mobile banner"].ad { 206 | width: 320px; 207 | height: 100px; 208 | } 209 | 210 | /* Mobile Leaderboard */ 211 | .ui[class*="mobile leaderboard"].ad { 212 | width: 320px; 213 | height: 50px; 214 | } 215 | 216 | 217 | /******************************* 218 | Types 219 | *******************************/ 220 | 221 | 222 | /* Mobile Sizes */ 223 | .ui.mobile.ad { 224 | display: none; 225 | } 226 | @media only screen and (max-width: 767px) { 227 | .ui.mobile.ad { 228 | display: block; 229 | } 230 | } 231 | 232 | 233 | /******************************* 234 | Variations 235 | *******************************/ 236 | 237 | .ui.centered.ad { 238 | margin-left: auto; 239 | margin-right: auto; 240 | } 241 | .ui.test.ad { 242 | position: relative; 243 | background: #545454; 244 | } 245 | .ui.test.ad:after { 246 | position: absolute; 247 | top: 50%; 248 | left: 50%; 249 | width: 100%; 250 | text-align: center; 251 | -webkit-transform: translateX(-50%) translateY(-50%); 252 | transform: translateX(-50%) translateY(-50%); 253 | content: 'Ad'; 254 | color: #FFFFFF; 255 | font-size: 1em; 256 | font-weight: bold; 257 | } 258 | .ui.mobile.test.ad:after { 259 | font-size: 0.85714286em; 260 | } 261 | .ui.test.ad[data-text]:after { 262 | content: attr(data-text); 263 | } 264 | 265 | 266 | /******************************* 267 | Theme Overrides 268 | *******************************/ 269 | 270 | 271 | 272 | /******************************* 273 | User Variable Overrides 274 | *******************************/ 275 | 276 | -------------------------------------------------------------------------------- /test/test_onedrive.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # -*- coding: utf-8 -*- 3 | # @File : test_onedrive.py 4 | # @Author: wangms 5 | # @Date : 2019/7/27 6 | from common import conf 7 | from urllib.parse import quote, unquote 8 | import webbrowser 9 | import requests 10 | import json 11 | 12 | def test_onedrive_connection(): 13 | info = conf.git_connection_info 14 | base_url = """ 15 | https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize? 16 | client_id={client_id} 17 | &response_type={response_type} 18 | &redirect_uri={redirect_uri} 19 | &response_mode={response_mode} 20 | &scope={scope} 21 | &state={state} 22 | """.format(tenant=info["tenant"], 23 | client_id=info["client_id"], 24 | response_type=info["response_type"], 25 | redirect_uri=quote(info["redirect_uri"]), 26 | response_mode=info["response_mode"], 27 | scope=quote(info["scope"]), 28 | state=info["state"]) 29 | print(base_url) 30 | webbrowser.open(base_url) 31 | 32 | session = requests.Session() 33 | token = "" 34 | def test_fetch_onedrive_token(): 35 | base_url = """https://login.microsoftonline.com/56bf626c-6568-4dfb-b53b-3145c8ef7618/oauth2/v2.0/token""" 36 | 37 | resp = session.post(base_url,data={ 38 | "client_id": "963224c0-fdef-4c42-8ccb-6474d5a5f086", 39 | "scope": "https://graph.microsoft.com/.default", 40 | "client_secret": "4X3PslAkd.UE=21MmC-pJhnE_qASJRML", 41 | "grant_type": "client_credentials" 42 | }, headers={ 43 | "Host": "login.microsoftonline.com", 44 | "Content-Type" : "application/x-www-form-urlencoded" 45 | }) 46 | result = resp.json() 47 | print("\n") 48 | print(result["access_token"]) 49 | token = result["access_token"] 50 | return token 51 | 52 | 53 | def test_fetch_user_info(): 54 | token = "eyJ0eXAiOiJKV1QiLCJub25jZSI6Im1hYlhveXVoeUR3MWZYdzRmRWVHZzlNLUpzbUF1N0k4aGZCU2NKWWpDVjgiLCJhbGciOiJSUzI1NiIsIng1dCI6InU0T2ZORlBId0VCb3NIanRyYXVPYlY4NExuWSIsImtpZCI6InU0T2ZORlBId0VCb3NIanRyYXVPYlY4NExuWSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC81NmJmNjI2Yy02NTY4LTRkZmItYjUzYi0zMTQ1YzhlZjc2MTgvIiwiaWF0IjoxNTY0MzE2MDM2LCJuYmYiOjE1NjQzMTYwMzYsImV4cCI6MTU2NDMxOTkzNiwiYWlvIjoiNDJGZ1lQQ2FWLzdpVnpDZjZZeWZHM2RadUQzM0F3QT0iLCJhcHBfZGlzcGxheW5hbWUiOiJJZGVhTm90ZSIsImFwcGlkIjoiOTYzMjI0YzAtZmRlZi00YzQyLThjY2ItNjQ3NGQ1YTVmMDg2IiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvNTZiZjYyNmMtNjU2OC00ZGZiLWI1M2ItMzE0NWM4ZWY3NjE4LyIsIm9pZCI6ImMwMzU3NzJmLTg2NWMtNGU4ZS1hMDA4LTY0ZDNmNzliYWU3YiIsInJvbGVzIjpbIlVzZXIuUmVhZFdyaXRlLkFsbCIsIlNpdGVzLlJlYWQuQWxsIiwiU2l0ZXMuUmVhZFdyaXRlLkFsbCIsIkZpbGVzLlJlYWRXcml0ZS5BbGwiLCJVc2VyLlJlYWQuQWxsIiwiRmlsZXMuUmVhZC5BbGwiXSwic3ViIjoiYzAzNTc3MmYtODY1Yy00ZThlLWEwMDgtNjRkM2Y3OWJhZTdiIiwidGlkIjoiNTZiZjYyNmMtNjU2OC00ZGZiLWI1M2ItMzE0NWM4ZWY3NjE4IiwidXRpIjoiamNUdy1OQ25kRXlraDFPeGhWY3lBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTY0MjE4Mjg1fQ.Fyx5Mk6fyLzjGqJg0cov9zqIo-muh1MAsUTsH-4SbjCwvRZ2WYouqgV30RDyCcTJvsnARKPjq7AW6fpnoI8TD7xhlmIaptDNn_uiSPFpRsYJ_KLjAkd2U-CYQ9rkOaY-s5ZT_AH4IvvRZ3tlJMgK5YnYK3eJQR24mYPiTEqOqmhByTXBE__Rc_sYcfcl5UbET91QUwwLd4Snq9-6VJ4JygoFF8FQEAuIWCkspXtX86FnrS_Fj1WBnOxP7416OPiMrVLdUaaUTRHqZxL1JaYwFfdfdtAAC29UfomXOHApAIk_pootqeDjIBulBjwl29s4MGlG7JRWzhS25-QInREV9w" 55 | base_url = "https://graph.microsoft.com/v1.0/users/77661ab0-7626-4800-b344-ceec5ca6adc0" 56 | resp = session.get(base_url, headers={ 57 | "Authorization": "Bearer {}".format(token), 58 | "Host": "graph.microsoft.com" 59 | }) 60 | print(json.dumps(resp.json(), indent=4, ensure_ascii=False)) 61 | 62 | 63 | def test_fetch_onedrive_data(): 64 | token="eyJ0eXAiOiJKV1QiLCJub25jZSI6ImN1QVJMT1l3TzRsZkVXMjFuN21PMUpoSHViRnBLTjVKckgwcEhELUNvNmciLCJhbGciOiJSUzI1NiIsIng1dCI6InU0T2ZORlBId0VCb3NIanRyYXVPYlY4NExuWSIsImtpZCI6InU0T2ZORlBId0VCb3NIanRyYXVPYlY4NExuWSJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC81NmJmNjI2Yy02NTY4LTRkZmItYjUzYi0zMTQ1YzhlZjc2MTgvIiwiaWF0IjoxNTY0MzE2OTM3LCJuYmYiOjE1NjQzMTY5MzcsImV4cCI6MTU2NDMyMDgzNywiYWlvIjoiNDJGZ1lHZ0pteVo5YitITkI1eFQ0eElXemowL0F3QT0iLCJhcHBfZGlzcGxheW5hbWUiOiJJZGVhTm90ZSIsImFwcGlkIjoiOTYzMjI0YzAtZmRlZi00YzQyLThjY2ItNjQ3NGQ1YTVmMDg2IiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvNTZiZjYyNmMtNjU2OC00ZGZiLWI1M2ItMzE0NWM4ZWY3NjE4LyIsIm9pZCI6ImMwMzU3NzJmLTg2NWMtNGU4ZS1hMDA4LTY0ZDNmNzliYWU3YiIsInJvbGVzIjpbIlVzZXIuUmVhZFdyaXRlLkFsbCIsIlNpdGVzLlJlYWQuQWxsIiwiU2l0ZXMuUmVhZFdyaXRlLkFsbCIsIkZpbGVzLlJlYWRXcml0ZS5BbGwiLCJVc2VyLlJlYWQuQWxsIiwiRmlsZXMuUmVhZC5BbGwiXSwic3ViIjoiYzAzNTc3MmYtODY1Yy00ZThlLWEwMDgtNjRkM2Y3OWJhZTdiIiwidGlkIjoiNTZiZjYyNmMtNjU2OC00ZGZiLWI1M2ItMzE0NWM4ZWY3NjE4IiwidXRpIjoiS21PcVRCYTVSRTZtRzF6R2thTXJBQSIsInZlciI6IjEuMCIsInhtc190Y2R0IjoxNTY0MjE4Mjg1fQ.U8pefQNSm3P9u0CYJCY_gORe77zcWJEl87BL_8cjumy-eSUmUhWtrNY99fYO-gD-oMlCPTsw7QdZIgN_uuSS5tB8iLnP3wDna0l71jdOUCWcx-9eYmcGMJgnU3cv4ghjcMQniEqgoqT9sjCwq1wuFUqZhwcWyFJeFVjttUIwnSPH94WQvvFvJlACXGq5Uw6ZedS3PFBEIh-P9E7jvItq0ILwp1h86XPWcRRvAAGUImBMwgK5kCWga3GCMX9Zy5SX410Xuu01lIAEUg3M8Slyx51kX1J1NuPC6hp8lTRqHIxh8SDG6eqqw51rC-rkQNSoqUi37MGYBTfoJ1TKPKp1KQ" 65 | base_url = "https://graph.microsoft.com/v1.0/me/drive/root/children" 66 | resp = session.get(base_url, headers={ 67 | "Authorization": "Bearer {}".format(token), 68 | "Host": "graph.microsoft.com" 69 | }) 70 | print(json.dumps(resp.json(), indent=4, ensure_ascii=False)) -------------------------------------------------------------------------------- /static/css/components/nag.min.js: -------------------------------------------------------------------------------- 1 | !function(y,k,e,S){"use strict";k=void 0!==k&&k.Math==Math?k:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")(),y.fn.nag=function(u){var d,e=y(this),m=e.selector||"",f=(new Date).getTime(),p=[],h=u,b="string"==typeof h,v=[].slice.call(arguments,1);return e.each(function(){var r,n=y.isPlainObject(u)?y.extend(!0,{},y.fn.nag.settings,u):y.extend({},y.fn.nag.settings),e=(n.className,n.selector),l=n.error,o=n.namespace,t="."+o,i=o+"-module",s=y(this),a=(s.find(e.close),n.context?y(n.context):y("body")),c=this,g=s.data(i);k.requestAnimationFrame||k.mozRequestAnimationFrame||k.webkitRequestAnimationFrame||k.msRequestAnimationFrame;r={initialize:function(){r.verbose("Initializing element"),s.on("click"+t,e.close,r.dismiss).data(i,r),n.detachable&&s.parent()[0]!==a[0]&&s.detach().prependTo(a),0 2 | 3 | 4 | 5 | 6 | IdeaNote 7 | 8 | 9 | {% block cssdefine %}{% endblock %} 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% block jsdefinebefore %}{% endblock %} 17 | 18 | 19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
验证
28 |
29 |
30 | 31 | 32 | 40 | 41 | {% block content %} 42 |
43 |
44 | 49 | 50 |
51 |
    52 |
    53 |
    54 |
      55 |
      56 |
      57 | 60 | 63 | 66 |
      67 | 68 |
      69 |
      70 |
      71 | {% block centerframe %}{% endblock %} 72 |
      73 |
      74 |
      75 |
      76 | {% endblock %} 77 | 78 | 79 | 131 | {% block jsdefineafter %}{% endblock %} 132 | 133 | -------------------------------------------------------------------------------- /static/css/components/reveal.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Reveal 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.reveal{display:inherit;position:relative!important;font-size:0!important}.ui.reveal>.visible.content{position:absolute!important;top:0!important;left:0!important;z-index:3!important;-webkit-transition:all .5s ease .1s;transition:all .5s ease .1s}.ui.reveal>.hidden.content{position:relative!important;z-index:2!important}.ui.active.reveal .visible.content,.ui.reveal:hover .visible.content{z-index:4!important}.ui.slide.reveal{position:relative!important;overflow:hidden!important;white-space:nowrap}.ui.slide.reveal>.content{display:block;width:100%;white-space:normal;float:left;margin:0;-webkit-transition:-webkit-transform .5s ease .1s;transition:-webkit-transform .5s ease .1s;transition:transform .5s ease .1s;transition:transform .5s ease .1s,-webkit-transform .5s ease .1s}.ui.slide.reveal>.visible.content{position:relative!important}.ui.slide.reveal>.hidden.content{position:absolute!important;left:0!important;width:100%!important;-webkit-transform:translateX(100%)!important;transform:translateX(100%)!important}.ui.slide.active.reveal>.visible.content,.ui.slide.reveal:hover>.visible.content{-webkit-transform:translateX(-100%)!important;transform:translateX(-100%)!important}.ui.slide.active.reveal>.hidden.content,.ui.slide.reveal:hover>.hidden.content{-webkit-transform:translateX(0)!important;transform:translateX(0)!important}.ui.slide.right.reveal>.visible.content{-webkit-transform:translateX(0)!important;transform:translateX(0)!important}.ui.slide.right.reveal>.hidden.content{-webkit-transform:translateX(-100%)!important;transform:translateX(-100%)!important}.ui.slide.right.active.reveal>.visible.content,.ui.slide.right.reveal:hover>.visible.content{-webkit-transform:translateX(100%)!important;transform:translateX(100%)!important}.ui.slide.right.active.reveal>.hidden.content,.ui.slide.right.reveal:hover>.hidden.content{-webkit-transform:translateX(0)!important;transform:translateX(0)!important}.ui.slide.up.reveal>.hidden.content{-webkit-transform:translateY(100%)!important;transform:translateY(100%)!important}.ui.slide.up.active.reveal>.visible.content,.ui.slide.up.reveal:hover>.visible.content{-webkit-transform:translateY(-100%)!important;transform:translateY(-100%)!important}.ui.slide.up.active.reveal>.hidden.content,.ui.slide.up.reveal:hover>.hidden.content{-webkit-transform:translateY(0)!important;transform:translateY(0)!important}.ui.slide.down.reveal>.hidden.content{-webkit-transform:translateY(-100%)!important;transform:translateY(-100%)!important}.ui.slide.down.active.reveal>.visible.content,.ui.slide.down.reveal:hover>.visible.content{-webkit-transform:translateY(100%)!important;transform:translateY(100%)!important}.ui.slide.down.active.reveal>.hidden.content,.ui.slide.down.reveal:hover>.hidden.content{-webkit-transform:translateY(0)!important;transform:translateY(0)!important}.ui.fade.reveal>.visible.content{opacity:1}.ui.fade.active.reveal>.visible.content,.ui.fade.reveal:hover>.visible.content{opacity:0}.ui.move.reveal{position:relative!important;overflow:hidden!important;white-space:nowrap}.ui.move.reveal>.content{display:block;float:left;white-space:normal;margin:0;-webkit-transition:-webkit-transform .5s cubic-bezier(.175,.885,.32,1) .1s;transition:-webkit-transform .5s cubic-bezier(.175,.885,.32,1) .1s;transition:transform .5s cubic-bezier(.175,.885,.32,1) .1s;transition:transform .5s cubic-bezier(.175,.885,.32,1) .1s,-webkit-transform .5s cubic-bezier(.175,.885,.32,1) .1s}.ui.move.reveal>.visible.content{position:relative!important}.ui.move.reveal>.hidden.content{position:absolute!important;left:0!important;width:100%!important}.ui.move.active.reveal>.visible.content,.ui.move.reveal:hover>.visible.content{-webkit-transform:translateX(-100%)!important;transform:translateX(-100%)!important}.ui.move.right.active.reveal>.visible.content,.ui.move.right.reveal:hover>.visible.content{-webkit-transform:translateX(100%)!important;transform:translateX(100%)!important}.ui.move.up.active.reveal>.visible.content,.ui.move.up.reveal:hover>.visible.content{-webkit-transform:translateY(-100%)!important;transform:translateY(-100%)!important}.ui.move.down.active.reveal>.visible.content,.ui.move.down.reveal:hover>.visible.content{-webkit-transform:translateY(100%)!important;transform:translateY(100%)!important}.ui.rotate.reveal>.visible.content{-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transform:rotate(0);transform:rotate(0)}.ui.rotate.reveal>.visible.content,.ui.rotate.right.reveal>.visible.content{-webkit-transform-origin:bottom right;transform-origin:bottom right}.ui.rotate.active.reveal>.visible.content,.ui.rotate.reveal:hover>.visible.content,.ui.rotate.right.active.reveal>.visible.content,.ui.rotate.right.reveal:hover>.visible.content{-webkit-transform:rotate(110deg);transform:rotate(110deg)}.ui.rotate.left.reveal>.visible.content{-webkit-transform-origin:bottom left;transform-origin:bottom left}.ui.rotate.left.active.reveal>.visible.content,.ui.rotate.left.reveal:hover>.visible.content{-webkit-transform:rotate(-110deg);transform:rotate(-110deg)}.ui.disabled.reveal:hover>.visible.visible.content{position:static!important;display:block!important;opacity:1!important;top:0!important;left:0!important;right:auto!important;bottom:auto!important;-webkit-transform:none!important;transform:none!important}.ui.disabled.reveal:hover>.hidden.hidden.content{display:none!important}.ui.reveal>.ui.ribbon.label{z-index:5}.ui.visible.reveal{overflow:visible}.ui.instant.reveal>.content{-webkit-transition-delay:0s!important;transition-delay:0s!important}.ui.reveal>.content{font-size:1rem!important} -------------------------------------------------------------------------------- /static/css/codemirror.min.css: -------------------------------------------------------------------------------- 1 | .CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5);-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:-20px;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute;pointer-events:none}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-focused div.CodeMirror-cursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background-color:#ffa;background-color:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0} 2 | /*# sourceMappingURL=codemirror.min.css.map */ -------------------------------------------------------------------------------- /static/css/components/item.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Item 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */.ui.items>.item{display:-webkit-box;display:-ms-flexbox;display:flex;margin:1em 0;width:100%;min-height:0;background:0 0;padding:0;border:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:-webkit-box-shadow .1s ease;transition:-webkit-box-shadow .1s ease;transition:box-shadow .1s ease;transition:box-shadow .1s ease,-webkit-box-shadow .1s ease;z-index:''}.ui.items>.item a{cursor:pointer}.ui.items{margin:1.5em 0}.ui.items:first-child{margin-top:0!important}.ui.items:last-child{margin-bottom:0!important}.ui.items>.item:after{display:block;content:' ';height:0;clear:both;overflow:hidden;visibility:hidden}.ui.items>.item:first-child{margin-top:0}.ui.items>.item:last-child{margin-bottom:0}.ui.items>.item>.image{position:relative;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;display:block;float:none;margin:0;padding:0;max-height:'';-ms-flex-item-align:top;align-self:top}.ui.items>.item>.image>img{display:block;width:100%;height:auto;border-radius:.125rem;border:none}.ui.items>.item>.image:only-child>img{border-radius:0}.ui.items>.item>.content{display:block;-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;background:0 0;margin:0;padding:0;-webkit-box-shadow:none;box-shadow:none;font-size:1em;border:none;border-radius:0}.ui.items>.item>.content:after{display:block;content:' ';height:0;clear:both;overflow:hidden;visibility:hidden}.ui.items>.item>.image+.content{min-width:0;width:auto;display:block;margin-left:0;-ms-flex-item-align:top;align-self:top;padding-left:1.5em}.ui.items>.item>.content>.header{display:inline-block;margin:-.21425em 0 0;font-family:Lato,'Helvetica Neue',Arial,Helvetica,sans-serif;font-weight:700;color:rgba(0,0,0,.85)}.ui.items>.item>.content>.header:not(.ui){font-size:1.28571429em}.ui.items>.item [class*="left floated"]{float:left}.ui.items>.item [class*="right floated"]{float:right}.ui.items>.item .content img{-ms-flex-item-align:middle;align-self:middle;width:''}.ui.items>.item .avatar img,.ui.items>.item img.avatar{width:'';height:'';border-radius:500rem}.ui.items>.item>.content>.description{margin-top:.6em;max-width:auto;font-size:1em;line-height:1.4285em;color:rgba(0,0,0,.87)}.ui.items>.item>.content p{margin:0 0 .5em}.ui.items>.item>.content p:last-child{margin-bottom:0}.ui.items>.item .meta{margin:.5em 0 .5em;font-size:1em;line-height:1em;color:rgba(0,0,0,.6)}.ui.items>.item .meta *{margin-right:.3em}.ui.items>.item .meta :last-child{margin-right:0}.ui.items>.item .meta [class*="right floated"]{margin-right:0;margin-left:.3em}.ui.items>.item>.content a:not(.ui){color:'';-webkit-transition:color .1s ease;transition:color .1s ease}.ui.items>.item>.content a:not(.ui):hover{color:''}.ui.items>.item>.content>a.header{color:rgba(0,0,0,.85)}.ui.items>.item>.content>a.header:hover{color:#1e70bf}.ui.items>.item .meta>a:not(.ui){color:rgba(0,0,0,.4)}.ui.items>.item .meta>a:not(.ui):hover{color:rgba(0,0,0,.87)}.ui.items>.item>.content .favorite.icon{cursor:pointer;opacity:.75;-webkit-transition:color .1s ease;transition:color .1s ease}.ui.items>.item>.content .favorite.icon:hover{opacity:1;color:#ffb70a}.ui.items>.item>.content .active.favorite.icon{color:#ffe623}.ui.items>.item>.content .like.icon{cursor:pointer;opacity:.75;-webkit-transition:color .1s ease;transition:color .1s ease}.ui.items>.item>.content .like.icon:hover{opacity:1;color:#ff2733}.ui.items>.item>.content .active.like.icon{color:#ff2733}.ui.items>.item .extra{display:block;position:relative;background:0 0;margin:.5rem 0 0;width:100%;padding:0 0 0;top:0;left:0;color:rgba(0,0,0,.4);-webkit-box-shadow:none;box-shadow:none;-webkit-transition:color .1s ease;transition:color .1s ease;border-top:none}.ui.items>.item .extra>*{margin:.25rem .5rem .25rem 0}.ui.items>.item .extra>[class*="right floated"]{margin:.25rem 0 .25rem .5rem}.ui.items>.item .extra:after{display:block;content:' ';height:0;clear:both;overflow:hidden;visibility:hidden}.ui.items>.item>.image:not(.ui){width:175px}@media only screen and (min-width:768px) and (max-width:991px){.ui.items>.item{margin:1em 0}.ui.items>.item>.image:not(.ui){width:150px}.ui.items>.item>.image+.content{display:block;padding:0 0 0 1em}}@media only screen and (max-width:767px){.ui.items:not(.unstackable)>.item{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin:2em 0}.ui.items:not(.unstackable)>.item>.image{display:block;margin-left:auto;margin-right:auto}.ui.items:not(.unstackable)>.item>.image,.ui.items:not(.unstackable)>.item>.image>img{max-width:100%!important;width:auto!important;max-height:250px!important}.ui.items:not(.unstackable)>.item>.image+.content{display:block;padding:1.5em 0 0}}.ui.items>.item>.image+[class*="top aligned"].content{-ms-flex-item-align:start;align-self:flex-start}.ui.items>.item>.image+[class*="middle aligned"].content{-ms-flex-item-align:center;align-self:center}.ui.items>.item>.image+[class*="bottom aligned"].content{-ms-flex-item-align:end;align-self:flex-end}.ui.relaxed.items>.item{margin:1.5em 0}.ui[class*="very relaxed"].items>.item{margin:2em 0}.ui.divided.items>.item{border-top:1px solid rgba(34,36,38,.15);margin:0;padding:1em 0}.ui.divided.items>.item:first-child{border-top:none;margin-top:0!important;padding-top:0!important}.ui.divided.items>.item:last-child{margin-bottom:0!important;padding-bottom:0!important}.ui.relaxed.divided.items>.item{margin:0;padding:1.5em 0}.ui[class*="very relaxed"].divided.items>.item{margin:0;padding:2em 0}.ui.items a.item:hover,.ui.link.items>.item:hover{cursor:pointer}.ui.items a.item:hover .content .header,.ui.link.items>.item:hover .content .header{color:#1e70bf}.ui.items>.item{font-size:1em}@media only screen and (max-width:767px){.ui.unstackable.items>.item>.image,.ui.unstackable.items>.item>.image>img{width:125px!important}} -------------------------------------------------------------------------------- /static/css/components/site.min.js: -------------------------------------------------------------------------------- 1 | !function(b,p,v,h){b.site=b.fn.site=function(e){var a,c,i=(new Date).getTime(),t=[],n=e,o="string"==typeof n,l=[].slice.call(arguments,1),u=b.isPlainObject(e)?b.extend(!0,{},b.site.settings,e):b.extend({},b.site.settings),s=u.namespace,m=u.error,r="module-"+s,d=b(v),g=this,f=d.data(r);return a={initialize:function(){a.instantiate()},instantiate:function(){a.verbose("Storing instance of site",a),f=a,d.data(r,a)},normalize:function(){a.fix.console(),a.fix.requestAnimationFrame()},fix:{console:function(){a.debug("Normalizing window.console"),console!==h&&console.log!==h||(a.verbose("Console not available, normalizing events"),a.disable.console()),void 0!==console.group&&void 0!==console.groupEnd&&void 0!==console.groupCollapsed||(a.verbose("Console group not available, normalizing events"),p.console.group=function(){},p.console.groupEnd=function(){},p.console.groupCollapsed=function(){}),void 0===console.markTimeline&&(a.verbose("Mark timeline not available, normalizing events"),p.console.markTimeline=function(){})},consoleClear:function(){a.debug("Disabling programmatic console clearing"),p.console.clear=function(){}},requestAnimationFrame:function(){a.debug("Normalizing requestAnimationFrame"),p.requestAnimationFrame===h&&(a.debug("RequestAnimationFrame not available, normalizing event"),p.requestAnimationFrame=p.requestAnimationFrame||p.mozRequestAnimationFrame||p.webkitRequestAnimationFrame||p.msRequestAnimationFrame||function(e){setTimeout(e,0)})}},moduleExists:function(e){return b.fn[e]!==h&&b.fn[e].settings!==h},enabled:{modules:function(e){var o=[];return e=e||u.modules,b.each(e,function(e,n){a.moduleExists(n)&&o.push(n)}),o}},disabled:{modules:function(e){var o=[];return e=e||u.modules,b.each(e,function(e,n){a.moduleExists(n)||o.push(n)}),o}},change:{setting:function(t,s,e,r){e="string"==typeof e?"all"===e?u.modules:[e]:e||u.modules,r=r===h||r,b.each(e,function(e,n){var o,i=!a.moduleExists(n)||(b.fn[n].settings.namespace||!1);a.moduleExists(n)&&(a.verbose("Changing default setting",t,s,n),b.fn[n].settings[t]=s,r&&i&&0<(o=b(":data(module-"+i+")")).length&&(a.verbose("Modifying existing settings",o),o[n]("setting",t,s)))})},settings:function(i,e,t){e="string"==typeof e?[e]:e||u.modules,t=t===h||t,b.each(e,function(e,n){var o;a.moduleExists(n)&&(a.verbose("Changing default setting",i,n),b.extend(!0,b.fn[n].settings,i),t&&s&&0<(o=b(":data(module-"+s+")")).length&&(a.verbose("Modifying existing settings",o),o[n]("setting",i)))})}},enable:{console:function(){a.console(!0)},debug:function(e,n){e=e||u.modules,a.debug("Enabling debug for modules",e),a.change.setting("debug",!0,e,n)},verbose:function(e,n){e=e||u.modules,a.debug("Enabling verbose debug for modules",e),a.change.setting("verbose",!0,e,n)}},disable:{console:function(){a.console(!1)},debug:function(e,n){e=e||u.modules,a.debug("Disabling debug for modules",e),a.change.setting("debug",!1,e,n)},verbose:function(e,n){e=e||u.modules,a.debug("Disabling verbose debug for modules",e),a.change.setting("verbose",!1,e,n)}},console:function(e){if(e){if(f.cache.console===h)return void a.error(m.console);a.debug("Restoring console function"),p.console=f.cache.console}else a.debug("Disabling console function"),f.cache.console=p.console,p.console={clear:function(){},error:function(){},group:function(){},groupCollapsed:function(){},groupEnd:function(){},info:function(){},log:function(){},markTimeline:function(){},warn:function(){}}},destroy:function(){a.verbose("Destroying previous site for",d),d.removeData(r)},cache:{},setting:function(e,n){if(b.isPlainObject(e))b.extend(!0,u,e);else{if(n===h)return u[e];u[e]=n}},internal:function(e,n){if(b.isPlainObject(e))b.extend(!0,a,e);else{if(n===h)return a[e];a[e]=n}},debug:function(){u.debug&&(u.performance?a.performance.log(arguments):(a.debug=Function.prototype.bind.call(console.info,console,u.name+":"),a.debug.apply(console,arguments)))},verbose:function(){u.verbose&&u.debug&&(u.performance?a.performance.log(arguments):(a.verbose=Function.prototype.bind.call(console.info,console,u.name+":"),a.verbose.apply(console,arguments)))},error:function(){a.error=Function.prototype.bind.call(console.error,console,u.name+":"),a.error.apply(console,arguments)},performance:{log:function(e){var n,o;u.performance&&(o=(n=(new Date).getTime())-(i||n),i=n,t.push({Element:g,Name:e[0],Arguments:[].slice.call(e,1)||"","Execution Time":o})),clearTimeout(a.performance.timer),a.performance.timer=setTimeout(a.performance.display,500)},display:function(){var e=u.name+":",o=0;i=!1,clearTimeout(a.performance.timer),b.each(t,function(e,n){o+=n["Execution Time"]}),e+=" "+o+"ms",(console.group!==h||console.table!==h)&&0.column+.divider,.ui.grid>.row>.column+.divider{left:auto}.ui.horizontal.divider{display:table;white-space:nowrap;height:auto;margin:'';line-height:1;text-align:center}.ui.horizontal.divider:after,.ui.horizontal.divider:before{content:'';display:table-cell;position:relative;top:50%;width:50%;background-repeat:no-repeat}.ui.horizontal.divider:before{background-position:right 1em top 50%}.ui.horizontal.divider:after{background-position:left 1em top 50%}.ui.vertical.divider{position:absolute;z-index:2;top:50%;left:50%;margin:0;padding:0;width:auto;height:50%;line-height:0;text-align:center;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.ui.vertical.divider:after,.ui.vertical.divider:before{position:absolute;left:50%;content:'';z-index:3;border-left:1px solid rgba(34,36,38,.15);border-right:1px solid rgba(255,255,255,.1);width:0%;height:calc(100% - 1rem)}.ui.vertical.divider:before{top:-100%}.ui.vertical.divider:after{top:auto;bottom:0}@media only screen and (max-width:767px){.ui.grid .stackable.row .ui.vertical.divider,.ui.stackable.grid .ui.vertical.divider{display:table;white-space:nowrap;height:auto;margin:'';overflow:hidden;line-height:1;text-align:center;position:static;top:0;left:0;-webkit-transform:none;transform:none}.ui.grid .stackable.row .ui.vertical.divider:after,.ui.grid .stackable.row .ui.vertical.divider:before,.ui.stackable.grid .ui.vertical.divider:after,.ui.stackable.grid .ui.vertical.divider:before{position:static;left:0;border-left:none;border-right:none;content:'';display:table-cell;position:relative;top:50%;width:50%;background-repeat:no-repeat}.ui.grid .stackable.row .ui.vertical.divider:before,.ui.stackable.grid .ui.vertical.divider:before{background-position:right 1em top 50%}.ui.grid .stackable.row .ui.vertical.divider:after,.ui.stackable.grid .ui.vertical.divider:after{background-position:left 1em top 50%}}.ui.divider>.icon{margin:0;font-size:1rem;height:1em;vertical-align:middle}.ui.hidden.divider{border-color:transparent!important}.ui.hidden.divider:after,.ui.hidden.divider:before{display:none}.ui.divider.inverted,.ui.horizontal.inverted.divider,.ui.vertical.inverted.divider{color:#fff}.ui.divider.inverted,.ui.divider.inverted:after,.ui.divider.inverted:before{border-top-color:rgba(34,36,38,.15)!important;border-left-color:rgba(34,36,38,.15)!important;border-bottom-color:rgba(255,255,255,.15)!important;border-right-color:rgba(255,255,255,.15)!important}.ui.fitted.divider{margin:0}.ui.clearing.divider{clear:both}.ui.section.divider{margin-top:2rem;margin-bottom:2rem}.ui.divider{font-size:1rem}.ui.horizontal.divider:after,.ui.horizontal.divider:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaAAAAACCAYAAACuTHuKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1OThBRDY4OUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1OThBRDY4QUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjU5OEFENjg3Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU5OEFENjg4Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+VU513gAAADVJREFUeNrs0DENACAQBDBIWLGBJQby/mUcJn5sJXQmOQMAAAAAAJqt+2prAAAAAACg2xdgANk6BEVuJgyMAAAAAElFTkSuQmCC)}@media only screen and (max-width:767px){.ui.grid .stackable.row .ui.vertical.divider:after,.ui.grid .stackable.row .ui.vertical.divider:before,.ui.stackable.grid .ui.vertical.divider:after,.ui.stackable.grid .ui.vertical.divider:before{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaAAAAACCAYAAACuTHuKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1OThBRDY4OUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1OThBRDY4QUNDMTYxMUU0OUE3NUVGOEJDMzMzMjE2NyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjU5OEFENjg3Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjU5OEFENjg4Q0MxNjExRTQ5QTc1RUY4QkMzMzMyMTY3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+VU513gAAADVJREFUeNrs0DENACAQBDBIWLGBJQby/mUcJn5sJXQmOQMAAAAAAJqt+2prAAAAAACg2xdgANk6BEVuJgyMAAAAAElFTkSuQmCC)}} -------------------------------------------------------------------------------- /static/css/components/video.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.0.0 - Video 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Copyright 2014 Contributorss 7 | * Released under the MIT license 8 | * http://opensource.org/licenses/MIT 9 | * 10 | */ 11 | !function(e,o,t,n){"use strict";e.fn.video=function(t){{var a,i=e(this),r=i.selector||"",l=(new Date).getTime(),c=[],u=arguments[0],s="string"==typeof u,m=[].slice.call(arguments,1);o.requestAnimationFrame||o.mozRequestAnimationFrame||o.webkitRequestAnimationFrame||o.msRequestAnimationFrame||function(e){setTimeout(e,0)}}return i.each(function(){var d,p=e.isPlainObject(t)?e.extend(!0,{},e.fn.video.settings,t):e.extend({},e.fn.video.settings),f=p.selector,g=p.className,h=p.error,v=p.metadata,b=p.namespace,y=p.templates,w="."+b,x="module-"+b,F=(e(o),e(this)),C=F.find(f.placeholder),E=F.find(f.playButton),T=F.find(f.embed),A=this,P=F.data(x);d={initialize:function(){d.debug("Initializing video"),d.create(),F.on("click"+w,f.placeholder,d.play).on("click"+w,f.playButton,d.play),d.instantiate()},instantiate:function(){d.verbose("Storing instance of module",d),P=d,F.data(x,d)},create:function(){var e=F.data(v.image),o=y.video(e);F.html(o),d.refresh(),e||d.play(),d.debug("Creating html for video element",o)},destroy:function(){d.verbose("Destroying previous instance of video"),d.reset(),F.removeData(x).off(w)},refresh:function(){d.verbose("Refreshing selector cache"),C=F.find(f.placeholder),E=F.find(f.playButton),T=F.find(f.embed)},change:function(e,o,t){d.debug("Changing video to ",e,o,t),F.data(v.source,e).data(v.id,o).data(v.url,t),p.onChange()},reset:function(){d.debug("Clearing video embed and showing placeholder"),F.removeClass(g.active),T.html(" "),C.show(),p.onReset()},play:function(){d.debug("Playing video");var e=F.data(v.source)||!1,o=F.data(v.url)||!1,t=F.data(v.id)||!1;T.html(d.generate.html(e,t,o)),F.addClass(g.active),p.onPlay()},get:{source:function(e){return"string"!=typeof e?!1:-1!==e.search("youtube.com")?"youtube":-1!==e.search("vimeo.com")?"vimeo":!1},id:function(e){return e.match(p.regExp.youtube)?e.match(p.regExp.youtube)[1]:e.match(p.regExp.vimeo)?e.match(p.regExp.vimeo)[2]:!1}},generate:{html:function(e,o,t){d.debug("Generating embed html");var n;return e=e||p.source,o=o||p.id,e&&o||t?(e&&o||(e=d.get.source(t),o=d.get.id(t)),"vimeo"==e?n='':"youtube"==e&&(n='')):d.error(h.noVideo),n},url:function(e){var o=p.api?1:0,t="auto"===p.autoplay?F.data("image")!==n:p.autoplay,a=p.hd?1:0,i=p.showUI?1:0,r=p.showUI?0:1,l="";return"vimeo"==e&&(l="api="+o+"&title="+i+"&byline="+i+"&portrait="+i+"&autoplay="+t,p.color&&(l+="&color="+p.color)),"ustream"==e?(l="autoplay="+t,p.color&&(l+="&color="+p.color)):"youtube"==e&&(l="enablejsapi="+o+"&autoplay="+t+"&autohide="+r+"&hq="+a+"&modestbranding=1",p.color&&(l+="&color="+p.color)),l}},setting:function(o,t){if(d.debug("Changing setting",o,t),e.isPlainObject(o))e.extend(!0,p,o);else{if(t===n)return p[o];p[o]=t}},internal:function(o,t){if(e.isPlainObject(o))e.extend(!0,d,o);else{if(t===n)return d[o];d[o]=t}},debug:function(){p.debug&&(p.performance?d.performance.log(arguments):(d.debug=Function.prototype.bind.call(console.info,console,p.name+":"),d.debug.apply(console,arguments)))},verbose:function(){p.verbose&&p.debug&&(p.performance?d.performance.log(arguments):(d.verbose=Function.prototype.bind.call(console.info,console,p.name+":"),d.verbose.apply(console,arguments)))},error:function(){d.error=Function.prototype.bind.call(console.error,console,p.name+":"),d.error.apply(console,arguments)},performance:{log:function(e){var o,t,n;p.performance&&(o=(new Date).getTime(),n=l||o,t=o-n,l=o,c.push({Name:e[0],Arguments:[].slice.call(e,1)||"",Element:A,"Execution Time":t})),clearTimeout(d.performance.timer),d.performance.timer=setTimeout(d.performance.display,500)},display:function(){var o=p.name+":",t=0;l=!1,clearTimeout(d.performance.timer),e.each(c,function(e,o){t+=o["Execution Time"]}),o+=" "+t+"ms",r&&(o+=" '"+r+"'"),i.length>1&&(o+=" ("+i.length+")"),(console.group!==n||console.table!==n)&&c.length>0&&(console.groupCollapsed(o),console.table?console.table(c):e.each(c,function(e,o){console.log(o.Name+": "+o["Execution Time"]+"ms")}),console.groupEnd()),c=[]}},invoke:function(o,t,i){var r,l,c,u=P;return t=t||m,i=A||i,"string"==typeof o&&u!==n&&(o=o.split(/[\. ]/),r=o.length-1,e.each(o,function(t,a){var i=t!=r?a+o[t+1].charAt(0).toUpperCase()+o[t+1].slice(1):o;if(e.isPlainObject(u[i])&&t!=r)u=u[i];else{if(u[i]!==n)return l=u[i],!1;if(!e.isPlainObject(u[a])||t==r)return u[a]!==n?(l=u[a],!1):(d.error(h.method,o),!1);u=u[a]}})),e.isFunction(l)?c=l.apply(i,t):l!==n&&(c=l),e.isArray(a)?a.push(c):a!==n?a=[a,c]:c!==n&&(a=c),l}},s?(P===n&&d.initialize(),d.invoke(u)):(P!==n&&P.invoke("destroy"),d.initialize())}),a!==n?a:this},e.fn.video.settings={name:"Video",namespace:"video",debug:!1,verbose:!1,performance:!0,metadata:{id:"id",image:"image",source:"source",url:"url"},source:!1,url:!1,id:!1,aspectRatio:16/9,onPlay:function(){},onReset:function(){},onChange:function(){},onPause:function(){},onStop:function(){},width:"auto",height:"auto",autoplay:"auto",color:"#442359",hd:!0,showUI:!1,api:!0,regExp:{youtube:/^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/,vimeo:/http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/},error:{noVideo:"No video specified",method:"The method you called is not defined"},className:{active:"active"},selector:{embed:".embed",placeholder:".placeholder",playButton:".play"}},e.fn.video.settings.templates={video:function(e){var o="";return e&&(o+=''),o+='
      '}}}(jQuery,window,document); -------------------------------------------------------------------------------- /static/css/components/comment.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * # Semantic UI 2.4.1 - Comment 3 | * http://github.com/semantic-org/semantic-ui/ 4 | * 5 | * 6 | * Released under the MIT license 7 | * http://opensource.org/licenses/MIT 8 | * 9 | */ 10 | 11 | 12 | /******************************* 13 | Standard 14 | *******************************/ 15 | 16 | 17 | /*-------------- 18 | Comments 19 | ---------------*/ 20 | 21 | .ui.comments { 22 | margin: 1.5em 0em; 23 | max-width: 650px; 24 | } 25 | .ui.comments:first-child { 26 | margin-top: 0em; 27 | } 28 | .ui.comments:last-child { 29 | margin-bottom: 0em; 30 | } 31 | 32 | /*-------------- 33 | Comment 34 | ---------------*/ 35 | 36 | .ui.comments .comment { 37 | position: relative; 38 | background: none; 39 | margin: 0.5em 0em 0em; 40 | padding: 0.5em 0em 0em; 41 | border: none; 42 | border-top: none; 43 | line-height: 1.2; 44 | } 45 | .ui.comments .comment:first-child { 46 | margin-top: 0em; 47 | padding-top: 0em; 48 | } 49 | 50 | /*-------------------- 51 | Nested Comments 52 | ---------------------*/ 53 | 54 | .ui.comments .comment .comments { 55 | margin: 0em 0em 0.5em 0.5em; 56 | padding: 1em 0em 1em 1em; 57 | } 58 | .ui.comments .comment .comments:before { 59 | position: absolute; 60 | top: 0px; 61 | left: 0px; 62 | } 63 | .ui.comments .comment .comments .comment { 64 | border: none; 65 | border-top: none; 66 | background: none; 67 | } 68 | 69 | /*-------------- 70 | Avatar 71 | ---------------*/ 72 | 73 | .ui.comments .comment .avatar { 74 | display: block; 75 | width: 2.5em; 76 | height: auto; 77 | float: left; 78 | margin: 0.2em 0em 0em; 79 | } 80 | .ui.comments .comment img.avatar, 81 | .ui.comments .comment .avatar img { 82 | display: block; 83 | margin: 0em auto; 84 | width: 100%; 85 | height: 100%; 86 | border-radius: 0.25rem; 87 | } 88 | 89 | /*-------------- 90 | Content 91 | ---------------*/ 92 | 93 | .ui.comments .comment > .content { 94 | display: block; 95 | } 96 | 97 | /* If there is an avatar move content over */ 98 | .ui.comments .comment > .avatar ~ .content { 99 | margin-left: 3.5em; 100 | } 101 | 102 | /*-------------- 103 | Author 104 | ---------------*/ 105 | 106 | .ui.comments .comment .author { 107 | font-size: 1em; 108 | color: rgba(0, 0, 0, 0.87); 109 | font-weight: bold; 110 | } 111 | .ui.comments .comment a.author { 112 | cursor: pointer; 113 | } 114 | .ui.comments .comment a.author:hover { 115 | color: #1e70bf; 116 | } 117 | 118 | /*-------------- 119 | Metadata 120 | ---------------*/ 121 | 122 | .ui.comments .comment .metadata { 123 | display: inline-block; 124 | margin-left: 0.5em; 125 | color: rgba(0, 0, 0, 0.4); 126 | font-size: 0.875em; 127 | } 128 | .ui.comments .comment .metadata > * { 129 | display: inline-block; 130 | margin: 0em 0.5em 0em 0em; 131 | } 132 | .ui.comments .comment .metadata > :last-child { 133 | margin-right: 0em; 134 | } 135 | 136 | /*-------------------- 137 | Comment Text 138 | ---------------------*/ 139 | 140 | .ui.comments .comment .text { 141 | margin: 0.25em 0em 0.5em; 142 | font-size: 1em; 143 | word-wrap: break-word; 144 | color: rgba(0, 0, 0, 0.87); 145 | line-height: 1.3; 146 | } 147 | 148 | /*-------------------- 149 | User Actions 150 | ---------------------*/ 151 | 152 | .ui.comments .comment .actions { 153 | font-size: 0.875em; 154 | } 155 | .ui.comments .comment .actions a { 156 | cursor: pointer; 157 | display: inline-block; 158 | margin: 0em 0.75em 0em 0em; 159 | color: rgba(0, 0, 0, 0.4); 160 | } 161 | .ui.comments .comment .actions a:last-child { 162 | margin-right: 0em; 163 | } 164 | .ui.comments .comment .actions a.active, 165 | .ui.comments .comment .actions a:hover { 166 | color: rgba(0, 0, 0, 0.8); 167 | } 168 | 169 | /*-------------------- 170 | Reply Form 171 | ---------------------*/ 172 | 173 | .ui.comments > .reply.form { 174 | margin-top: 1em; 175 | } 176 | .ui.comments .comment .reply.form { 177 | width: 100%; 178 | margin-top: 1em; 179 | } 180 | .ui.comments .reply.form textarea { 181 | font-size: 1em; 182 | height: 12em; 183 | } 184 | 185 | 186 | /******************************* 187 | State 188 | *******************************/ 189 | 190 | .ui.collapsed.comments, 191 | .ui.comments .collapsed.comments, 192 | .ui.comments .collapsed.comment { 193 | display: none; 194 | } 195 | 196 | 197 | /******************************* 198 | Variations 199 | *******************************/ 200 | 201 | 202 | /*-------------------- 203 | Threaded 204 | ---------------------*/ 205 | 206 | .ui.threaded.comments .comment .comments { 207 | margin: -1.5em 0 -1em 1.25em; 208 | padding: 3em 0em 2em 2.25em; 209 | -webkit-box-shadow: -1px 0px 0px rgba(34, 36, 38, 0.15); 210 | box-shadow: -1px 0px 0px rgba(34, 36, 38, 0.15); 211 | } 212 | 213 | /*-------------------- 214 | Minimal 215 | ---------------------*/ 216 | 217 | .ui.minimal.comments .comment .actions { 218 | opacity: 0; 219 | position: absolute; 220 | top: 0px; 221 | right: 0px; 222 | left: auto; 223 | -webkit-transition: opacity 0.2s ease; 224 | transition: opacity 0.2s ease; 225 | -webkit-transition-delay: 0.1s; 226 | transition-delay: 0.1s; 227 | } 228 | .ui.minimal.comments .comment > .content:hover > .actions { 229 | opacity: 1; 230 | } 231 | 232 | /*------------------- 233 | Sizes 234 | --------------------*/ 235 | 236 | .ui.mini.comments { 237 | font-size: 0.78571429rem; 238 | } 239 | .ui.tiny.comments { 240 | font-size: 0.85714286rem; 241 | } 242 | .ui.small.comments { 243 | font-size: 0.92857143rem; 244 | } 245 | .ui.comments { 246 | font-size: 1rem; 247 | } 248 | .ui.large.comments { 249 | font-size: 1.14285714rem; 250 | } 251 | .ui.big.comments { 252 | font-size: 1.28571429rem; 253 | } 254 | .ui.huge.comments { 255 | font-size: 1.42857143rem; 256 | } 257 | .ui.massive.comments { 258 | font-size: 1.71428571rem; 259 | } 260 | 261 | 262 | /******************************* 263 | Theme Overrides 264 | *******************************/ 265 | 266 | 267 | 268 | /******************************* 269 | User Variable Overrides 270 | *******************************/ 271 | 272 | --------------------------------------------------------------------------------