diff --git a/HISTORY.rst b/HISTORY.rst index 53fb58576c..3282232228 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -21,8 +21,16 @@ document (document stub that has no document version). - Add support for client side caching of document page images. The time the images are cached is controlled by the new setting - DOCUMENTS_PAGE_IMAGE_CACHE_TIME which defaults to 3600 seconds (1 hour). + DOCUMENTS_PAGE_IMAGE_CACHE_TIME which defaults to 31556926 seconds (1 year). - The document quick label selection field now uses a select2 widget. +- Include querystring when force reload of a bare template view. +- Speed up document image fade in reveal. +- Use reseteable timer to ensure more document panels heights are matched. +- Rewrote Mayan's Javascript suite MayanApp into ECMAScript2015. +- Remove use is waitForJQuery. +- Remove code statistics from the documentation. +- Remove the pending work chapter. This is now available in the Wiki: + wiki.mayan-edms.com 3.0.1 (2018-07-08) ================= diff --git a/docs/topics/code_statistics.rst b/docs/topics/code_statistics.rst deleted file mode 100644 index dfe990721f..0000000000 --- a/docs/topics/code_statistics.rst +++ /dev/null @@ -1,662 +0,0 @@ -Code statistics ---------------- - -As of Wed Mar 14 19:31:49 2018 (commit f3ba6ee2cca99acbbb2403d69cc3f922b0f2b0a2 - -App name: acls - - Views - module: mayan/apps/acls/views.py - class based views: 4 - function based views: 0 - - API Views - module: mayan/apps/acls/api_views.py - class based views: 4 - function based views: 0 - - Tests - module: mayan/apps/acls/tests/test_models.py - tests: 8 - module: mayan/apps/acls/tests/test_actions.py - tests: 2 - module: mayan/apps/acls/tests/test_links.py - tests: 4 - module: mayan/apps/acls/tests/test_api.py - tests: 9 - module: mayan/apps/acls/tests/test_views.py - tests: 8 - - -App name: appearance - - Views - No views - - API Views - No API views - - Tests - No tests - - -App name: authentication - - Views - module: mayan/apps/authentication/views.py - class based views: 0 - function based views: 7 - - API Views - No API views - - Tests - module: mayan/apps/authentication/tests/test_views.py - tests: 10 - - -App name: cabinets - - Views - module: mayan/apps/cabinets/views.py - class based views: 9 - function based views: 0 - - API Views - module: mayan/apps/cabinets/api_views.py - class based views: 5 - function based views: 0 - - Tests - module: mayan/apps/cabinets/tests/test_models.py - tests: 5 - module: mayan/apps/cabinets/tests/test_events.py - tests: 2 - module: mayan/apps/cabinets/tests/test_api.py - tests: 13 - module: mayan/apps/cabinets/tests/test_views.py - tests: 15 - - -App name: checkouts - - Views - module: mayan/apps/checkouts/views.py - class based views: 4 - function based views: 0 - - API Views - module: mayan/apps/checkouts/api_views.py - class based views: 2 - function based views: 0 - - Tests - module: mayan/apps/checkouts/tests/test_models.py - tests: 10 - module: mayan/apps/checkouts/tests/test_api.py - tests: 10 - module: mayan/apps/checkouts/tests/test_views.py - tests: 7 - - -App name: common - - Views - module: mayan/apps/common/views.py - class based views: 17 - function based views: 1 - - API Views - module: mayan/apps/common/api_views.py - class based views: 1 - function based views: 0 - - Tests - module: mayan/apps/common/tests/test_api.py - tests: 1 - module: mayan/apps/common/tests/test_commands.py - tests: 1 - module: mayan/apps/common/tests/test_views.py - tests: 3 - - -App name: converter - - Views - module: mayan/apps/converter/views.py - class based views: 4 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/converter/tests/test_classes.py - tests: 6 - module: mayan/apps/converter/tests/test_views.py - tests: 6 - - -App name: django_gpg - - Views - module: mayan/apps/django_gpg/views.py - class based views: 9 - function based views: 0 - - API Views - module: mayan/apps/django_gpg/api_views.py - class based views: 2 - function based views: 0 - - Tests - module: mayan/apps/django_gpg/tests/test_models.py - tests: 15 - module: mayan/apps/django_gpg/tests/test_api.py - tests: 6 - module: mayan/apps/django_gpg/tests/test_views.py - tests: 4 - - -App name: document_comments - - Views - module: mayan/apps/document_comments/views.py - class based views: 3 - function based views: 0 - - API Views - module: mayan/apps/document_comments/api_views.py - class based views: 2 - function based views: 0 - - Tests - module: mayan/apps/document_comments/tests/test_api.py - tests: 8 - - -App name: document_indexing - - Views - module: mayan/apps/document_indexing/views.py - class based views: 13 - function based views: 0 - - API Views - module: mayan/apps/document_indexing/api_views.py - class based views: 6 - function based views: 0 - - Tests - module: mayan/apps/document_indexing/tests/test_models.py - tests: 4 - module: mayan/apps/document_indexing/tests/test_views.py - tests: 8 - - -App name: document_parsing - - Views - module: mayan/apps/document_parsing/views.py - class based views: 6 - function based views: 0 - - API Views - module: mayan/apps/document_parsing/api_views.py - class based views: 1 - function based views: 0 - - Tests - module: mayan/apps/document_parsing/tests/test_parsers.py - tests: 1 - module: mayan/apps/document_parsing/tests/test_events.py - tests: 2 - module: mayan/apps/document_parsing/tests/test_api.py - tests: 2 - module: mayan/apps/document_parsing/tests/test_views.py - tests: 4 - - -App name: document_signatures - - Views - module: mayan/apps/document_signatures/views.py - class based views: 8 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/document_signatures/tests/test_models.py - tests: 13 - module: mayan/apps/document_signatures/tests/test_links.py - tests: 4 - module: mayan/apps/document_signatures/tests/test_views.py - tests: 12 - - -App name: document_states - - Views - module: mayan/apps/document_states/views.py - class based views: 29 - function based views: 0 - - API Views - module: mayan/apps/document_states/api_views.py - class based views: 12 - function based views: 0 - - Tests - module: mayan/apps/document_states/tests/test_models.py - tests: 3 - module: mayan/apps/document_states/tests/test_actions.py - tests: 0 - module: mayan/apps/document_states/tests/test_api.py - tests: 66 - module: mayan/apps/document_states/tests/test_views.py - tests: 33 - - -App name: documents - - Views - No views - - API Views - module: mayan/apps/documents/api_views.py - class based views: 16 - function based views: 0 - - Tests - module: mayan/apps/documents/tests/test_document_type_views.py - tests: 12 - module: mayan/apps/documents/tests/test_duplicated_document_views.py - tests: 4 - module: mayan/apps/documents/tests/test_document_views.py - tests: 31 - module: mayan/apps/documents/tests/test_utils.py - tests: 1 - module: mayan/apps/documents/tests/test_models.py - tests: 12 - module: mayan/apps/documents/tests/test_events.py - tests: 4 - module: mayan/apps/documents/tests/test_widgets.py - tests: 1 - module: mayan/apps/documents/tests/test_links.py - tests: 6 - module: mayan/apps/documents/tests/test_search.py - tests: 4 - module: mayan/apps/documents/tests/test_api.py - tests: 39 - module: mayan/apps/documents/tests/test_deleted_document_views.py - tests: 8 - module: mayan/apps/documents/tests/test_document_version_views.py - tests: 4 - module: mayan/apps/documents/tests/test_document_page_views.py - tests: 2 - - -App name: dynamic_search - - Views - module: mayan/apps/dynamic_search/views.py - class based views: 4 - function based views: 0 - - API Views - module: mayan/apps/dynamic_search/api_views.py - class based views: 3 - function based views: 0 - - Tests - module: mayan/apps/dynamic_search/tests/test_models.py - tests: 4 - module: mayan/apps/dynamic_search/tests/test_api.py - tests: 3 - module: mayan/apps/dynamic_search/tests/test_views.py - tests: 1 - - -App name: events - - Views - module: mayan/apps/events/views.py - class based views: 9 - function based views: 0 - - API Views - module: mayan/apps/events/api_views.py - class based views: 7 - function based views: 0 - - Tests - module: mayan/apps/events/tests/test_api.py - tests: 1 - module: mayan/apps/events/tests/test_views.py - tests: 2 - - -App name: linking - - Views - module: mayan/apps/linking/views.py - class based views: 11 - function based views: 0 - - API Views - module: mayan/apps/linking/api_views.py - class based views: 7 - function based views: 0 - - Tests - module: mayan/apps/linking/tests/test_models.py - tests: 1 - module: mayan/apps/linking/tests/test_api.py - tests: 34 - module: mayan/apps/linking/tests/test_views.py - tests: 8 - - -App name: lock_manager - - Views - No views - - API Views - No API views - - Tests - module: mayan/apps/lock_manager/tests/test_backends.py - tests: 6 - - -App name: mailer - - Views - module: mayan/apps/mailer/views.py - class based views: 10 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/mailer/tests/test_models.py - tests: 5 - module: mayan/apps/mailer/tests/test_views.py - tests: 12 - - -App name: mayan_statistics - - Views - module: mayan/apps/mayan_statistics/views.py - class based views: 4 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/mayan_statistics/tests/test_views.py - tests: 4 - - -App name: metadata - - Views - module: mayan/apps/metadata/views.py - class based views: 9 - function based views: 0 - - API Views - module: mayan/apps/metadata/api_views.py - class based views: 6 - function based views: 0 - - Tests - module: mayan/apps/metadata/tests/test_models.py - tests: 14 - module: mayan/apps/metadata/tests/test_wizard_steps.py - tests: 1 - module: mayan/apps/metadata/tests/test_api.py - tests: 35 - module: mayan/apps/metadata/tests/test_views.py - tests: 8 - - -App name: mimetype - - Views - No views - - API Views - No API views - - Tests - No tests - - -App name: mirroring - - Views - No views - - API Views - No API views - - Tests - No tests - - -App name: motd - - Views - module: mayan/apps/motd/views.py - class based views: 4 - function based views: 0 - - API Views - module: mayan/apps/motd/api_views.py - class based views: 2 - function based views: 0 - - Tests - module: mayan/apps/motd/tests/test_models.py - tests: 4 - module: mayan/apps/motd/tests/test_api.py - tests: 10 - - -App name: navigation - - Views - No views - - API Views - No API views - - Tests - module: mayan/apps/navigation/tests/test_classes.py - tests: 9 - - -App name: ocr - - Views - module: mayan/apps/ocr/views.py - class based views: 8 - function based views: 0 - - API Views - module: mayan/apps/ocr/api_views.py - class based views: 3 - function based views: 0 - - Tests - module: mayan/apps/ocr/tests/test_models.py - tests: 2 - module: mayan/apps/ocr/tests/test_events.py - tests: 2 - module: mayan/apps/ocr/tests/test_api.py - tests: 6 - module: mayan/apps/ocr/tests/test_views.py - tests: 4 - - -App name: permissions - - Views - module: mayan/apps/permissions/views.py - class based views: 7 - function based views: 0 - - API Views - module: mayan/apps/permissions/api_views.py - class based views: 3 - function based views: 0 - - Tests - module: mayan/apps/permissions/tests/test_models.py - tests: 2 - module: mayan/apps/permissions/tests/test_api.py - tests: 17 - module: mayan/apps/permissions/tests/test_views.py - tests: 3 - - -App name: rest_api - - Views - No views - - API Views - module: mayan/apps/rest_api/api_views.py - class based views: 1 - function based views: 0 - - Tests - - -App name: smart_settings - - Views - module: mayan/apps/smart_settings/views.py - class based views: 2 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/smart_settings/tests/test_classes.py - tests: 1 - module: mayan/apps/smart_settings/tests/test_view_permissions.py - tests: 2 - - -App name: sources - - Views - module: mayan/apps/sources/views.py - class based views: 10 - function based views: 0 - - API Views - module: mayan/apps/sources/api_views.py - class based views: 4 - function based views: 0 - - Tests - module: mayan/apps/sources/tests/test_models.py - tests: 3 - module: mayan/apps/sources/tests/test_classes.py - tests: 1 - module: mayan/apps/sources/tests/test_views.py - tests: 15 - - -App name: storage - - Views - No views - - API Views - No API views - - Tests - No tests - - -App name: tags - - Views - module: mayan/apps/tags/views.py - class based views: 8 - function based views: 0 - - API Views - module: mayan/apps/tags/api_views.py - class based views: 5 - function based views: 0 - - Tests - module: mayan/apps/tags/tests/test_models.py - tests: 1 - module: mayan/apps/tags/tests/test_actions.py - tests: 2 - module: mayan/apps/tags/tests/test_wizard_steps.py - tests: 1 - module: mayan/apps/tags/tests/test_api.py - tests: 28 - module: mayan/apps/tags/tests/test_views.py - tests: 18 - - -App name: task_manager - - Views - module: mayan/apps/task_manager/views.py - class based views: 4 - function based views: 0 - - API Views - No API views - - Tests - module: mayan/apps/task_manager/tests/test_views.py - tests: 8 - - -App name: user_management - - Views - module: mayan/apps/user_management/views.py - class based views: 11 - function based views: 0 - - API Views - module: mayan/apps/user_management/api_views.py - class based views: 6 - function based views: 0 - - Tests - module: mayan/apps/user_management/tests/test_api.py - tests: 31 - module: mayan/apps/user_management/tests/test_views.py - tests: 10 - -Totals: - Tests: 753 - Function based API views: 0 - Function based views: 8 - Apps: 34 - Class based API views: 98 - Class based views: 207 - -These are the defined views and tests defined. Actual executable views or -tests could be higher if subclassed. - -Actual test executed: 757 as lock manager app subclasses its 6 tests once diff --git a/docs/topics/index.rst b/docs/topics/index.rst index c937e20d94..df0c8cf2b2 100644 --- a/docs/topics/index.rst +++ b/docs/topics/index.rst @@ -25,6 +25,4 @@ Introductions to all the key parts of Mayan EDMS you'll need to know: file_storage backups upload_wizard - pending_work - code_statistics docker diff --git a/docs/topics/pending_work.rst b/docs/topics/pending_work.rst deleted file mode 100644 index e47d81ebcd..0000000000 --- a/docs/topics/pending_work.rst +++ /dev/null @@ -1,312 +0,0 @@ -============ -Pending work -============ - -Release blockers ----------------- - -These are errors or issues that are blocking a release. - -- None - -Pending work ------------- - -These are tasks that need to be completed but are missing a dependency or -a design decision. As more information is added to each, they should be -converted into a MERC. - -API -~~~ -- User API edit view: Should not be able to add of remove groups without - corresponding group access. -- User group list API get & post views: Should adding a group to an user - via the API return 201 or 200. Currently returns 201. -- Consistent API return code for delete views without access. Some views - return 403 other return 404. -- Update API docstrings. The upgrade to the latest DRF broke all formatting. -- Make views smaller. Much as much as possible to serializers. -- Switch to ViewSets. -- Add API filtering. Example unread notifications. - - -Documents -~~~~~~~~~ -- Navigating to the interactive document page image is not triggering - the document view event. - - -Events -~~~~~~ -- New event: document emailed. - - -Forms processing -~~~~~~~~~~~~~~~~ -- Remove usage of self.cleaned_data. Use self.clean_data instead. - - -Permissions -~~~~~~~~~~~ -- Permission should be reciprocal. Example: To be able to add a tag to a - document, the user must hold the tag add permission for the document - and for the tag to be added. To be able to enable a metadata type to a - document type, the user must hold the metadata add permissions for the - metadata type and for the document type. -- Edit type permissions should only grant the ability to edit the properties - of an object. To modify its relationship with other objects a reciprocal - permission check should be instead. - - -Search -~~~~~~ -- Rename SearchModel.pk to id - - -Sources -~~~~~~~ -- Add ACLs support to sources. -- Provide error message/feedback when scanning from a remote scanner fails. -- Require a permission for document types to avoid a user that has the workflow - creation permission to attach a workflow to a document type they don't - control. -- Research making APIWorkflowDocumentTypeList a subclass of documents.api_views.APIDocumentTypeList -- A POST request to APIWorkflowDocumentTypeList should require some permission - on the document type part to avoid adding non controlled document types - to a new workflow. -- To transition a workflow, the transition permission is only needed for the - workflow. Make it necesary to have the same permission for the document - of document type. -- To view the transition log, the workflow view permission is only needed for the - document. Make it necesary to have the same permission for the workflow or - for the transition and the states. -- Render date time of scanned documents using SANE to a better output - (like document versions). - - -Testing -~~~~~~~ -- Add document test mixin that creates documents types and documents - (to be used in dynamic_search.test_api). -- Update all API tests using self.client to just self. and the HTTP method. -- Add test for searches for each app that uses search. - - -UI - Frontend -~~~~~~~~~~~~~ -- Fix menu not collapsing at the same width of nav parent. -- Move direct CSS style from code into base.css. grep 'style' * -R. Style code in: - - * appearance/templates/appearance/generic_list_items_subtemplate.html - * appearance/templates/appearance/base.html - * appearance/templates/appearance/generic_list_subtemplate.html - * appearance/templates/navigation/generic_link_instance.html - -- Check if location is found in partial and remove it. Avoid circular loading. -- Add location to history after a form submit redirect. - - -UI -~~ -- Shift click select to seletect multiple documents. -- During the document upload wizard and the option to double click to - select document type and submit the form. The purpose is to speed up - the step with less mouse travel since this is a common screen. -- Add metadata to the Menu class to allow UI code to decide where and how - to display each menu. -- Reduce the facet buttons paddings. -- Make facet action button smaller. Reduce margin-bottom. -- Remove previous from the views.py. It is not longer used by the form's cancel button. - - -Workflows -~~~~~~~~~ -- Workflow trigger filters. Example: {{ document.document_type.name = 'invoice' }} - or same UI as the smart links app. Will allow restricting the firing of workflow - actions by an user defined filter criteria. -- Require a permission for document types to avoid a user that has the workflow - creation permission to attach a workflow to a document type they don't - control. -- Research making APIWorkflowDocumentTypeList a subclass of - documents.api_views.APIDocumentTypeList -- A POST request to APIWorkflowDocumentTypeList should require some permission - on the document type part to avoid adding non controlled document types - to a new workflow. -- To transition a workflow, the transition permission is only needed for the - workflow. Make it necesary to have the same permission for the document - of document type. -- To view the transition log, the workflow view permission is only needed for - the document. Make it necesary to have the same permission for the workflow or - for the transition and the states. - - -New features ------------- - - -API -~~~ -- Add converter API -- Document signatures API -- Smart settings API -- Use REST_API's 'mayan_permission_attribute_check' to simplify API views access checking and filtering. -- DRF filtering using the URL query. - - -Converter -~~~~~~~~~ -- New zoom transformation. Resample, not just bigger final size but do - a resize * zoom multiple before. Produces a bigger image or higher - quality than the original. - - -Caching -~~~~~~~ -- Size limited caching. A new model in the common app will keep track - of all cache files. A manager method will be provided that will - return the cache files in other of age to be deleted. - - -Distribution -~~~~~~~~~~~~ -- Python based Javascript package manager. Each app specifies what - library and version needs. The common app (or a new app) will add all - the JS loading lines automatically so that compress can detect them. - - -Metadata -~~~~~~~~ -- Metadata lookup memory. Add a select2 style widget that will query a - new metadata API endpoint that will return all used values so far. -- Metadata validation_choices and parser_choices as static model methods -- Metadata.api as Metadata.utils and manager - - -Search -~~~~~~ -- Add support for highlighting the search results in pages. - - -Settings -~~~~~~~~ -- Database based settings. - - -Sources -~~~~~~~ -- UI improvement for staging folders files selection. GitLab issue. - - -UI -~~ -- Upgrade to Bootstrap 4. -- Upgrade to Flatly 4. -- Better workflow transition UI. Instead of a dropdown show all the - available transitions as buttons. - - -Workflows -~~~~~~~~~ -- Workflow trigger filters. Example: {{ document.document_type.name = 'invoice' }} or same - UI as the smart links app. Will allow restricting the firing of workflow - actions by an user defined filter criteria. -- New workflow action: send email. Subject and content are templates. - - -Other -~~~~~ -- Python based Javascript package manager. Each app specifies what - library and version needs. The common app (or a new app) will add all - the JS loading lines automatically so that compress can detect them. -- When moving documents to the trash update the message to "submitted" - and not "moved" or "deleted" since this is handled by a task queue - and is not immediate and doesn't delete the document. -- When emptying the trash update the message to "submitted" - since this is handled by a task queue and is not immediate. -- New app that allows creating user document filters. Will provide the - same service as the document filters class. Interface can be made - using the template language or the same UI as the smart links. -- Allow add queue metadata that can be exported via a management command. - This will allow creating supervisor templates without all the worker - entries being hardcoded. -- Delete .gitignore files from copied packages. Include .gitignore files - keep compiled or distributable files from being included in the main - repository. Temporary measure until a Javascript library manager is - added. -- Automatically capture license information from installed Javascript - libraries. -- Automatically capture license information from installed Python - packages. -- Update celery to 4.1.0 -- Update to use the new class based views in the authentication app. - password_change(), password_change_done(), password_reset(), - password_reset_done(), password_reset_confirm(), and password_reset_complete() - function-based views are deprecated in favor of new class-based views - PasswordChangeView, PasswordChangeDoneView, PasswordResetView, - PasswordResetDoneView, PasswordResetConfirmView, and PasswordResetCompleteView. -- django.utils.translation.string_concat() is deprecated in favor of - django.utils.text.format_lazy(). string_concat(strings) can be - replaced by format_lazy('{}' x len(strings), strings). - Found in converter/classes.py and metadata/forms.py. -- Fix warnings in preparation for Django 2.0. -- Update all tempfile.mkstemp() to tempfile.mkstemp(dir=setting_temporary_directory.value) -- Get rid of common.utils.get_descriptor only used by common.utils.copyfile -- Update common.utils.copyfile to use only file objects. -- Change metadata label column from CharField to Label -- Start testing to Python 3 compatibility. -- Unify all RelationshipForms into a common class. -- Add test for event subscription view. -- Repeated templates: password_reset_confirm.html and password_reset_form.html -- Remove unused text=get_notification_count from events.links -- Reduce number of languages so dropzone view starts faster. -- In DocumentComment model, rename comment field to text. -- class MultipleInstanceActionMixin is deprecated. Replace views using this with - MultipleObjectFormActionView or MultipleObjectConfirmActionView -- Subscribe to tag events -- Subscribe to workflow events -- Subscribe to workflow state events -- Link to go from event notification to view. Example document workflow notification to document workflow views. -- Find replacement for ``python-gnupg``. Unstable & inconsistent API. -- New app that allows creating user document filters. Will provide the - same service as the document filters class. Interface can be made - using the template language or the same UI as the smart links. -- Allow add queue metadata that can be exported via a management command. - This will allow creating supervisor templates without all the worker - entries being hardcoded. -- Automatically capture license information from installed Javascript - libraries. -- Automatically capture license information from installed Python - packages. -- Finish and merge improved compressed file branch. -- Improve and merge PCL support branch. -- Swtich to self hosted documentation. -- Unify error logs in a common model. Fields: Datetime, namespace, - message, content type, object id. -- Export documents as PDF. Each document image is used to create a PDF - dinamycally. -- Document splitting. Only for PDF files first. A document versions - relationship between the documents has to be designed. -- Manually linking documents. -- Migrate settings/base.py to Django's 1.11 format. -- Rename model methods to use ``get_`` or ``do_`` -- Hunt TODO -- Hunt FIXME -- Convert SETTING_GPG_BACKEND into a setting option similar to converter and converter options. -- Reorganize modelForms Meta class and methods. -- Periodic messages, like notifications. Using an AJAX worker. -- Find replacement for ``python-gnupg``. Unstable & inconsistent API. -- Google docs integration. Upload document from Google Drive. -- Get ``dumpdata`` and ``loaddata`` working flawlessly. Will allow for easier backups, restores and database backend migrations. -- Add generic list ordering. ``django.views.generic.list.MultipleObjectMixin`` (https://docs.djangoproject.com/en/1.8/ref/class-based-views/mixins-multiple-object/#django.views.generic.list.MultipleObjectMixin) now supports an ``ordering`` parameter. -- Add support to convert any document to PDF. https://gitlab.mister-muffin.de/josch/img2pdf -- Add support for combining documents. -- Add support for splitting documents. -- Add new document source to get documents from an URL. -- Add support for metadata mapping files. CSV file containing filename to metadata values mapping, useful for bulk upload and migrations. -- Add support for registering widgets to the home screen. -- Merge mimetype and converter apps. -- Metadata widgets (Date, time, timedate). -- Datatime widget: https://github.com/smalot/bootstrap-datetimepicker -- Add events for document signing app (uploaded detached signateure, signed document, deleted signature) -- A configurable conversion process. Being able to invoke different binaries for file conversion, as opposed to the current libreoffice only solution. -- A tool in the admin interface to mass (re)convert the files (basically the page count function, but then applied on all documents). diff --git a/mayan/apps/appearance/static/appearance/js/base.js b/mayan/apps/appearance/static/appearance/js/base.js index 72f0978ecc..244ac0298a 100644 --- a/mayan/apps/appearance/static/appearance/js/base.js +++ b/mayan/apps/appearance/static/appearance/js/base.js @@ -1,26 +1,12 @@ 'use strict'; -var app = new App(); +// Make it globally available. Used by event.links + +var MayanAppClass = MayanApp; + var partialNavigation = new PartialNavigation({ initialURL: initialURL, + disabledAnchorClasses: ['disabled'], excludeAnchorClasses: ['fancybox', 'new_window', 'non-ajax'], - formBeforeSerializeCallbacks: [App.MultiObjectFormProcess], + formBeforeSerializeCallbacks: [MayanApp.MultiObjectFormProcess], }); - -jQuery(document).ready(function() { - app.setupAutoSubmit(); - app.setupFullHeightResizing(); - app.setupItemsSelector(); - app.setupNavbarCollapse(); - app.setupNewWindowAnchor(); - app.setupAJAXperiodicWorkers(); - partialNavigation.initialize(); -}); - -var afterBaseLoad = function () { - MayanImage.intialize(); - app.doToastrMessages(); - app.resizeFullHeight(); - app.setupSelect2(); - app.setupScrollView(); -} diff --git a/mayan/apps/appearance/static/appearance/js/mayan_app.js b/mayan/apps/appearance/static/appearance/js/mayan_app.js index efcdd0dc38..7dd052e46e 100644 --- a/mayan/apps/appearance/static/appearance/js/mayan_app.js +++ b/mayan/apps/appearance/static/appearance/js/mayan_app.js @@ -1,284 +1,296 @@ 'use strict'; -var App = function (parameters) { - var self = this; +class MayanApp { + constructor (parameters) { + var self = this; - parameters = parameters || {} + parameters = parameters || {} - this.window = $(window); -} + this.window = $(window); + } -// Class methods and variables + // Class methods and variables -App.mayanNotificationBadge = function (options, data) { - // Callback to add the notifications count inside a badge markup - var notifications = data[options.attributeName]; + static mayanNotificationBadge (options, data) { + // Callback to add the notifications count inside a badge markup + var notifications = data[options.attributeName]; - if (notifications > 0) { - // Save the original link text before adding the initial badge markup - if (!options.element.data('mn-saved-text')) { - options.element.data('mn-saved-text', options.element.html()); - } + if (notifications > 0) { + // Save the original link text before adding the initial badge markup + if (!options.element.data('mn-saved-text')) { + options.element.data('mn-saved-text', options.element.html()); + } - options.element.html( - options.element.data('mn-saved-text') + ' ' + notifications + '' - ); - } else { - if (options.element.data('mn-saved-text')) { - // If there is a saved original link text, restore it options.element.html( - options.element.data('mn-saved-text') + options.element.data('mn-saved-text') + ' ' + notifications + '' ); + } else { + if (options.element.data('mn-saved-text')) { + // If there is a saved original link text, restore it + options.element.html( + options.element.data('mn-saved-text') + ); + } } } -} -App.MultiObjectFormProcess = function ($form, options) { - /* - * ajaxForm callback to add the external item checkboxes to the - * submitted form - */ + static MultiObjectFormProcess ($form, options) { + /* + * ajaxForm callback to add the external item checkboxes to the + * submitted form + */ - if ($form.hasClass('form-multi-object-action')) { - // Turn form data into an object - var formArray = $form.serializeArray().reduce(function (obj, item) { - obj[item.name] = item.value; - return obj; - }, {}); + if ($form.hasClass('form-multi-object-action')) { + // Turn form data into an object + var formArray = $form.serializeArray().reduce(function (obj, item) { + obj[item.name] = item.value; + return obj; + }, {}); - // Add all checked checkboxes to the form data - $('.form-multi-object-action-checkbox:checked').each(function() { + // Add all checked checkboxes to the form data + $('.form-multi-object-action-checkbox:checked').each(function() { + var $this = $(this); + formArray[$this.attr('name')] = $this.attr('value'); + }); + + // Set the form data as the data to send + options.data = formArray; + } + } + + static tagSelectionTemplate (tag, container) { + var $tag = $( + ' ' + tag.text + '' + ); + container[0].style.background = tag.element.dataset.color; + return $tag; + } + + static tagResultTemplate (tag) { + if (!tag.element) { return ''; } + var $tag = $( + ' ' + tag.text + '' + ); + return $tag; + } + + // Instance methods + + AJAXperiodicWorker (options) { + var app = this; + + $.ajax({ + complete: function() { + if (!options.app) { + // Preserve the app reference between consecutive calls + options.app = app; + } + setTimeout(options.app.AJAXperiodicWorker, options.interval, options); + }, + success: function(data) { + if (options.callback) { + // Conver the callback string to an actual function + var callbackFunction = window; + + $.each(options.callback.split('.'), function (index, value) { + callbackFunction = callbackFunction[value] + }); + + callbackFunction(options, data); + } else { + options.element.text(data[options.attributeName]); + } + }, + url: options.APIURL + }); + } + + doToastrMessages () { + toastr.options = { + 'closeButton': true, + 'debug': false, + 'newestOnTop': true, + 'positionClass': 'toast-top-right', + 'preventDuplicates': false, + 'onclick': null, + 'showDuration': '300', + 'hideDuration': '1000', + 'timeOut': '5000', + 'extendedTimeOut': '1000', + 'showEasing': 'swing', + 'hideEasing': 'linear', + 'showMethod': 'fadeIn', + 'hideMethod': 'fadeOut' + } + + // Add invisible bootstrap messages to copy the styles to toastr.js + + $('body').append('\ +
text
\ +text
\ +text
\ +text
\ +text
\ -text
\ -text
\ -text
\ -' + jqXHR.responseText + '');
- } else {
- if (jqXHR.status == 0) {
- $('#modal-server-error .modal-body').html($('#template-error').html());
- $('#modal-server-error').modal('show')
- } else {
- $('#ajax-content').html(jqXHR.responseText);
- }
- }
-}
-
-PartialNavigation.prototype.setLocation = function (newLocation, pushState) {
- /*
- * Method to update the browsers history and trigger a page update.
- */
-
- // Validate the new location first.
- newLocation = this.filterLocation(newLocation);
-
- if (typeof pushState === 'undefined') {
- // Check if we should just load the content or load the content
- // and update the history.
- pushState = true;
- }
-
- var currentLocation = new URI(location);
- currentLocation.fragment(newLocation);
-
- if (pushState) {
- history.pushState({}, '', currentLocation);
- }
- this.loadAjaxContent(newLocation);
-}
-
-PartialNavigation.prototype.setupAjaxAnchors = function () {
- /*
- * Setup the new click event handler.
- */
- var app = this;
- $('body').on('click', 'a', function (event) {
- app.onAnchorClick($(this), event);
- });
-}
-
-PartialNavigation.prototype.setupAjaxForm = function () {
- /*
- * Method to setup the handling of form in an AJAX way.
- */
- var app = this;
- var lastAjaxFormData = {};
-
- $('form').ajaxForm({
- async: true,
- beforeSerialize: function($form, options) {
- // Manage any callback registered to preprocess the form.
- $.each(app.formBeforeSerializeCallbacks, function (index, value) {
- value($form, options);
- });
- },
- beforeSubmit: function(arr, $form, options) {
- var uri = new URI(location);
- var uriFragment = uri.fragment();
- var url = $form.attr('action') || uriFragment;
-
- options.url = url;
- lastAjaxFormData.url = url + '?' + decodeURIComponent($form.serialize());
-
- if ($form.attr('target') == '_blank') {
- // If the form has a target attribute we emulate it by
- // opening a new window and passing the form serialized
- // data as the query.
- window.open(
- $form.attr('action') + '?' + decodeURIComponent($form.serialize())
- );
-
- return false;
- }
- },
- dataType: 'html',
- delegation: true,
- error: function(jqXHR, textStatus, errorThrown){
- app.processAjaxRequestError(jqXHR);
- },
- mimeType: 'text/html; charset=utf-8', // ! Need set mimeType only when run from local file
- success: function(data, textStatus, request){
- if (request.status == 278) {
- // Handle redirects after submitting the form
- var newLocation = request.getResponseHeader('Location');
- var uri = new URI(newLocation);
- var uriFragment = uri.fragment();
- var currentUri = new URI(window.location.hash);
- var currentUriFragment = currentUri.fragment();
- var url = uriFragment || currentUriFragment;
-
- app.setLocation(newLocation);
- } else {
- var currentUri = new URI(window.location.hash);
- currentUri.fragment(lastAjaxFormData.url);
- history.pushState({}, '', currentUri);
- $('#ajax-content').html(data);
- }
+ if (!this.initialURL) {
+ alert('Need to setup initialURL');
}
- });
-}
+ }
-PartialNavigation.prototype.setupAjaxNavigation = function () {
- /*
- * Setup the navigation method using the hash of the location.
- * Also handles the back button event and loads via AJAX any
- * URL in the location when the app first launches. Registers
- * a callback to send an emulated HTTP_REFERER so that the backends
- * code will still work without change.
- */
- var app = this;
+ initialize () {
+ this.setupAjaxAnchors();
+ this.setupAjaxNavigation();
+ this.setupAjaxForm();
+ }
- // Load ajax content when the hash changes
- if (window.history && window.history.pushState) {
- $(window).on('popstate', function() {
- var uri = new URI(location);
- var uriFragment = uri.fragment();
- app.setLocation(uriFragment, false);
+ filterLocation (newLocation) {
+ /*
+ * Method to validate new locations
+ */
+ var uri = new URI(newLocation);
+ var currentLocation = new URI(location);
+
+ if (uri.path() === '') {
+ // href with no path remain in the same location
+ // We strip the same location query and use the new href's one
+ uri.path(
+ new URI(currentLocation.fragment()).path()
+ )
+ return uri.toString();
+ }
+
+ if (uri.path() === '/') {
+ // Root URL is not allowed
+ return this.initialURL;
+ }
+
+ return newLocation;
+ }
+
+ loadAjaxContent (url) {
+ /*
+ * Method to load and display partial backend views to the main
+ * view port.
+ */
+ var app = this;
+
+ url = this.filterLocation(url);
+ $.ajax({
+ async: true,
+ mimeType: 'text/html; charset=utf-8', // ! Need set mimeType only when run from local file
+ url: url,
+ type: 'GET',
+ success: function (data, textStatus, response){
+ if (response.status == 278) {
+ // Handle redirects
+ var newLocation = response.getResponseHeader('Location');
+
+ app.setLocation(newLocation);
+ app.lastLocation = newLocation;
+ } else {
+ app.lastLocation = url;
+ if (response.getResponseHeader('Content-Disposition')) {
+ window.location = this.url;
+ } else {
+ $('#ajax-content').html(data);
+ }
+ }
+ },
+ error: function (jqXHR, textStatus, errorThrown){
+ app.processAjaxRequestError(jqXHR);
+ },
+ dataType: 'html',
});
}
- // Load any initial address in the URL of the browser
- if (window.location.hash) {
- var uri = new URI(window.location.hash);
- var uriFragment = uri.fragment();
- this.setLocation(uriFragment);
- } else {
- this.setLocation('/');
+ onAnchorClick ($this, event) {
+ /*
+ * Anchor click event manager. We intercept all click events and
+ * route them to load the content via AJAX instead.
+ */
+ var url;
+
+ if ($this.hasAnyClass(this.excludeAnchorClasses)) {
+ return true;
+ }
+
+ if ($this.hasAnyClass(this.disabledAnchorClasses)) {
+ event.preventDefault();
+ return false;
+ }
+
+ if ($this.parents().hasAnyClass(this.disabledAnchorClasses)) {
+ event.preventDefault();
+ return false;
+ }
+
+ url = $this.attr('href');
+ if (url === undefined) {
+ return true;
+ }
+
+ if (url.indexOf('javascript:;') > -1) {
+ // Ignore links meant to execute javascript on click.
+ return true;
+ }
+
+ if (url === '#') {
+ // Ignore links with hash at the.
+ return true;
+ }
+
+ event.preventDefault();
+
+ if (event.ctrlKey) {
+ window.open(url);
+ return false;
+ }
+
+ if (!($this.hasClass('disabled') || $this.parent().hasClass('disabled'))) {
+ this.setLocation(url);
+ }
}
- $.ajaxSetup({
- beforeSend: function (jqXHR, settings) {
- // Emulate the HTTP_REFERER.
- jqXHR.setRequestHeader('X-Alt-Referer', app.lastLocation);
- },
- });
+ processAjaxRequestError (jqXHR) {
+ /*
+ * Method to process an AJAX request and make it presentable to the
+ * user.
+ */
+
+ if (djangoDEBUG) {
+ $('#ajax-content').html('' + jqXHR.responseText + '');
+ } else {
+ if (jqXHR.status == 0) {
+ $('#modal-server-error .modal-body').html($('#template-error').html());
+ $('#modal-server-error').modal('show')
+ } else {
+ $('#ajax-content').html(jqXHR.responseText);
+ }
+ }
+ }
+
+ setLocation (newLocation, pushState) {
+ /*
+ * Method to update the browsers history and trigger a page update.
+ */
+
+ // Validate the new location first.
+ newLocation = this.filterLocation(newLocation);
+
+ if (typeof pushState === 'undefined') {
+ // Check if we should just load the content or load the content
+ // and update the history.
+ pushState = true;
+ }
+
+ var currentLocation = new URI(location);
+ currentLocation.fragment(newLocation);
+
+ if (pushState) {
+ history.pushState({}, '', currentLocation);
+ }
+ this.loadAjaxContent(newLocation);
+ }
+
+ setupAjaxAnchors () {
+ /*
+ * Setup the new click event handler.
+ */
+ var app = this;
+ $('body').on('click', 'a', function (event) {
+ app.onAnchorClick($(this), event);
+ });
+ }
+
+ setupAjaxForm () {
+ /*
+ * Method to setup the handling of form in an AJAX way.
+ */
+ var app = this;
+ var lastAjaxFormData = {};
+
+ $('form').ajaxForm({
+ async: true,
+ beforeSerialize: function($form, options) {
+ // Manage any callback registered to preprocess the form.
+ $.each(app.formBeforeSerializeCallbacks, function (index, value) {
+ value($form, options);
+ });
+ },
+ beforeSubmit: function(arr, $form, options) {
+ var uri = new URI(location);
+ var uriFragment = uri.fragment();
+ var url = $form.attr('action') || uriFragment;
+
+ options.url = url;
+ lastAjaxFormData.url = url + '?' + decodeURIComponent($form.serialize());
+
+ if ($form.attr('target') == '_blank') {
+ // If the form has a target attribute we emulate it by
+ // opening a new window and passing the form serialized
+ // data as the query.
+ window.open(
+ $form.attr('action') + '?' + decodeURIComponent($form.serialize())
+ );
+
+ return false;
+ }
+ },
+ dataType: 'html',
+ delegation: true,
+ error: function(jqXHR, textStatus, errorThrown){
+ app.processAjaxRequestError(jqXHR);
+ },
+ mimeType: 'text/html; charset=utf-8', // ! Need set mimeType only when run from local file
+ success: function(data, textStatus, request){
+ if (request.status == 278) {
+ // Handle redirects after submitting the form
+ var newLocation = request.getResponseHeader('Location');
+ var uri = new URI(newLocation);
+ var uriFragment = uri.fragment();
+ var currentUri = new URI(window.location.hash);
+ var currentUriFragment = currentUri.fragment();
+ var url = uriFragment || currentUriFragment;
+
+ app.setLocation(newLocation);
+ } else {
+ var currentUri = new URI(window.location.hash);
+ currentUri.fragment(lastAjaxFormData.url);
+ history.pushState({}, '', currentUri);
+ $('#ajax-content').html(data);
+ }
+ }
+ });
+ }
+
+ setupAjaxNavigation () {
+ /*
+ * Setup the navigation method using the hash of the location.
+ * Also handles the back button event and loads via AJAX any
+ * URL in the location when the app first launches. Registers
+ * a callback to send an emulated HTTP_REFERER so that the backends
+ * code will still work without change.
+ */
+ var app = this;
+
+ // Load ajax content when the hash changes
+ if (window.history && window.history.pushState) {
+ $(window).on('popstate', function() {
+ var uri = new URI(location);
+ var uriFragment = uri.fragment();
+ app.setLocation(uriFragment, false);
+ });
+ }
+
+ // Load any initial address in the URL of the browser
+ if (window.location.hash) {
+ var uri = new URI(window.location.hash);
+ var uriFragment = uri.fragment();
+ this.setLocation(uriFragment);
+ } else {
+ this.setLocation('/');
+ }
+
+ $.ajaxSetup({
+ beforeSend: function (jqXHR, settings) {
+ // Emulate the HTTP_REFERER.
+ jqXHR.setRequestHeader('X-Alt-Referer', app.lastLocation);
+ },
+ });
+ }
}
diff --git a/mayan/apps/appearance/templates/appearance/base.html b/mayan/apps/appearance/templates/appearance/base.html
index 03924406b5..677f8c7758 100644
--- a/mayan/apps/appearance/templates/appearance/base.html
+++ b/mayan/apps/appearance/templates/appearance/base.html
@@ -11,7 +11,7 @@
* current location's path as the new hash
*/
document.write('
diff --git a/mayan/apps/appearance/templates/appearance/base_plain.html b/mayan/apps/appearance/templates/appearance/base_plain.html
index 6c33c4fd4a..a2a9a8b82f 100644
--- a/mayan/apps/appearance/templates/appearance/base_plain.html
+++ b/mayan/apps/appearance/templates/appearance/base_plain.html
@@ -31,16 +31,6 @@
if (currentHash.length) {
window.location = currentHash.substring(1);
}
-
- function waitForJQuery(func) {
- if (window.jQuery) {
- func();
- } else {
- setTimeout(function() {
- waitForJQuery(func)
- }, 50);
- }
- }
diff --git a/mayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.html b/mayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.html
index 063ffe7111..93bf83dbec 100644
--- a/mayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.html
+++ b/mayan/apps/appearance/templates/appearance/generic_list_items_subtemplate.html
@@ -4,18 +4,6 @@
{% load common_tags %}
{% load navigation_tags %}
-
-