diff --git a/myapp/__init__.py b/myapp/__init__.py index 1380439..3c38098 100644 --- a/myapp/__init__.py +++ b/myapp/__init__.py @@ -25,6 +25,16 @@ formatter = logging.Formatter(app.config['LONG_LOG_FORMAT']) handler.setFormatter(formatter) app.logger.addHandler(handler) + +@app.context_processor +def inject_data(): + result = {} + + result['STATIC'] = app.config['STATIC'] + result['ITEMS_ON_PAGE'] = app.config['ITEMS_ON_PAGE'] + + return result + from . import lib, models diff --git a/myapp/bin/api.py b/myapp/bin/api.py index 9b36a75..9efd091 100755 --- a/myapp/bin/api.py +++ b/myapp/bin/api.py @@ -22,7 +22,7 @@ def main(): parser.add_argument("--json-rpc", help="JSON-RPC") parser.add_argument("--methods", action='store_true') - parser.add_argument("--example", action='store_true') + parser.add_argument("--example") parser.add_argument("--verbose", action='store_true') parser.add_argument("--save") @@ -43,7 +43,8 @@ def main(): print('[{0}]'.format(', '.join(jsonrpc.methods))) if args.example: - print(jsonrpc.example) + result = jsonrpc.example(args.example) + print(json.dumps(result)) if __name__ == "__main__": diff --git a/myapp/mutations/__init__.py b/myapp/mutations/__init__.py new file mode 100644 index 0000000..18c55bb --- /dev/null +++ b/myapp/mutations/__init__.py @@ -0,0 +1,2 @@ +__author__ = 'RemiZOffAlex' +__email__ = 'remizoffalex@mail.ru' diff --git a/myapp/mutations/page.py b/myapp/mutations/page.py new file mode 100644 index 0000000..491e336 --- /dev/null +++ b/myapp/mutations/page.py @@ -0,0 +1,80 @@ +__author__ = 'RemiZOffAlex' +__email__ = 'remizoffalex@mail.ru' + +import logging + +from .. import lib, models + + +log = logging.getLogger(__name__) + + +def page_as_dict( + page: models.Page, + fields: list = ['id', 'title'] +): + """Статью как словарь (в JSON) + """ + def field_favorite(page): + # Избранное + assert lib.get_user(), 'favorite only authorized users' + result = False + favorite = models.db_session.query( + models.FavoritePage + ).filter( + models.FavoritePage.page_id == page.id, + models.FavoritePage.user_id == lib.get_user().id + ).first() + if favorite: + result = True + return result + + def field_tags(page): + # Теги + result = [] + for tagLink in page.tags: + newTag = tagLink.tag.as_dict() + result.append(newTag) + return result + + def field_user(page): + # Пользователь + return page.user.as_dict() + + def field_parents(page): + # Родители + result = [] + parent = page.parent + while parent: + result.append(parent.as_dict()) + parent = parent.parent + result.reverse() + return result + + def field_nodes(page): + # Дети + result = [] + for item in page.nodes: + result.append(page_as_dict(item)) + return result + + funcs = { + 'favorite': field_favorite, + 'tags': field_tags, + 'user': field_user, + 'parents': field_parents, + 'nodes': field_nodes + } + result = {} + + for column in page.__table__.columns: + if column.name in fields: + result[column.name] = getattr(page, column.name) + + for field in fields: + if field in funcs: + func = funcs[field] + result[field] = func(page) + + log.info(result) + return result diff --git a/myapp/ns_api/login.py b/myapp/ns_api/login.py index 36712a0..96c7b10 100644 --- a/myapp/ns_api/login.py +++ b/myapp/ns_api/login.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' import string @@ -10,7 +9,7 @@ from . import jsonrpc from .. import app, lib, models -@jsonrpc.method('login') +@jsonrpc.method('auth.login') def login(username: str, password: str) -> bool: user = models.db_session.query( models.User @@ -29,7 +28,7 @@ def login(username: str, password: str) -> bool: return True -@jsonrpc.method('login.register') +@jsonrpc.method('auth.register') def login_register(username: str, password: str) -> bool: """Регистрация """ diff --git a/myapp/ns_api/page.py b/myapp/ns_api/page.py index b279538..f3703b2 100644 --- a/myapp/ns_api/page.py +++ b/myapp/ns_api/page.py @@ -3,10 +3,14 @@ __email__ = 'remizoffalex@mail.ru' from . import jsonrpc, login_required from .. import app, lib, models +from ..mutations.page import page_as_dict @jsonrpc.method('page') -def page_id(id: int) -> dict: +def page_id( + id: int, + fields: list = ['id', 'title'] +) -> dict: """Статья """ page = models.db_session.query( @@ -17,11 +21,7 @@ def page_id(id: int) -> dict: if page is None: raise ValueError - result = page.as_dict() - result['user'] = page.user.as_dict() - result['tags'] = [] - for tagLink in page.tags: - result['tags'].append(tagLink.tag.as_dict()) + result = page_as_dict(page, fields) return result @@ -93,7 +93,8 @@ def page_update(id: int, title: str, text: str) -> dict: @jsonrpc.method('pages') def pages_list( page: int = 1, - order_by: dict = {'field': 'title', 'order': 'asc'} + order_by: dict = {'field': 'title', 'order': 'asc'}, + fields: list = ['id', 'title'], ) -> list: """Список статей """ @@ -120,11 +121,7 @@ def pages_list( result = [] for page in pages: - newRow = page.as_dict() - newRow['user'] = page.user.as_dict() - newRow['tags'] = [] - for tagLink in page.tags: - newRow['tags'].append(tagLink.tag.as_dict()) + newRow = page_as_dict(page, fields) result.append(newRow) return result diff --git a/myapp/ns_note/templates/notes.html b/myapp/ns_note/templates/notes.html index 7f1270b..a645f6d 100644 --- a/myapp/ns_note/templates/notes.html +++ b/myapp/ns_note/templates/notes.html @@ -11,8 +11,6 @@
-{% include 'inc/filter.html' %} - {% include 'inc/notes.html' %} diff --git a/myapp/ns_page/routes.py b/myapp/ns_page/routes.py index bc621e5..6e9400f 100644 --- a/myapp/ns_page/routes.py +++ b/myapp/ns_page/routes.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' from flask import abort diff --git a/myapp/ns_page/templates/guest/page.html b/myapp/ns_page/templates/guest/page.html index 438fb09..74492ef 100644 --- a/myapp/ns_page/templates/guest/page.html +++ b/myapp/ns_page/templates/guest/page.html @@ -1,4 +1,4 @@ -{% extends "skeleton.html" %} +{% extends "/public/skeleton.html" %} {% block content %} {% raw %} @@ -29,19 +29,9 @@ {% endblock %} {% block breadcrumb %} -{% raw %} - -{% endraw %} -{% endblock %} - -{% block script %} - + {% endblock %} diff --git a/myapp/ns_page/templates/guest/pages.html b/myapp/ns_page/templates/guest/pages.html index c6d3122..29eb6dc 100644 --- a/myapp/ns_page/templates/guest/pages.html +++ b/myapp/ns_page/templates/guest/pages.html @@ -4,8 +4,6 @@

Статьи


-{% include '/inc/filter.html' %} -
@@ -32,13 +30,6 @@ Object.assign(root.data, { raw_pages: [], pagination: {{ pagedata['pagination']|tojson|safe }}, }); -Object.assign(root.data.panels, { - order_by: { - visible: false, - field: 'title', - order: 'asc' - }, -}); Object.assign(root.methods, { filterApply: function() {}, filterPage: function(page) { diff --git a/myapp/ns_page/templates/user/pages.html b/myapp/ns_page/templates/user/pages.html index ed3539b..5a549ff 100644 --- a/myapp/ns_page/templates/user/pages.html +++ b/myapp/ns_page/templates/user/pages.html @@ -33,8 +33,6 @@
-{% include 'inc/filter.html' %} -
diff --git a/myapp/ns_page/views_guest.py b/myapp/ns_page/views_guest.py index bcda278..6e3814a 100644 --- a/myapp/ns_page/views_guest.py +++ b/myapp/ns_page/views_guest.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' from flask import abort, render_template diff --git a/myapp/ns_page/views_user.py b/myapp/ns_page/views_user.py index 80b2e50..ae8efaa 100644 --- a/myapp/ns_page/views_user.py +++ b/myapp/ns_page/views_user.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' from flask import abort, render_template diff --git a/myapp/ns_tag/routes.py b/myapp/ns_tag/routes.py index b3d9ea4..c4a1435 100644 --- a/myapp/ns_tag/routes.py +++ b/myapp/ns_tag/routes.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' from flask import abort diff --git a/myapp/ns_user/routes.py b/myapp/ns_user/routes.py index 3bd76e4..05280fd 100644 --- a/myapp/ns_user/routes.py +++ b/myapp/ns_user/routes.py @@ -1,6 +1,5 @@ __author__ = 'RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -__url__ = 'https://remizoffalex.ru/' from flask import abort diff --git a/myapp/ns_user/templates/guest/users.html b/myapp/ns_user/templates/guest/users.html index ffc0abc..e7b5968 100644 --- a/myapp/ns_user/templates/guest/users.html +++ b/myapp/ns_user/templates/guest/users.html @@ -4,8 +4,6 @@

Список пользователей


-{% include '/inc/filter.html' %} - {% include '/inc/users.html' %} diff --git a/myapp/ns_user/templates/users.html b/myapp/ns_user/templates/users.html index 213a1c7..6e0808b 100644 --- a/myapp/ns_user/templates/users.html +++ b/myapp/ns_user/templates/users.html @@ -4,8 +4,6 @@

Список пользователей


-{% include '/inc/filter.html' %} - {% include '/inc/users.html' %} diff --git a/myapp/static/ckeditor/CHANGES.md b/myapp/static/ckeditor/CHANGES.md deleted file mode 100644 index 0803614..0000000 --- a/myapp/static/ckeditor/CHANGES.md +++ /dev/null @@ -1,1358 +0,0 @@ -CKEditor 4 Changelog -==================== - -## CKEditor 4.7.3 - -New Features: - -* [#568](https://github.com/ckeditor/ckeditor-dev/issues/568): Added possibility to adjust nested editables' filters using the [`CKEDITOR.filter.disallowedContent`](https://docs.ckeditor.com/#!/api/CKEDITOR.filter-property-disallowedContent) property. - -Fixed Issues: - -* [#554](https://github.com/ckeditor/ckeditor-dev/issues/554): Fixed: [`change`](https://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-change) event not fired when typing the first character after pasting into the editor. Thanks to [Daniel Miller](https://github.com/millerdev)! -* [#566](https://github.com/ckeditor/ckeditor-dev/issues/566): Fixed: The CSS `border` shorthand property with zero width (`border: 0px solid #000;`) causes the table to have the border attribute set to 1. -* [#779](https://github.com/ckeditor/ckeditor-dev/issues/779): Fixed: The [Remove Format](https://ckeditor.com/addon/removeformat) plugin removes elements with language definition inserted by the [Language](https://ckeditor.com/addon/language) plugin. -* [#423](https://github.com/ckeditor/ckeditor-dev/issues/423): Fixed: The [Paste from Word](https://ckeditor.com/addon/pastefromword) plugin pastes paragraphs into the editor even if [`CKEDITOR.config.enterMode`](https://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enterMode) is set to `CKEDITOR.ENTER_BR`. -* [#719](https://github.com/ckeditor/ckeditor-dev/issues/719): Fixed: Image inserted using the [Enhanced Image](https://ckeditor.com/addon/image2) plugin can be resized when the editor is in [read-only mode](https://docs.ckeditor.com/#!/guide/dev_readonly). -* [#577](https://github.com/ckeditor/ckeditor-dev/issues/577): Fixed: The "Delete Columns" command provided by the [Table Tools](https://ckeditor.com/addon/tabletools) plugin throws an error when trying to delete columns. -* [#867](https://github.com/ckeditor/ckeditor-dev/issues/867): Fixed: Typing into a selected table throws an error. -* [#817](https://github.com/ckeditor/ckeditor-dev/issues/817): Fixed: The [Save](https://ckeditor.com/addon/save) plugin does not work in [Source Mode](https://ckeditor.com/addon/sourcearea). - -Other Changes: - -* Updated the [WebSpellChecker](http://ckeditor.com/addon/wsc) plugin: - * [#40](https://github.com/WebSpellChecker/ckeditor-plugin-wsc/issues/40): Fixed: IE10 throws an error when spell checking is started. -* [#800](https://github.com/ckeditor/ckeditor-dev/issues/800): Added the [`CKEDITOR.dom.selection.isCollapsed`](https://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-isCollapsed) method which is a simpler way to check if the selection is collapsed. -* [#830](https://github.com/ckeditor/ckeditor-dev/issues/830): Added an option to define which dialog tab should be shown by default when creating [`CKEDITOR.dialogCommand`](https://docs.ckeditor.com/#!/api/CKEDITOR.dialogCommand). - -## CKEditor 4.7.2 - -New Features: - -* [#455](https://github.com/ckeditor/ckeditor-dev/issues/455): Added [Advanced Content Filter](https://docs.ckeditor.com/#!/guide/dev_acf) integration with the [Justify](http://ckeditor.com/addon/justify) plugin. - -Fixed Issues: - -* [#663](https://github.com/ckeditor/ckeditor-dev/issues/663): [Chrome] Fixed: Clicking the scrollbar throws an `Uncaught TypeError: element.is is not a function` error. -* [#694](https://github.com/ckeditor/ckeditor-dev/pull/694): Refactoring in the [Table Selection](http://ckeditor.com/addon/tableselection) plugin: - * [#520](https://github.com/ckeditor/ckeditor-dev/issues/520): Fixed: Widgets cannot be properly pasted into a table cell. - * [#460](https://github.com/ckeditor/ckeditor-dev/issues/460): Fixed: Editor gone after pasting into an editor within a table. -* [#579](https://github.com/ckeditor/ckeditor-dev/issues/579): Fixed: Internal `cke_table-faked-selection-table` class is visible in the Stylesheet Classes field of the [Table Properties](http://ckeditor.com/addon/table) dialog. -* [#545](https://github.com/ckeditor/ckeditor-dev/issues/545): [Edge] Fixed: Error thrown when pressing the [Select All](https://ckeditor.com/addon/selectall) button in [Source Mode](http://ckeditor.com/addon/sourcearea). -* [#582](https://github.com/ckeditor/ckeditor-dev/issues/582): Fixed: Double slash in the path to stylesheet needed by the [Table Selection](http://ckeditor.com/addon/tableselection) plugin. Thanks to [Marius Dumitru Florea](https://github.com/mflorea)! -* [#491](https://github.com/ckeditor/ckeditor-dev/issues/491): Fixed: Unnecessary dependency on the [Editor Toolbar](http://ckeditor.com/addon/toolbar) plugin inside the [Notification](http://ckeditor.com/addon/notification) plugin. -* [#646](https://github.com/ckeditor/ckeditor-dev/issues/646): Fixed: Error thrown into the browser console after opening the [Styles Combo](http://ckeditor.com/addon/stylescombo) plugin menu in the editor without any selection. -* [#501](https://github.com/ckeditor/ckeditor-dev/issues/501): Fixed: Double click does not open the dialog for modifying anchors inserted via the [Link](http://ckeditor.com/addon/link) plugin. -* [#9780](https://dev.ckeditor.com/ticket/9780): [IE8-9] Fixed: Clicking inside an empty [read-only](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-property-readOnly) editor throws an error. -* [#16820](https://dev.ckeditor.com/ticket/16820): [IE10] Fixed: Clicking below a single horizontal rule throws an error. -* [#426](https://github.com/ckeditor/ckeditor-dev/issues/426): Fixed: The [`range.cloneContents`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-cloneContents) method selects the whole element when the selection starts at the beginning of that element. -* [#644](https://github.com/ckeditor/ckeditor-dev/issues/644): Fixed: The [`range.extractContents`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-extractContents) method returns an incorrect result when multiple nodes are selected. -* [#684](https://github.com/ckeditor/ckeditor-dev/issues/684): Fixed: The [`elementPath.contains`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.elementPath-method-contains) method incorrectly excludes the last element instead of root when the `fromTop` parameter is set to `true`. - -Other Changes: - -* Updated the [SCAYT](http://ckeditor.com/addon/scayt) (Spell Check As You Type) plugin: - * [#148](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/148): Fixed: SCAYT leaves underlined word after the CKEditor Replace dialog corrects it. -* [#751](https://github.com/ckeditor/ckeditor-dev/issues/751): Added the [`CKEDITOR.dom.nodeList.toArray`](https://docs.ckeditor.com/#!/api/CKEDITOR.dom.nodeList-method-toArray) method which returns an array representation of a [node list](https://docs.ckeditor.com/#!/api/CKEDITOR.dom.nodeList). - -## CKEditor 4.7.1 - -New Features: - -* Added a new Mexican Spanish localization. Thanks to [David Alexandro Rodriguez](https://www.transifex.com/user/profile/darsco16/)! -* [#413](https://github.com/ckeditor/ckeditor-dev/issues/413): Added Paste as Plain Text keyboard shortcut to the [Accessibility Help](http://ckeditor.com/addon/a11yhelp) instructions. - -Fixed Issues: - -* [#515](https://github.com/ckeditor/ckeditor-dev/issues/515): [Chrome] Fixed: Mouse actions on CKEditor scrollbar throw an exception when the [Table Selection](http://ckeditor.com/addon/tableselection) plugin is loaded. -* [#493](https://github.com/ckeditor/ckeditor-dev/issues/493): Fixed: Selection started from a nested table causes an error in the browser while scrolling down. -* [#415](https://github.com/ckeditor/ckeditor-dev/issues/415): [Firefox] Fixed: Enter key breaks the table structure when pressed in a table selection. -* [#457](https://github.com/ckeditor/ckeditor-dev/issues/457): Fixed: Error thrown when deleting content from the editor with no selection. -* [#478](https://github.com/ckeditor/ckeditor-dev/issues/478): [Chrome] Fixed: Error thrown by the [Enter Key](http://ckeditor.com/addon/enterkey) plugin when pressing Enter with no selection. -* [#424](https://github.com/ckeditor/ckeditor-dev/issues/424): Fixed: Error thrown by [Tab Key Handling](http://ckeditor.com/addon/tab) and [Indent List](http://ckeditor.com/addon/indentlist) plugins when pressing Tab with no selection in inline editor. -* [#476](https://github.com/ckeditor/ckeditor-dev/issues/476): Fixed: Anchors inserted with the [Link](http://ckeditor.com/addon/link) plugin on collapsed selection cannot be edited. -* [#417](https://github.com/ckeditor/ckeditor-dev/issues/417): Fixed: The [Table Resize](http://ckeditor.com/addon/tableresize) plugin throws an error when used with a table with only header or footer rows. -* [#523](https://github.com/ckeditor/ckeditor-dev/issues/523): Fixed: The [`editor.getCommandKeystroke`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getCommandKeystroke) method does not obtain the correct keystroke. -* [#534](https://github.com/ckeditor/ckeditor-dev/issues/534): [IE] Fixed: [Paste from Word](http://ckeditor.com/addon/pastefromword) does not work in Quirks Mode. -* [#450](https://github.com/ckeditor/ckeditor-dev/issues/450): Fixed: [`CKEDITOR.filter`](http://docs.ckeditor.com/#!/api/CKEDITOR.filter) incorrectly transforms the `margin` CSS property. - -## CKEditor 4.7 - -**Important Notes:** - -* [#13793](http://dev.ckeditor.com/ticket/13793): The [`embed_provider`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-embed_provider) configuration option for the [Media Embed](http://ckeditor.com/addon/embed) and [Semantic Media Embed](http://ckeditor.com/addon/embedsemantic) plugins is no longer preset by default. -* The [UI Color](http://ckeditor.com/addon/uicolor) plugin now uses a custom color picker instead of the `YUI 2.7.0` library which has some known vulnerabilities (it's a security precaution, there was no security issue in CKEditor due to the way it was used). - -New Features: - -* [#16755](http://dev.ckeditor.com/ticket/16755): Added the [Table Selection](http://ckeditor.com/addon/tableselection) plugin that lets you select and manipulate an arbitrary rectangular table fragment (a few cells, a row or a column). -* [#16961](http://dev.ckeditor.com/ticket/16961): Added support for pasting from Microsoft Excel. -* [#13381](http://dev.ckeditor.com/ticket/13381): Dynamic code evaluation call in [`CKEDITOR.template`](http://docs.ckeditor.com/#!/api/CKEDITOR.template) removed. CKEditor can now be used without the `unsafe-eval` Content Security Policy. Thanks to [Caridy Patiño](http://caridy.name)! -* [#16971](http://dev.ckeditor.com/ticket/16971): Added support for color in the `background` property containing also other styles for table cells in the [Table Tools](http://ckeditor.com/addon/tabletools) plugin. -* [#16847](http://dev.ckeditor.com/ticket/16847): Added support for parsing and inlining any formatting created using the Microsoft Word style system to the [Paste from Word](http://ckeditor.com/addon/pastefromword) plugin. -* [#16818](http://dev.ckeditor.com/ticket/16818): Added table cell height parsing in the [Paste from Word](http://ckeditor.com/addon/pastefromword) plugin. -* [#16850](http://dev.ckeditor.com/ticket/16850): Added a new [`config.enableContextMenu`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-enableContextMenu) configuration option for enabling and disabling the [context menu](http://ckeditor.com/addon/contextmenu). -* [#16937](http://dev.ckeditor.com/ticket/16937): The `command` parameter in [CKEDITOR.editor.getCommandKeystroke](http://docs.ckeditor.dev/#!/api/CKEDITOR.editor-method-getCommandKeystroke) now also accepts a command name as an argument. -* [#17010](http://dev.ckeditor.com/ticket/17010): The [`CKEDITOR.dom.range.shrink`](http://docs.ckeditor.com/#!/api/CKEDITOR.dom.range-method-shrink) method now allows for skipping bogus `
` elements. - -Fixed Issues: - -* [#16935](http://dev.ckeditor.com/ticket/16935): [Chrome] Fixed: Blurring the editor in [Source Mode](http://ckeditor.com/addon/sourcearea) throws an error. -* [#16825](http://dev.ckeditor.com/ticket/16825): [Chrome] Fixed: Error thrown when destroying a focused inline editor. -* [#16857](http://dev.ckeditor.com/ticket/16857): Fixed: Ctrl+Shift+V blocked by [Copy Formatting](http://ckeditor.com/addon/copyformatting). -* [#16845](https://dev.ckeditor.com/ticket/16845): [IE] Fixed: Cursor jumps to the top of the scrolled editor after focusing it when the [Copy Formatting](http://ckeditor.com/addon/copyformatting) plugin is enabled. -* [#16786](http://dev.ckeditor.com/ticket/16786): Fixed: Added missing translations for the [Copy Formatting](http://ckeditor.com/addon/copyformatting) plugin. -* [#14714](http://dev.ckeditor.com/ticket/14714): [WebKit/Blink] Fixed: Exception thrown on refocusing a blurred inline editor. -* [#16913](http://dev.ckeditor.com/ticket/16913): [Firefox, IE] Fixed: [Paste as Plain Text](http://ckeditor.com/addon/pastetext) keystroke does not work. -* [#16968](http://dev.ckeditor.com/ticket/16968): Fixed: [Safari] [Paste as Plain Text](http://ckeditor.com/addon/pastetext) is not handled by the editor. -* [#16912](http://dev.ckeditor.com/ticket/16912): Fixed: Exception thrown when a single image is pasted using [Paste from Word](http://ckeditor.com/addon/pastefromword). -* [#16821](http://dev.ckeditor.com/ticket/16821): Fixed: Extraneous `` elements with `height` style stacked when [pasting from Word](http://ckeditor.com/addon/pastefromword). -* [#16866](http://dev.ckeditor.com/ticket/16866): [IE, Edge] Fixed: Whitespaces not preserved when [pasting from Word](http://ckeditor.com/addon/pastefromword). -* [#16860](http://dev.ckeditor.com/ticket/16860): Fixed: Paragraphs which only look like lists incorrectly transformed into them when [pasting from Word](http://ckeditor.com/addon/pastefromword). -* [#16817](http://dev.ckeditor.com/ticket/16817): Fixed: When [pasting from Word](http://ckeditor.com/addon/pastefromword), paragraphs are transformed into lists with some corrupted data. -* [#16833](http://dev.ckeditor.com/ticket/16833): [IE11] Fixed: Malformed list with headers [pasted from Word](http://ckeditor.com/addon/pastefromword). -* [#16826](http://dev.ckeditor.com/ticket/16826): [IE] Fixed: Superfluous paragraphs within lists [pasted from Word](http://ckeditor.com/addon/pastefromword). -* [#12465](http://dev.ckeditor.com/ticket/12465): Fixed: Cannot change the state of checkboxes or radio buttons if the properties dialog was invoked with a double-click. -* [#13062](http://dev.ckeditor.com/ticket/13062): Fixed: Impossible to unlink when the caret is at the edge of the link. -* [#13585](http://dev.ckeditor.com/ticket/13585): Fixed: Error when wrapping two adjacent `
` elements with a `
`. -* [#16811](http://dev.ckeditor.com/ticket/16811): Fixed: Table alignment is not preserved by the [Paste from Word](http://ckeditor.com/addon/pastefromword) plugin. -* [#16810](http://dev.ckeditor.com/ticket/16810): Fixed: Vertical align in tables is not supported by the [Paste from Word](http://ckeditor.com/addon/pastefromword) plugin. -* [#11956](http://dev.ckeditor.com/ticket/11956): [Blink, IE] Fixed: [Link](http://ckeditor.com/addon/link) dialog does not open on a double click on the second word of the link with a background color or other styles. -* [#10472](http://dev.ckeditor.com/ticket/10472): Fixed: Unable to use [Table Resize](http://ckeditor.com/addon/tableresize) on table header and footer. -* [#14762](http://dev.ckeditor.com/ticket/14762): Fixed: Hovering over an empty table (without rows or cells) throws an error when the [Table Resize](http://ckeditor.com/addon/tableresize) plugin is active. -* [#16777](https://dev.ckeditor.com/ticket/16777): [Edge] Fixed: The [Clipboard](http://ckeditor.com/addon/clipboard) plugin does not allow to drop widgets into the editor. -* [#14894](https://dev.ckeditor.com/ticket/14894): [Chrome] Fixed: The editor scrolls to the top after focusing or when a dialog is opened. -* [#14769](https://dev.ckeditor.com/ticket/14769): Fixed: URLs with '-' in host are not detected by the [Auto Link](http://ckeditor.com/addon/autolink) plugin. -* [#16804](https://dev.ckeditor.com/ticket/16804): Fixed: Focus is not on the first menu item when the user opens a context menu or a drop-down list from the editor toolbar. -* [#14407](https://dev.ckeditor.com/ticket/14407): [IE] Fixed: Non-editable widgets can be edited. -* [#16927](https://dev.ckeditor.com/ticket/16927): Fixed: An error thrown if a bundle containing the [Color Button](http://ckeditor.com/addon/colorbutton) plugin is run in ES5 strict mode. Thanks to [Igor Rubinovich](https://github.com/IgorRubinovich)! -* [#16920](http://dev.ckeditor.com/ticket/16920): Fixed: Several plugins not using the [Dialog](http://ckeditor.com/addon/dialog) plugin as a direct dependency. -* [PR#336](https://github.com/ckeditor/ckeditor-dev/pull/336): Fixed: Typo in [`CKEDITOR.getCss`](http://docs.ckeditor.com/#!/api/CKEDITOR-method-getCss) API documentation. Thanks to [knusperpixel](https://github.com/knusperpixel)! -* [#17027](http://dev.ckeditor.com/ticket/17027): Fixed: Command event data should be initialized as an empty object. -* Fixed the behavior of HTML parser when parsing `src`/`srcdoc` attributes of the `"}(n):"application/x-shockwave-flash"===n.source1mime?function(e){var t='';return e.poster&&(t+=''),t+=""}(n):-1!==n.source1mime.indexOf("audio")?function(e,t){return t?t(e):'"}(n,o):"script"===n.type?function(e){return' + + + {{ pagedata['title'] }} diff --git a/myapp/templates/inc/editor.js b/myapp/templates/inc/editor.js deleted file mode 100644 index 2684a25..0000000 --- a/myapp/templates/inc/editor.js +++ /dev/null @@ -1,80 +0,0 @@ -{# -Подгрузить скрипт - -{% import 'inc/editor.js' as editor %} -{{ editor.plugin('tinymce') }} - -Получить данные - -{{ editor.getValue('"text"', 'vm.note.text', type='tinymce') }} - -{{ editor.getValue('"field" + field.id', 'field.cell.value', type='tinymce') }} - -Получить данные - -{{ editor.setValue('"text"', 'vm.note.text', type='tinymce') }} - -{{ editor.setValue('"field" + field.id', 'field.cell.value', type='tinymce') }} - -Инициализировать редактор - -{{ editor.tinymce('"text"') }} - -{{ editor.tinymce('"field" + field.id') }} - -#} - -{% macro plugin(type="tinymce") -%} -{% if type=="tinymce" %} - -{% elif type=="ckeditor" %} - -{% endif %} -{%- endmacro %} - -{% macro ckeditor(name) -%} -CKEDITOR.replace( {{ name }}, { - customConfig: '/static/js/ckeditor-conf.js' -} ); -{%- endmacro %} - -{% macro tinymce(name) -%} -tinymce.init({ - selector: '#' + {{ name }}, - height: 400, - language: 'ru', - plugins: 'code importcss searchreplace autolink save directionality visualblocks visualchars fullscreen image link media table charmap hr pagebreak nonbreaking anchor toc advlist lists wordcount imagetools textpattern noneditable help charmap quickbars', - toolbar: 'code | undo redo | bold italic underline strikethrough removeformat | formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | pagebreak | fullscreen | link image anchor charmap', - - formats: { - img: { selector: 'img', classes: 'img-thumbnail', styles: {} }, - table: { selector: 'table', classes: 'table', styles: {} }, - }, - style_formats: [ - { title: 'Картинка', format: 'img' }, - { title: 'Таблица', format: 'table' }, - ] -}); -{%- endmacro %} - -{% macro getValue(name, param, type="tinymce") -%} -{% if type=="tinymce" %} -let value = tinymce.get({{ name }}).getContent(); -if (value != {{ param }}) { - {{ param }} = value; -} -{% elif type=="ckeditor" %} -var value = CKEDITOR.instances[{{ name }}].getData(); -if (value != {{ param }}) { - {{ param }} = value; -} -{% endif %} -{%- endmacro %} - -{% macro setValue(name, param, type="tinymce") -%} -{% if type=="tinymce" %} -tinymce.get({{ name }}).setContent({{ param }}); -{% elif type=="ckeditor" %} -CKEDITOR.instances[{{ name }}].setData({{ param }}); -{% endif %} -{%- endmacro %} diff --git a/myapp/templates/inc/filter.html b/myapp/templates/inc/filter.html deleted file mode 100644 index 394da66..0000000 --- a/myapp/templates/inc/filter.html +++ /dev/null @@ -1,31 +0,0 @@ - -
-
-
-
-
- - - -
-
-
-
-
- - - diff --git a/myapp/templates/inc/pages.html b/myapp/templates/inc/pages.html index 7fda49f..ffdc0c3 100644 --- a/myapp/templates/inc/pages.html +++ b/myapp/templates/inc/pages.html @@ -1,24 +1,14 @@ -{% raw %} -
-
-{{ page.title }} + +{% for page in pagedata['pages'] %} + + + +{% endfor %} +
+{{ page.title }} -
-
- - {{ tag.name }}  - -
-
+{% for tagLink in page.tags %} +{{ tagLink.tag.name }} +{% endfor %} -
-
- {{ page.user.name }}  -Создано: {{ page.created }}  -Обновлено: {{ page.updated }} -
-
- - - -{% endraw %} +
diff --git a/myapp/templates/index.html b/myapp/templates/index.html index 501c62f..615960b 100644 --- a/myapp/templates/index.html +++ b/myapp/templates/index.html @@ -1,12 +1,8 @@ {% extends "skeleton.html" %} {% block content %} -
-
-

{{ pagedata['info'] }}

+

{{ pagedata['info'] }}


Самурай без меча подобен самураю с мечом, но только без меча, однако как-будто с мечом, которого у него нет, но и без него он как с ним...

-
-
{% endblock %} diff --git a/myapp/templates/lib.js b/myapp/templates/lib.js new file mode 100644 index 0000000..5c91cb4 --- /dev/null +++ b/myapp/templates/lib.js @@ -0,0 +1,10 @@ +function arrayRemove(arr, value) { + /* Удаление элемента из списка */ + return arr.filter(function(ele){ + return ele.id != value.id; + }); +}; +function panel_show(panel) { + /* Показать/скрыть панель */ + panel.visible = !panel.visible; +}; diff --git a/myapp/templates/public/app.js b/myapp/templates/public/app.js new file mode 100644 index 0000000..bff2e0a --- /dev/null +++ b/myapp/templates/public/app.js @@ -0,0 +1,15 @@ +{% include '/public/settings.js' %} + +//let vr = document.body; +let vroot = document.getElementById("app"); +let routes = {}; + +{% include '/lib.js' %} +{% include '/public/layout.js' %} + +{% include '/components/inc.j2' %} + +{% include '/public/components/inc.j2' %} +{% include '/public/domains/inc.j2' %} + +{% include '/routes.js' %} diff --git a/myapp/templates/public/components/footer.js b/myapp/templates/public/components/footer.js new file mode 100644 index 0000000..a52c6d2 --- /dev/null +++ b/myapp/templates/public/components/footer.js @@ -0,0 +1,11 @@ +let Footer = { + view: function() { + return {tag: '<', children: `
+
+
+ © RemiZOffAlex +
+
+
`} + } +}; diff --git a/myapp/templates/public/domains/auth/inc.j2 b/myapp/templates/public/domains/auth/inc.j2 new file mode 100644 index 0000000..e92aabb --- /dev/null +++ b/myapp/templates/public/domains/auth/inc.j2 @@ -0,0 +1,10 @@ +{% include '/public/domains/auth/login.js' %} +{% include '/public/domains/auth/register.js' %} + +Object.assign( + routes, + { + "/login": layout_decorator(Login), + "/register": layout_decorator(Register), + } +); diff --git a/myapp/templates/public/domains/auth/login.js b/myapp/templates/public/domains/auth/login.js new file mode 100644 index 0000000..eff6841 --- /dev/null +++ b/myapp/templates/public/domains/auth/login.js @@ -0,0 +1,70 @@ +function Login() { + let data = { + username: '', + password: '' + }; + function login() { + if (data.username.length==0 || data.password.length==0) { + return; + } + m.request({ + url: '/api', + method: "POST", + body: { + "jsonrpc": "2.0", + "method": 'auth.login', + "params": { + "username": data.username, + "password": data.password + }, + "id": 1 + } + }).then( + function(response) { + if ('result' in response) { + window.location.href = '/'; + } else if ('error' in response) { + data.error = response['error']; + } + } + ); + }; + function form_submit(e) { + e.preventDefault(); + login(); + }; + return { + data: data, + view: function(vnode) { + let result = []; + result.push( + m('div', {class: 'row justify-content-center my-3'}, + m('div', {class: 'col-md-6'}, [ + m('h3', [ + {tag: '<', children: 'Забыл пароль'}, + 'Вход', + {tag: '<', children: '
'}, + ]), + m('form', {onsubmit: form_submit}, [ + m('div', {class: "input-group mb-3"}, [ + {tag: '<', children: ''}, + m('input', {class: 'form-control', placeholder: 'Логин', type: 'text', oninput: function (e) {data.username = e.target.value}, value: data.username}), + ]), + m('div', {class: "input-group mb-3"}, [ + {tag: '<', children: ''}, + m('input', {class: 'form-control', placeholder: 'Пароль', type: 'password', oninput: function (e) {data.password = e.target.value}, value: data.password}), + ]), + m('div', {class: 'row'}, + m('div', {class: "col py-2"}, [ + m(m.route.Link, {class: 'btn btn-outline-secondary', href: '/register'}, 'Регистрация'), + m('button', {class: 'btn btn-outline-success float-end', type: 'submit'}, 'Войти') + ]), + ), + ]) + ]) + ) + ) + return result; + } + }; +}; diff --git a/myapp/templates/public/domains/page/pages.js b/myapp/templates/public/domains/page/pages.js new file mode 100644 index 0000000..d72e85a --- /dev/null +++ b/myapp/templates/public/domains/page/pages.js @@ -0,0 +1,180 @@ +function Pages() { + let data = { + filter: PanelFilter(), + order_by: PanelOrderBy({ + field: 'title', + fields: [ + {value: 'id', text: 'ID'}, + {value: 'title', text: 'заголовку'}, + {value: 'created', text: 'дате создания'}, + {value: 'updated', text: 'дате обновления'} + ], + clickHandler: pages_get, + order: 'asc', + }), + raw_pages: [], + get pages() { + /* Отфильтрованный список */ + let value = data.filter.data.value; + if ( value.length<1 ) { + return data.raw_pages; + } + if (data.filter.data.isregex) { + try { + let regex = new RegExp(value, 'ig'); + } catch (e) { + console.log(e); + return data.raw_pages; + } + } + let result = data.raw_pages.filter(page_filter); + return result; + }, + pagination: Pagination({ + clickHandler: pages_get, + prefix_url: '/pages' + }), + }; + function page_filter(page) { + /* Фильтр статей */ + let value = data.filter.data.value; + if ( value.length<1 ) { + return true; + } + let isTitle = null; + if ( data.filter.data.isregex) { + let regex = new RegExp(value, 'ig'); + isTitle = regex.test(page.title.toLowerCase()); + } else { + isTitle = page.title.toLowerCase().includes(value.toLowerCase()); + } + if ( isTitle ) { + return true; + } + return false; + }; + function breadcrumbs_render() { + let result = m('ul', {class: 'breadcrumb mt-3'}, [ + m('li', {class: 'breadcrumb-item'}, m(m.route.Link, {href: '/'}, m('i', {class: 'fa fa-home'}))), + m('li', {class: 'breadcrumb-item active'}, 'Список статей'), + ]); + return result; + }; + function pages_get() { + let order_by = data.order_by.data; + let pagination = data.pagination.data; + m.request({ + url: '/api', + method: "POST", + body: [ + { + "jsonrpc": "2.0", + "method": 'pages', + "params": { + "page": pagination.page, + "order_by": { + "field": order_by.field, + 'order': order_by.order + }, + "fields": ["id", "title", "tags"] + }, + "id": 1 + }, + { + "jsonrpc": "2.0", + "method": 'pages.count', + "id": 1 + } + ] + + }).then( + function(response) { + if ('result' in response[0]) { + data.raw_pages = response[0]['result']; + } + if ('result' in response[1]) { + data.pagination.size = response[1]['result']; + } + } + ); + }; + function page_render(page, pageIdx) { + let odd = ''; + if (pageIdx % 2) { + odd = ' bg-light' + }; + return m('div', {class: 'row'}, + m('div', {class: `col py-2 ${odd}`}, [ + m(m.route.Link, {href: `/page/${page.id}`}, m.trust(page.title)), + m('div', {class: 'row'}, + ), + ]) + ); + }; + function pages_render() { + return data.pages.map(page_render); + }; + return { + oninit: function(vnode) { + let pagination = data.pagination.data; + if (vnode.attrs.page!==undefined) { + pagination.page = Number(vnode.attrs.page); + }; + document.title = `Список статей - ${SETTINGS.TITLE}`; + pages_get(); + }, + view: function(vnode) { + let result = []; + result.push( + breadcrumbs_render(), + m('div', {class: 'row'}, + m('div', {class: 'col h1 py-1'}, [ + m('div', {class: "btn-group btn-group-lg me-2"}, [ + m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.filter.data) }}, + m('i', {class: "fa fa-filter"}) + ), + m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.order_by.data) }}, + m('i', {class: "fa fa-sort-alpha-asc"}) + ) + ]), + 'Статьи', + ]) + ), + m('hr'), + ); + result.push(m(data.filter)); + result.push(m(data.order_by)); + result.push(m(data.pagination)); + if (data.pages.length>0) { + result.push(m(ComponentPages, {pages: data.pages})); + result.push(m(data.pagination)); + }; + result.push(breadcrumbs_render()); + return result + } + } +}; +/* +
+
+{ page.title } + +
+
+ + { tag.name }  + +
+
+ +
+
+ { page.user.name }  +Создано: { page.created }  +Обновлено: { page.updated } +
+
+ +
+
+*/ diff --git a/myapp/templates/public/layout.js b/myapp/templates/public/layout.js new file mode 100644 index 0000000..405ef9c --- /dev/null +++ b/myapp/templates/public/layout.js @@ -0,0 +1,20 @@ +function layout_decorator(controller) { + return { + render: function(vnode) { + return m(Layout, m(controller, vnode.attrs)) + } + } +}; +function Layout() { + return { + view: function(vnode) { + let result = [ + m(MenuGeneral), + m("section", vnode.children), + m(Footer), + m(Backtotop), + ]; + return result; + } + } +}; diff --git a/myapp/templates/navbar.html b/myapp/templates/public/navbar.html similarity index 100% rename from myapp/templates/navbar.html rename to myapp/templates/public/navbar.html diff --git a/myapp/templates/public/settings.js b/myapp/templates/public/settings.js new file mode 100644 index 0000000..e39dca2 --- /dev/null +++ b/myapp/templates/public/settings.js @@ -0,0 +1,4 @@ +const SETTINGS = { + ITEMS_ON_PAGE: {{ ITEMS_ON_PAGE }}, + TITLE: 'Моя панель', +} diff --git a/myapp/templates/public/skeleton.html b/myapp/templates/public/skeleton.html new file mode 100644 index 0000000..28f8c93 --- /dev/null +++ b/myapp/templates/public/skeleton.html @@ -0,0 +1,22 @@ + + + {% include 'header.html' %} + + +
+{% include '/public/navbar.html' %} + +{% block content %} +{% endblock content %} + +{% block breadcrumb %} +{% endblock %} + +{% include 'footer.html' %} +
+ +{% block script %}{% endblock %} + + + + diff --git a/myapp/templates/routes.js b/myapp/templates/routes.js new file mode 100644 index 0000000..a69027a --- /dev/null +++ b/myapp/templates/routes.js @@ -0,0 +1,14 @@ +m.route.prefix = ''; +function layout_decorator(controller) { + return { + render: function(vnode) { + return m(Layout, m(controller, vnode.attrs)) + } + } +}; + +m.route( + vroot, + "/", + routes +); diff --git a/myapp/templates/skeleton.html b/myapp/templates/skeleton.html index 29636b9..efa4b17 100644 --- a/myapp/templates/skeleton.html +++ b/myapp/templates/skeleton.html @@ -4,7 +4,7 @@
-{% include 'navbar.html' %} +{% include '/public/navbar.html' %} {% block content %} {% endblock content %} diff --git a/myapp/views.py b/myapp/views.py index f98ec7d..a21c9ab 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -2,9 +2,22 @@ __author__ = 'RemiZOffAlex' __copyright__ = '(c) RemiZOffAlex' __email__ = 'remizoffalex@mail.ru' -from myapp import app from flask import render_template, Response +from myapp import app, lib + + +@app.route('/app.js') +def app_js(): + """Фильтр + """ + pagedata = {} + if lib.get_user(): + body = render_template('/private/app.js', pagedata=pagedata) + else: + body = render_template('/public/app.js', pagedata=pagedata) + return Response(body, mimetype='application/javascript') + @app.route('/') def index():