summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.github/issue_template.md23
-rw-r--r--.github/pull_request_template.md6
-rw-r--r--.htaccess7
-rw-r--r--.travis.yml2
-rw-r--r--CONTRIBUTORS.md3
-rw-r--r--ChangeLog77
-rw-r--r--LICENSE2
-rw-r--r--Makefile2
-rw-r--r--README.md6
-rw-r--r--app/Action/TaskEmail.php1
-rw-r--r--app/Api/Procedure/ActionProcedure.php6
-rw-r--r--app/Api/Procedure/BoardProcedure.php3
-rw-r--r--app/Api/Procedure/MeProcedure.php2
-rw-r--r--app/Api/Procedure/ProjectPermissionProcedure.php4
-rw-r--r--app/Api/Procedure/TaskMetadataProcedure.php2
-rw-r--r--app/Api/Procedure/TaskProcedure.php14
-rw-r--r--app/Api/Procedure/TaskTagProcedure.php2
-rw-r--r--app/Console/JobCommand.php35
-rw-r--r--app/Controller/BoardAjaxController.php3
-rw-r--r--app/Controller/BoardViewController.php5
-rw-r--r--app/Controller/ColumnController.php18
-rw-r--r--app/Controller/ConfigController.php1
-rw-r--r--app/Controller/CurrencyController.php59
-rw-r--r--app/Controller/CustomFilterController.php34
-rw-r--r--app/Controller/ExportController.php34
-rw-r--r--app/Controller/FileViewerController.php53
-rw-r--r--app/Controller/GroupAjaxController.php6
-rw-r--r--app/Controller/ICalendarController.php5
-rw-r--r--app/Controller/LinkController.php50
-rw-r--r--app/Controller/PluginController.php1
-rw-r--r--app/Controller/ProjectEditController.php95
-rw-r--r--app/Controller/ProjectGanttController.php3
-rw-r--r--app/Controller/TaskAjaxController.php6
-rw-r--r--app/Controller/TaskCreationController.php5
-rw-r--r--app/Controller/TaskExternalLinkController.php21
-rw-r--r--app/Controller/TaskGanttController.php3
-rw-r--r--app/Controller/TaskGanttCreationController.php64
-rw-r--r--app/Controller/TaskImportController.php7
-rw-r--r--app/Controller/TaskMovePositionController.php7
-rw-r--r--app/Controller/TaskStatusController.php10
-rw-r--r--app/Controller/UserAjaxController.php10
-rw-r--r--app/Controller/UserCreationController.php7
-rw-r--r--app/Controller/UserInviteController.php107
-rw-r--r--app/Core/Base.php16
-rw-r--r--app/Core/DateParser.php9
-rw-r--r--app/Core/ExternalTask/ExternalTaskManager.php7
-rw-r--r--app/Core/Filter/FormatterInterface.php2
-rw-r--r--app/Core/Helper.php1
-rw-r--r--app/Core/Http/Request.php15
-rw-r--r--app/Core/Mail/Transport/Mail.php4
-rw-r--r--app/Core/Mail/Transport/Smtp.php1
-rw-r--r--app/Core/Paginator.php45
-rw-r--r--app/Core/Plugin/Base.php13
-rw-r--r--app/Core/Plugin/Directory.php13
-rw-r--r--app/Core/Plugin/Loader.php48
-rw-r--r--app/Core/Plugin/PluginException.php15
-rw-r--r--app/Core/Plugin/PluginInstallerException.php4
-rw-r--r--app/Core/Plugin/Version.php38
-rw-r--r--app/Core/Queue/QueueManager.php2
-rw-r--r--app/Core/Tool.php25
-rw-r--r--app/Formatter/BoardColumnFormatter.php2
-rw-r--r--app/Formatter/BoardFormatter.php2
-rw-r--r--app/Formatter/BoardSwimlaneFormatter.php2
-rw-r--r--app/Formatter/GroupAutoCompleteFormatter.php22
-rw-r--r--app/Formatter/UserAutoCompleteFormatter.php6
-rw-r--r--app/Helper/AppHelper.php6
-rw-r--r--app/Helper/CalendarHelper.php9
-rw-r--r--app/Helper/DateHelper.php2
-rw-r--r--app/Helper/FileHelper.php29
-rw-r--r--app/Helper/ICalHelper.php11
-rw-r--r--app/Helper/LayoutHelper.php14
-rw-r--r--app/Helper/ModalHelper.php83
-rw-r--r--app/Helper/ProjectActivityHelper.php9
-rw-r--r--app/Helper/SubtaskHelper.php8
-rw-r--r--app/Helper/TaskHelper.php63
-rw-r--r--app/Helper/UrlHelper.php33
-rw-r--r--app/Locale/bs_BA/translations.php66
-rw-r--r--app/Locale/cs_CZ/translations.php66
-rw-r--r--app/Locale/da_DK/translations.php66
-rw-r--r--app/Locale/de_DE/translations.php86
-rw-r--r--app/Locale/el_GR/translations.php66
-rw-r--r--app/Locale/es_ES/translations.php66
-rw-r--r--app/Locale/fi_FI/translations.php66
-rw-r--r--app/Locale/fr_FR/translations.php69
-rw-r--r--app/Locale/hu_HU/translations.php66
-rw-r--r--app/Locale/id_ID/translations.php1326
-rw-r--r--app/Locale/it_IT/translations.php66
-rw-r--r--app/Locale/ja_JP/translations.php66
-rw-r--r--app/Locale/ko_KR/translations.php66
-rw-r--r--app/Locale/my_MY/translations.php66
-rw-r--r--app/Locale/nb_NO/translations.php66
-rw-r--r--app/Locale/nl_NL/translations.php66
-rw-r--r--app/Locale/pl_PL/translations.php66
-rw-r--r--app/Locale/pt_BR/translations.php66
-rw-r--r--app/Locale/pt_PT/translations.php76
-rw-r--r--app/Locale/ru_RU/translations.php106
-rw-r--r--app/Locale/sr_Latn_RS/translations.php66
-rw-r--r--app/Locale/sv_SE/translations.php66
-rw-r--r--app/Locale/th_TH/translations.php66
-rw-r--r--app/Locale/tr_TR/translations.php130
-rw-r--r--app/Locale/zh_CN/translations.php66
-rw-r--r--app/Model/CommentModel.php7
-rw-r--r--app/Model/CurrencyModel.php1
-rw-r--r--app/Model/FileModel.php4
-rw-r--r--app/Model/InviteModel.php73
-rw-r--r--app/Schema/Mysql.php26
-rw-r--r--app/Schema/Postgres.php22
-rw-r--r--app/Schema/Sql/mysql.sql15
-rw-r--r--app/Schema/Sql/postgres.sql28
-rw-r--r--app/Schema/Sqlite.php22
-rw-r--r--app/ServiceProvider/AuthenticationProvider.php22
-rw-r--r--app/ServiceProvider/ClassProvider.php1
-rw-r--r--app/ServiceProvider/CommandProvider.php2
-rw-r--r--app/ServiceProvider/FilterProvider.php4
-rw-r--r--app/ServiceProvider/FormatterProvider.php48
-rw-r--r--app/ServiceProvider/HelperProvider.php1
-rw-r--r--app/ServiceProvider/RouteProvider.php5
-rw-r--r--app/Template/action/index.php12
-rw-r--r--app/Template/action/remove.php10
-rw-r--r--app/Template/action_creation/create.php10
-rw-r--r--app/Template/action_creation/event.php11
-rw-r--r--app/Template/action_creation/params.php9
-rw-r--r--app/Template/activity/project.php14
-rw-r--r--app/Template/analytic/avg_time_columns.php28
-rw-r--r--app/Template/analytic/burndown.php24
-rw-r--r--app/Template/analytic/cfd.php24
-rw-r--r--app/Template/analytic/layout.php18
-rw-r--r--app/Template/analytic/lead_cycle_time.php26
-rw-r--r--app/Template/analytic/sidebar.php15
-rw-r--r--app/Template/analytic/task_distribution.php8
-rw-r--r--app/Template/analytic/time_comparison.php16
-rw-r--r--app/Template/analytic/user_distribution.php8
-rw-r--r--app/Template/board/table_column.php9
-rw-r--r--app/Template/board/task_footer.php2
-rw-r--r--app/Template/board/tooltip_files.php4
-rw-r--r--app/Template/board_popover/close_all_tasks_column.php29
-rw-r--r--app/Template/category/edit.php9
-rw-r--r--app/Template/category/index.php6
-rw-r--r--app/Template/category/remove.php28
-rw-r--r--app/Template/column/create.php9
-rw-r--r--app/Template/column/edit.php9
-rw-r--r--app/Template/column/index.php15
-rw-r--r--app/Template/column/remove.php9
-rw-r--r--app/Template/column_move_restriction/create.php34
-rw-r--r--app/Template/column_move_restriction/remove.php9
-rw-r--r--app/Template/column_restriction/create.php32
-rw-r--r--app/Template/column_restriction/remove.php9
-rw-r--r--app/Template/comment/create.php8
-rw-r--r--app/Template/comment/edit.php8
-rw-r--r--app/Template/comment/remove.php10
-rw-r--r--app/Template/comment/show.php10
-rw-r--r--app/Template/comments/show.php3
-rw-r--r--app/Template/config/about.php8
-rw-r--r--app/Template/config/api.php12
-rw-r--r--app/Template/config/application.php40
-rw-r--r--app/Template/config/board.php21
-rw-r--r--app/Template/config/calendar.php28
-rw-r--r--app/Template/config/email.php11
-rw-r--r--app/Template/config/integrations.php8
-rw-r--r--app/Template/config/keyboard_shortcuts.php2
-rw-r--r--app/Template/config/project.php29
-rw-r--r--app/Template/config/sidebar.php6
-rw-r--r--app/Template/config/webhook.php22
-rw-r--r--app/Template/currency/change.php9
-rw-r--r--app/Template/currency/create.php11
-rw-r--r--app/Template/currency/index.php54
-rw-r--r--app/Template/currency/show.php34
-rw-r--r--app/Template/custom_filter/create.php (renamed from app/Template/custom_filter/add.php)9
-rw-r--r--app/Template/custom_filter/edit.php11
-rw-r--r--app/Template/custom_filter/index.php16
-rw-r--r--app/Template/custom_filter/remove.php28
-rw-r--r--app/Template/dashboard/layout.php12
-rw-r--r--app/Template/dashboard/notifications.php6
-rw-r--r--app/Template/dashboard/show.php2
-rw-r--r--app/Template/doc/show.php3
-rw-r--r--app/Template/export/header.php17
-rw-r--r--app/Template/export/sidebar.php17
-rw-r--r--app/Template/export/subtasks.php16
-rw-r--r--app/Template/export/summary.php16
-rw-r--r--app/Template/export/tasks.php16
-rw-r--r--app/Template/export/transitions.php17
-rw-r--r--app/Template/external_task_creation/step1.php7
-rw-r--r--app/Template/external_task_creation/step2.php7
-rw-r--r--app/Template/external_task_modification/show.php8
-rw-r--r--app/Template/group/associate.php13
-rw-r--r--app/Template/group/dissociate.php10
-rw-r--r--app/Template/group/index.php14
-rw-r--r--app/Template/group/remove.php10
-rw-r--r--app/Template/group/users.php7
-rw-r--r--app/Template/group_creation/show.php8
-rw-r--r--app/Template/group_modification/show.php8
-rw-r--r--app/Template/header/creation_dropdown.php7
-rw-r--r--app/Template/header/user_dropdown.php27
-rw-r--r--app/Template/layout.php1
-rw-r--r--app/Template/link/create.php12
-rw-r--r--app/Template/link/edit.php6
-rw-r--r--app/Template/link/index.php33
-rw-r--r--app/Template/link/remove.php10
-rw-r--r--app/Template/link/show.php36
-rw-r--r--app/Template/plugin/directory.php6
-rw-r--r--app/Template/plugin/remove.php10
-rw-r--r--app/Template/plugin/show.php43
-rw-r--r--app/Template/project/dropdown.php23
-rw-r--r--app/Template/project/sidebar.php10
-rw-r--r--app/Template/project_action_duplication/show.php8
-rw-r--r--app/Template/project_creation/create.php8
-rw-r--r--app/Template/project_edit/dates.php22
-rw-r--r--app/Template/project_edit/description.php19
-rw-r--r--app/Template/project_edit/general.php36
-rw-r--r--app/Template/project_edit/show.php58
-rw-r--r--app/Template/project_edit/task_priority.php29
-rw-r--r--app/Template/project_file/create.php43
-rw-r--r--app/Template/project_file/remove.php10
-rw-r--r--app/Template/project_gantt/show.php16
-rw-r--r--app/Template/project_header/dropdown.php35
-rw-r--r--app/Template/project_header/views.php15
-rw-r--r--app/Template/project_list/show.php18
-rw-r--r--app/Template/project_overview/attachments.php2
-rw-r--r--app/Template/project_overview/description.php4
-rw-r--r--app/Template/project_overview/files.php13
-rw-r--r--app/Template/project_overview/images.php6
-rw-r--r--app/Template/project_overview/information.php8
-rw-r--r--app/Template/project_overview/show.php1
-rw-r--r--app/Template/project_permission/groups.php5
-rw-r--r--app/Template/project_permission/users.php5
-rw-r--r--app/Template/project_role/create.php8
-rw-r--r--app/Template/project_role/edit.php8
-rw-r--r--app/Template/project_role/remove.php9
-rw-r--r--app/Template/project_role/show.php27
-rw-r--r--app/Template/project_role_restriction/create.php8
-rw-r--r--app/Template/project_role_restriction/remove.php9
-rw-r--r--app/Template/project_status/disable.php9
-rw-r--r--app/Template/project_status/enable.php9
-rw-r--r--app/Template/project_status/remove.php9
-rw-r--r--app/Template/project_tag/create.php8
-rw-r--r--app/Template/project_tag/edit.php8
-rw-r--r--app/Template/project_tag/index.php9
-rw-r--r--app/Template/project_tag/remove.php10
-rw-r--r--app/Template/project_user_overview/layout.php17
-rw-r--r--app/Template/project_view/share.php8
-rw-r--r--app/Template/project_view/show.php8
-rw-r--r--app/Template/search/activity.php5
-rw-r--r--app/Template/search/index.php5
-rw-r--r--app/Template/subtask/create.php15
-rw-r--r--app/Template/subtask/edit.php21
-rw-r--r--app/Template/subtask/menu.php9
-rw-r--r--app/Template/subtask/remove.php10
-rw-r--r--app/Template/subtask/table.php6
-rw-r--r--app/Template/subtask_converter/show.php10
-rw-r--r--app/Template/subtask_restriction/show.php8
-rw-r--r--app/Template/swimlane/create.php8
-rw-r--r--app/Template/swimlane/edit.php8
-rw-r--r--app/Template/swimlane/edit_default.php8
-rw-r--r--app/Template/swimlane/index.php3
-rw-r--r--app/Template/swimlane/remove.php28
-rw-r--r--app/Template/swimlane/table.php21
-rw-r--r--app/Template/tag/create.php8
-rw-r--r--app/Template/tag/edit.php8
-rw-r--r--app/Template/tag/index.php9
-rw-r--r--app/Template/tag/remove.php10
-rw-r--r--app/Template/task/analytics.php2
-rw-r--r--app/Template/task/details.php8
-rw-r--r--app/Template/task/dropdown.php39
-rw-r--r--app/Template/task/sidebar.php60
-rw-r--r--app/Template/task/time_tracking_summary.php20
-rw-r--r--app/Template/task_bulk/show.php13
-rw-r--r--app/Template/task_creation/duplicate_projects.php9
-rw-r--r--app/Template/task_creation/show.php62
-rw-r--r--app/Template/task_duplication/copy.php30
-rw-r--r--app/Template/task_duplication/duplicate.php10
-rw-r--r--app/Template/task_duplication/move.php29
-rw-r--r--app/Template/task_external_link/create.php9
-rw-r--r--app/Template/task_external_link/edit.php9
-rw-r--r--app/Template/task_external_link/find.php8
-rw-r--r--app/Template/task_external_link/remove.php10
-rw-r--r--app/Template/task_external_link/table.php6
-rw-r--r--app/Template/task_file/create.php43
-rw-r--r--app/Template/task_file/files.php12
-rw-r--r--app/Template/task_file/images.php8
-rw-r--r--app/Template/task_file/remove.php10
-rw-r--r--app/Template/task_file/screenshot.php10
-rw-r--r--app/Template/task_gantt/show.php9
-rw-r--r--app/Template/task_gantt_creation/show.php46
-rw-r--r--app/Template/task_import/show.php15
-rw-r--r--app/Template/task_import/sidebar.php8
-rw-r--r--app/Template/task_internal_link/create.php8
-rw-r--r--app/Template/task_internal_link/edit.php6
-rw-r--r--app/Template/task_internal_link/remove.php10
-rw-r--r--app/Template/task_internal_link/table.php6
-rw-r--r--app/Template/task_modification/show.php44
-rw-r--r--app/Template/task_move_position/show.php6
-rw-r--r--app/Template/task_recurrence/edit.php10
-rw-r--r--app/Template/task_status/close.php10
-rw-r--r--app/Template/task_status/open.php10
-rw-r--r--app/Template/task_suppression/remove.php10
-rw-r--r--app/Template/twofactor/disable.php9
-rw-r--r--app/Template/twofactor/show.php2
-rw-r--r--app/Template/user_creation/remote.php51
-rw-r--r--app/Template/user_creation/show.php67
-rw-r--r--app/Template/user_credential/authentication.php12
-rw-r--r--app/Template/user_credential/password.php14
-rw-r--r--app/Template/user_import/show.php9
-rw-r--r--app/Template/user_invite/email.php12
-rw-r--r--app/Template/user_invite/show.php15
-rw-r--r--app/Template/user_invite/signup.php (renamed from app/Template/user_creation/local.php)47
-rw-r--r--app/Template/user_list/dropdown.php12
-rw-r--r--app/Template/user_list/show.php16
-rw-r--r--app/Template/user_modification/show.php33
-rw-r--r--app/Template/user_status/disable.php10
-rw-r--r--app/Template/user_status/enable.php10
-rw-r--r--app/Template/user_status/remove.php10
-rw-r--r--app/Template/user_view/layout.php17
-rw-r--r--app/Template/user_view/profile.php14
-rw-r--r--app/Template/user_view/share.php6
-rw-r--r--app/Template/user_view/show.php16
-rw-r--r--app/Validator/ProjectValidator.php12
-rw-r--r--app/Validator/TaskValidator.php2
-rw-r--r--app/Validator/UserValidator.php2
-rw-r--r--app/common.php1
-rw-r--r--app/functions.php11
-rw-r--r--assets/css/app.min.css2
-rw-r--r--assets/js/app.min.js5
-rw-r--r--assets/js/components/accordion.js9
-rw-r--r--assets/js/components/chart-task-time-column.js3
-rw-r--r--assets/js/components/confirm-buttons.js (renamed from assets/js/components/submit-cancel.js)24
-rw-r--r--assets/js/components/file-upload.js195
-rw-r--r--assets/js/components/form-export.js9
-rw-r--r--assets/js/components/image-slideshow.js8
-rw-r--r--assets/js/components/keyboard-shortcuts.js135
-rw-r--r--assets/js/components/modal.js39
-rw-r--r--assets/js/components/screenshot.js122
-rw-r--r--assets/js/components/select-dropdown-autocomplete.js89
-rw-r--r--assets/js/components/submit-buttons.js102
-rw-r--r--assets/js/components/suggest-menu.js12
-rw-r--r--assets/js/components/task-move-position.js6
-rw-r--r--assets/js/core/base.js71
-rw-r--r--assets/js/core/bootstrap.js1
-rw-r--r--assets/js/core/dom.js30
-rw-r--r--assets/js/core/http.js38
-rw-r--r--assets/js/core/modal.js173
-rw-r--r--assets/js/core/utils.js62
-rw-r--r--assets/js/polyfills/event_key.js113
-rw-r--r--assets/js/src/App.js37
-rw-r--r--assets/js/src/BoardCollapsedMode.js10
-rw-r--r--assets/js/src/BoardHorizontalScrolling.js10
-rw-r--r--assets/js/src/BoardTask.js13
-rw-r--r--assets/js/src/Dropdown.js9
-rw-r--r--assets/js/src/FileUpload.js125
-rw-r--r--assets/js/src/Popover.js161
-rw-r--r--assets/js/src/Screenshot.js134
-rw-r--r--assets/js/src/Search.js58
-rw-r--r--assets/js/src/Task.js48
-rw-r--r--assets/js/vendor.min.js14
-rw-r--r--assets/sass/_base.sass9
-rw-r--r--assets/sass/_board.sass5
-rw-r--r--assets/sass/_dialog_box.sass4
-rw-r--r--assets/sass/_file_upload.sass2
-rw-r--r--assets/sass/_form.sass22
-rw-r--r--assets/sass/_links.sass4
-rw-r--r--assets/sass/_markdown_editor.sass10
-rw-r--r--assets/sass/_modal.sass (renamed from assets/sass/_popover.sass)23
-rw-r--r--assets/sass/_pagination.sass5
-rw-r--r--assets/sass/_panel.sass (renamed from assets/sass/_listing.sass)12
-rw-r--r--assets/sass/_select_dropdown.sass6
-rw-r--r--assets/sass/_task_form.sass32
-rw-r--r--assets/sass/_thumbnails.sass2
-rw-r--r--assets/sass/app.sass6
-rw-r--r--bower.json1
-rw-r--r--composer.json2
-rw-r--r--composer.lock113
-rw-r--r--config.default.php4
-rw-r--r--doc/api-json-rpc.markdown1
-rw-r--r--doc/api-tags-procedures.markdown195
-rw-r--r--doc/api-task-procedures.markdown22
-rw-r--r--doc/automatic-actions.markdown28
-rw-r--r--doc/board-collapsed-expanded.markdown2
-rw-r--r--doc/board-show-hide-columns.markdown2
-rw-r--r--doc/cli.markdown7
-rw-r--r--doc/creating-projects.markdown10
-rw-r--r--doc/editing-projects.markdown14
-rw-r--r--doc/es_ES/kanban-vs-todo-and-scrum.markdown2
-rw-r--r--doc/installation.markdown2
-rw-r--r--doc/kanban-vs-todo-and-scrum.markdown10
-rw-r--r--doc/mysql-configuration.markdown24
-rw-r--r--doc/nice-urls.markdown45
-rw-r--r--doc/plugin-helpers.markdown2
-rw-r--r--doc/plugin-hooks.markdown4
-rw-r--r--doc/plugin-overrides.markdown31
-rw-r--r--doc/plugin-registration.markdown10
-rw-r--r--doc/project-permissions.markdown12
-rw-r--r--doc/project-views.markdown20
-rw-r--r--doc/removing-projects.markdown4
-rw-r--r--doc/search.markdown4
-rw-r--r--doc/sharing-projects.markdown16
-rw-r--r--doc/suse-installation.markdown2
-rw-r--r--doc/usage-examples.markdown4
-rw-r--r--doc/what-is-kanban.markdown20
-rw-r--r--gulpfile.js3
-rw-r--r--package.json13
-rw-r--r--tests/integration/CommentProcedureTest.php3
-rw-r--r--tests/integration/TaskTagProcedureTest.php27
-rw-r--r--tests/units.postgres.xml2
-rw-r--r--tests/units/Base.php1
-rw-r--r--tests/units/Core/DateParserTest.php9
-rw-r--r--tests/units/Core/ExternalTask/ExternalTaskManagerTest.php6
-rw-r--r--tests/units/Core/Http/RequestTest.php3
-rw-r--r--tests/units/Core/Plugin/VersionTest.php29
-rw-r--r--tests/units/Helper/FileHelperTest.php (renamed from tests/units/Helper/FileHelperText.php)9
-rw-r--r--tests/units/Helper/TaskHelperTest.php6
-rw-r--r--tests/units/Model/CommentModelTest.php3
-rw-r--r--tests/units/Model/InviteModelTest.php27
-rw-r--r--tests/units/ServiceProvider/ClassProviderTest.php21
-rw-r--r--tests/units/ServiceProvider/FormatterProviderTest.php21
-rw-r--r--yarn.lock2413
415 files changed, 8578 insertions, 4362 deletions
diff --git a/.gitattributes b/.gitattributes
index 71b22659..d3dac044 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,10 +2,10 @@ app/constants.php export-subst
.gitattributes export-ignore
.gitignore export-ignore
-
.docker export-ignore
.scrutinizer.yml export-ignore
.travis.yml export-ignore
+yarn.lock export-ignore
Dockerfile export-ignore
docker-compose.yml export-ignore
Makefile export-ignore
diff --git a/.github/issue_template.md b/.github/issue_template.md
index 3aede7f5..8155eeb1 100644
--- a/.github/issue_template.md
+++ b/.github/issue_template.md
@@ -1,23 +1,30 @@
-### Expected behaviour
-
-Tell us what should happen
+**Please, do not create duplicate issues**
### Actual behaviour
-Tell us what happens instead
+Tell us what happens
+
+
+### Expected behaviour
+
+Tell us what should actually happen
### Steps to reproduce
-1.
-2.
-3.
+Please supply step-by-step instructions so that anyone with the same environment can reproduce the issue. Whenever you offer a description, imagine
+yourself in the shoes of someone who has never encountered this problem before and would like to know exactly how to observe it under a given set of conditions.
+Here is an example:
+
+1. Log in to the application as the administrative user
+2. Click on button X, then on the modal dialog that appears, click Y
+3. Wait for 3 seconds, and note the appearance of an unexpected message
### Configuration
-Copy and paste the configuration section from the Kanboard settings page or fill these fields:
+Copy and paste the configuration section from the Kanboard settings page or supply values for these fields:
- Kanboard version:
- Database type and version:
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index be59deac..9756a6e7 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,8 +1,8 @@
Before to submit your pull-request:
- Be sure that the unit tests pass
-- If you create a new feature, test your code, do not introduce new bugs
+- If you create a new feature, test your code, and do not introduce new bugs
- Avoid code duplication
-- Small pull-requests are easier to review and can be merged quickly
+- Remember, small pull-requests are easier to review and can be merged quickly
- 1 pull-request == 1 feature/improvement
-- Non necessary features should be implemented as plugin
+- Nonessential features should be implemented as plugin
diff --git a/.htaccess b/.htaccess
index 9da74f57..24bfe9be 100644
--- a/.htaccess
+++ b/.htaccess
@@ -3,6 +3,9 @@
SetEnv HTTP_MOD_REWRITE On
+ # Uncomment this line depending of your Apache configuration
+ # RewriteBase /
+
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
@@ -14,3 +17,7 @@
# RewriteCond %{HTTPS} !=on
# RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
</IfModule>
+
+<IfModule pagespeed_module>
+ ModPagespeed Off
+</IfModule>
diff --git a/.travis.yml b/.travis.yml
index 8c78bf8b..e9ee6098 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,8 +25,8 @@ before_script:
- phpenv config-add tests/php.ini
- composer install
- npm install
- - ./node_modules/.bin/jshint assets/js/{core,components}
script:
+ - ./node_modules/.bin/jshint assets/js/{core,components}
- phpunit -c tests/units.$DB.xml
- phpunit tests/configtest
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 199a161c..f945a84d 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -15,6 +15,7 @@ Contributors:
- [Ashbike](https://github.com/ashbike)
- [Ashish Kulkarni](https://github.com/ashkulz)
- [António Pereira](https://github.com/Shaxine)
+- [Bernhard Kau](https://github.com/2ndkauboy)
- [Biniou180](https://github.com/Biniou180)
- [Bitcoin 333](https://github.com/bitcoin333)
- [Busfreak](https://github.com/Busfreak)
@@ -77,6 +78,7 @@ Contributors:
- [Łukasz Klim](https://github.com/lukas346)
- [Maces](https://github.com/maces)
- [Manish Lad](https://github.com/manishlad)
+- [Mark Szymanski](https://github.com/markjszy)
- [Mathgl67](https://github.com/mathgl67)
- [Matthieu Keller](https://github.com/maggick)
- [Mauro Mariño](https://github.com/moromarino)
@@ -145,6 +147,7 @@ Contributors:
- [Vedovator](https://github.com/vedovator)
- [Vitaliy S. Orlov](https://github.com/orlov0562)
- [Vladimir Babin](https://github.com/Chiliec)
+- [Volodymyr Kushnir](https://github.com/volodymyr-kushnir)
- [Yannick Ihmels](https://github.com/ihmels)
- [Yakovenkov](https://github.com/yakovenkov)
- [Ybarc](https://github.com/ybarc)
diff --git a/ChangeLog b/ChangeLog
index cf6d7209..87eef5ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,20 +1,91 @@
-Version 1.0.36 (unreleased)
----------------------------
+Version 1.0.38 (Jan 28, 2017)
+-----------------------------
+
+New features:
+
+* User invitations by email
+
+Improvements:
+
+* Simplify user creation form
+* Add modification date for comments
+* Add project creation links to project management pages
+* More API procedures are now available to project members and project viewers
+* Simplify date and time configuration to avoid potential validation issues
+* Show dashboard column visibility in columns page
+* Add new template hooks
+* Update translations (id_ID, de_DE, ru_RU, fr_FR, pt_PT)
+* Add command to execute individual job (mostly for debugging)
+
+Regressions:
+
+* Stay on the same page when a task is closed
+* Wrong URL in modal to move task to another project
+
+Bug fixes:
+
+* Fix broken link when clicking on user avatar for tasks on board
+* Fix wrong datetime formatting when task form shows validation errors
+* Empty arrays are serialized to a list instead of a dict (Json API)
+* Always unbind internal listeners when closing a modal dialog
+* Fix installation errors on MySQL 8.0.0 (unescaped reserved keyword)
+* Avoid PHP notice when column form validation failed
+* Fix wrong default value for add group member modal
+* Add missing filter (completed) for task search
+
+Version 1.0.37 (Jan 14, 2017)
+-----------------------------
+
+Improvements:
+
+* Improve keyboard shortcuts handling
+* Improve auto-complete dropdown elements sorting
+* Larger task form
+* Rewrite dialog and confirmation boxes (inline popups)
+* Remove TaskGanttCreationController
+* Add helpers to open modal boxes
+* Make icons clickable in menus
+* Open task imports in modal box
+* Open form to create customer filters in modal box
+* Open project activities in modal box
+* Display project analytics in modal box
+* Display project exports in modal box
+* Improve accordion component
+* Improve currencies page navigation
+* Improve link labels page navigation
+* Improve settings page layout
+* Offer the possibility to define version compatibility from plugins
+* Add task creation event to the automatic action to send task by email
+
+Bug fixes:
+
+* Closing screenshot dialog prevent input elements to get focus
+
+Version 1.0.36 (Dec 30, 2016)
+-----------------------------
New features:
* Add slideshow for images
* Add API calls to manage tags
+* Offer the possibility to override internal formatter objects from plugins
+* Open PDF attachments in browser tab (preview)
Improvements:
+* Add pagination details
* Handle username with dots in user mentions
-* Replace Chosen jQuery plugin by custom UI component
* Rewrite UI component that change user/group roles
+* Replace Chosen jQuery plugin by custom UI component
+* Remove dependency on Mousetrap Javascript library
+* Disable PageSpeed module from .htaccess if present
+* Add currency of Chinese Yuan
Bug fixes:
+* Fix compatibility issue with PHP 5.3 for array_combine function
* Fix wrong controller name on project activity page when using filters
+* Uploaded avatar images are now visible in public board view
Version 1.0.35 (Dec 4, 2016)
----------------------------
diff --git a/LICENSE b/LICENSE
index c1efa204..15ce8eb5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2014-2016 Frédéric Guillot
+Copyright (c) 2014-2017 Frédéric Guillot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index 985aded7..42b1cdc9 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ clean:
@ rm -rf ./node_modules ./bower_components
static: clean
- @ npm install
+ @ yarn install || npm install
@ ./node_modules/.bin/gulp bower
@ ./node_modules/.bin/gulp vendor js css
@ ./node_modules/.bin/jshint assets/js/{core,components,polyfills}
diff --git a/README.md b/README.md
index d14982f0..bdd0d66b 100644
--- a/README.md
+++ b/README.md
@@ -4,15 +4,15 @@ Kanboard
[![Build Status](https://travis-ci.org/kanboard/kanboard.svg?branch=master)](https://travis-ci.org/kanboard/kanboard)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/kanboard/kanboard/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/kanboard/kanboard/?branch=master)
-Kanboard is a project management software that focus on the Kanban methodology.
+Kanboard is project management software that focuses on the Kanban methodology.
Official website: <https://kanboard.net>
-- Get a visual and clear overview of your project
+- Get a clear visual overview of your project
- Multiple boards with the ability to drag and drop tasks
- Open source and self-hosted
- Super simple installation
-- Translated in many languages
+- Translated into many languages
- Distributed under [MIT License](https://github.com/kanboard/kanboard/blob/master/LICENSE)
- The complete [list of features are available on the website](https://kanboard.net/features)
- [Change Log](https://github.com/kanboard/kanboard/blob/master/ChangeLog)
diff --git a/app/Action/TaskEmail.php b/app/Action/TaskEmail.php
index fdfe7987..559c2c0b 100644
--- a/app/Action/TaskEmail.php
+++ b/app/Action/TaskEmail.php
@@ -34,6 +34,7 @@ class TaskEmail extends Base
return array(
TaskModel::EVENT_MOVE_COLUMN,
TaskModel::EVENT_CLOSE,
+ TaskModel::EVENT_CREATE,
);
}
diff --git a/app/Api/Procedure/ActionProcedure.php b/app/Api/Procedure/ActionProcedure.php
index 4043dbb9..72fb9bbe 100644
--- a/app/Api/Procedure/ActionProcedure.php
+++ b/app/Api/Procedure/ActionProcedure.php
@@ -15,17 +15,17 @@ class ActionProcedure extends BaseProcedure
{
public function getAvailableActions()
{
- return $this->actionManager->getAvailableActions();
+ return (object) $this->actionManager->getAvailableActions();
}
public function getAvailableActionEvents()
{
- return $this->eventManager->getAll();
+ return (object) $this->eventManager->getAll();
}
public function getCompatibleActionEvents($action_name)
{
- return $this->actionManager->getCompatibleEvents($action_name);
+ return (object) $this->actionManager->getCompatibleEvents($action_name);
}
public function removeAction($action_id)
diff --git a/app/Api/Procedure/BoardProcedure.php b/app/Api/Procedure/BoardProcedure.php
index 674b5466..69daaf09 100644
--- a/app/Api/Procedure/BoardProcedure.php
+++ b/app/Api/Procedure/BoardProcedure.php
@@ -3,7 +3,6 @@
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
-use Kanboard\Formatter\BoardFormatter;
/**
* Board API controller
@@ -17,7 +16,7 @@ class BoardProcedure extends BaseProcedure
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getBoard', $project_id);
- return BoardFormatter::getInstance($this->container)
+ return $this->boardFormatter
->withProjectId($project_id)
->withQuery($this->taskFinderModel->getExtendedQuery())
->format();
diff --git a/app/Api/Procedure/MeProcedure.php b/app/Api/Procedure/MeProcedure.php
index e59e6522..71d5555b 100644
--- a/app/Api/Procedure/MeProcedure.php
+++ b/app/Api/Procedure/MeProcedure.php
@@ -54,7 +54,7 @@ class MeProcedure extends BaseProcedure
public function getMyProjectsList()
{
- return $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId());
+ return (object) $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId());
}
public function getMyOverdueTasks()
diff --git a/app/Api/Procedure/ProjectPermissionProcedure.php b/app/Api/Procedure/ProjectPermissionProcedure.php
index e22e1d62..1938a067 100644
--- a/app/Api/Procedure/ProjectPermissionProcedure.php
+++ b/app/Api/Procedure/ProjectPermissionProcedure.php
@@ -16,13 +16,13 @@ class ProjectPermissionProcedure extends BaseProcedure
public function getProjectUsers($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUsers', $project_id);
- return $this->projectUserRoleModel->getAllUsers($project_id);
+ return (object) $this->projectUserRoleModel->getAllUsers($project_id);
}
public function getAssignableUsers($project_id, $prepend_unassigned = false)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAssignableUsers', $project_id);
- return $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned);
+ return (object) $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned);
}
public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER)
diff --git a/app/Api/Procedure/TaskMetadataProcedure.php b/app/Api/Procedure/TaskMetadataProcedure.php
index 169482f5..ab6c32d0 100644
--- a/app/Api/Procedure/TaskMetadataProcedure.php
+++ b/app/Api/Procedure/TaskMetadataProcedure.php
@@ -15,7 +15,7 @@ class TaskMetadataProcedure extends BaseProcedure
public function getTaskMetadata($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTask', $task_id);
- return $this->taskMetadataModel->getAll($task_id);
+ return (object) $this->taskMetadataModel->getAll($task_id);
}
public function getTaskMetadataByName($task_id, $name)
diff --git a/app/Api/Procedure/TaskProcedure.php b/app/Api/Procedure/TaskProcedure.php
index ee9242d1..af67f3de 100644
--- a/app/Api/Procedure/TaskProcedure.php
+++ b/app/Api/Procedure/TaskProcedure.php
@@ -87,9 +87,9 @@ class TaskProcedure extends BaseProcedure
}
public function createTask($title, $project_id, $color_id = '', $column_id = 0, $owner_id = 0, $creator_id = 0,
- $date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0, $priority = 0,
- $recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
- $recurrence_basedate = 0, $reference = '')
+ $date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0, $priority = 0,
+ $recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
+ $recurrence_basedate = 0, $reference = '', array $tags = array())
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTask', $project_id);
@@ -120,6 +120,7 @@ class TaskProcedure extends BaseProcedure
'recurrence_basedate' => $recurrence_basedate,
'reference' => $reference,
'priority' => $priority,
+ 'tags' => $tags,
);
list($valid, ) = $this->taskValidator->validateCreation($values);
@@ -128,9 +129,9 @@ class TaskProcedure extends BaseProcedure
}
public function updateTask($id, $title = null, $color_id = null, $owner_id = null,
- $date_due = null, $description = null, $category_id = null, $score = null, $priority = null,
- $recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
- $recurrence_timeframe = null, $recurrence_basedate = null, $reference = null)
+ $date_due = null, $description = null, $category_id = null, $score = null, $priority = null,
+ $recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
+ $recurrence_timeframe = null, $recurrence_basedate = null, $reference = null, $tags = null)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTask', $id);
$project_id = $this->taskFinderModel->getProjectId($id);
@@ -159,6 +160,7 @@ class TaskProcedure extends BaseProcedure
'recurrence_basedate' => $recurrence_basedate,
'reference' => $reference,
'priority' => $priority,
+ 'tags' => $tags,
));
list($valid) = $this->taskValidator->validateApiModification($values);
diff --git a/app/Api/Procedure/TaskTagProcedure.php b/app/Api/Procedure/TaskTagProcedure.php
index 8596f507..55dac8d4 100644
--- a/app/Api/Procedure/TaskTagProcedure.php
+++ b/app/Api/Procedure/TaskTagProcedure.php
@@ -21,6 +21,6 @@ class TaskTagProcedure extends BaseProcedure
public function getTaskTags($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskTags', $task_id);
- return $this->taskTagModel->getList($task_id);
+ return (object) $this->taskTagModel->getList($task_id);
}
}
diff --git a/app/Console/JobCommand.php b/app/Console/JobCommand.php
new file mode 100644
index 00000000..bdaae32f
--- /dev/null
+++ b/app/Console/JobCommand.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Kanboard\Console;
+
+use Kanboard\Core\Queue\JobHandler;
+use SimpleQueue\Job;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class JobCommand
+ *
+ * @package Kanboard\Console
+ * @author Frederic Guillot
+ */
+class JobCommand extends BaseCommand
+{
+ protected function configure()
+ {
+ $this
+ ->setName('job')
+ ->setDescription('Execute individual job (read payload from stdin)')
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $payload = fgets(STDIN);
+
+ $job = new Job();
+ $job->unserialize($payload);
+
+ JobHandler::getInstance($this->container)->executeJob($job);
+ }
+}
diff --git a/app/Controller/BoardAjaxController.php b/app/Controller/BoardAjaxController.php
index 484ef67d..ecb76e9c 100644
--- a/app/Controller/BoardAjaxController.php
+++ b/app/Controller/BoardAjaxController.php
@@ -3,7 +3,6 @@
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
-use Kanboard\Formatter\BoardFormatter;
use Kanboard\Model\UserMetadataModel;
/**
@@ -139,7 +138,7 @@ class BoardAjaxController extends BaseController
'board_highlight_period' => $this->configModel->get('board_highlight_period'),
'swimlanes' => $this->taskLexer
->build($this->userSession->getFilters($project_id))
- ->format(BoardFormatter::getInstance($this->container)->withProjectId($project_id))
+ ->format($this->boardFormatter->withProjectId($project_id))
));
}
}
diff --git a/app/Controller/BoardViewController.php b/app/Controller/BoardViewController.php
index 10165908..9ef77e54 100644
--- a/app/Controller/BoardViewController.php
+++ b/app/Controller/BoardViewController.php
@@ -3,7 +3,6 @@
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
-use Kanboard\Formatter\BoardFormatter;
use Kanboard\Model\TaskModel;
/**
@@ -35,7 +34,7 @@ class BoardViewController extends BaseController
$this->response->html($this->helper->layout->app('board/view_public', array(
'project' => $project,
- 'swimlanes' => BoardFormatter::getInstance($this->container)
+ 'swimlanes' => $this->boardFormatter
->withProjectId($project['id'])
->withQuery($query)
->format()
@@ -68,7 +67,7 @@ class BoardViewController extends BaseController
'board_highlight_period' => $this->configModel->get('board_highlight_period'),
'swimlanes' => $this->taskLexer
->build($search)
- ->format(BoardFormatter::getInstance($this->container)->withProjectId($project['id']))
+ ->format($this->boardFormatter->withProjectId($project['id']))
)));
}
}
diff --git a/app/Controller/ColumnController.php b/app/Controller/ColumnController.php
index 8c366c6e..69167976 100644
--- a/app/Controller/ColumnController.php
+++ b/app/Controller/ColumnController.php
@@ -60,7 +60,7 @@ class ColumnController extends BaseController
public function save()
{
$project = $this->getProject();
- $values = $this->request->getValues();
+ $values = $this->request->getValues() + array('hide_in_dashboard' => 0);
list($valid, $errors) = $this->columnValidator->validateCreation($values);
@@ -70,18 +70,19 @@ class ColumnController extends BaseController
$values['title'],
$values['task_limit'],
$values['description'],
- isset($values['hide_in_dashboard']) ? $values['hide_in_dashboard'] : 0
+ $values['hide_in_dashboard']
);
if ($result !== false) {
$this->flash->success(t('Column created successfully.'));
- return $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id'])), true);
+ $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id'])), true);
+ return;
} else {
$errors['title'] = array(t('Another column with the same name exists in the project'));
}
}
- return $this->create($values, $errors);
+ $this->create($values, $errors);
}
/**
@@ -112,7 +113,7 @@ class ColumnController extends BaseController
public function update()
{
$project = $this->getProject();
- $values = $this->request->getValues();
+ $values = $this->request->getValues() + array('hide_in_dashboard' => 0);
list($valid, $errors) = $this->columnValidator->validateModification($values);
@@ -122,18 +123,19 @@ class ColumnController extends BaseController
$values['title'],
$values['task_limit'],
$values['description'],
- isset($values['hide_in_dashboard']) ? $values['hide_in_dashboard'] : 0
+ $values['hide_in_dashboard']
);
if ($result) {
$this->flash->success(t('Board updated successfully.'));
- return $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id'])));
+ $this->response->redirect($this->helper->url->to('ColumnController', 'index', array('project_id' => $project['id'])), true);
+ return;
} else {
$this->flash->failure(t('Unable to update this board.'));
}
}
- return $this->edit($values, $errors);
+ $this->edit($values, $errors);
}
/**
diff --git a/app/Controller/ConfigController.php b/app/Controller/ConfigController.php
index 8285ee13..8572316e 100644
--- a/app/Controller/ConfigController.php
+++ b/app/Controller/ConfigController.php
@@ -76,7 +76,6 @@ class ConfigController extends BaseController
'languages' => $this->languageModel->getLanguages(),
'timezones' => $this->timezoneModel->getTimezones(),
'date_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateFormats()),
- 'datetime_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getDateTimeFormats()),
'time_formats' => $this->dateParser->getAvailableFormats($this->dateParser->getTimeFormats()),
'title' => t('Settings').' &gt; '.t('Application settings'),
)));
diff --git a/app/Controller/CurrencyController.php b/app/Controller/CurrencyController.php
index ad590035..155e229e 100644
--- a/app/Controller/CurrencyController.php
+++ b/app/Controller/CurrencyController.php
@@ -11,21 +11,33 @@ namespace Kanboard\Controller;
class CurrencyController extends BaseController
{
/**
- * Display all currency rates and form
+ * Display all currency rates
+ *
+ * @access public
+ */
+ public function show()
+ {
+ $this->response->html($this->helper->layout->config('currency/show', array(
+ 'application_currency' => $this->configModel->get('application_currency'),
+ 'rates' => $this->currencyModel->getAll(),
+ 'currencies' => $this->currencyModel->getCurrencies(),
+ 'title' => t('Settings') . ' &gt; ' . t('Currency rates'),
+ )));
+ }
+
+ /**
+ * Add or change currency rate
*
* @access public
* @param array $values
* @param array $errors
*/
- public function index(array $values = array(), array $errors = array())
+ public function create(array $values = array(), array $errors = array())
{
- $this->response->html($this->helper->layout->config('currency/index', array(
- 'config_values' => array('application_currency' => $this->configModel->get('application_currency')),
- 'values' => $values,
- 'errors' => $errors,
- 'rates' => $this->currencyModel->getAll(),
+ $this->response->html($this->template->render('currency/create', array(
+ 'values' => $values,
+ 'errors' => $errors,
'currencies' => $this->currencyModel->getCurrencies(),
- 'title' => t('Settings').' &gt; '.t('Currency rates'),
)));
}
@@ -34,7 +46,7 @@ class CurrencyController extends BaseController
*
* @access public
*/
- public function create()
+ public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->currencyValidator->validateCreation($values);
@@ -42,13 +54,34 @@ class CurrencyController extends BaseController
if ($valid) {
if ($this->currencyModel->create($values['currency'], $values['rate'])) {
$this->flash->success(t('The currency rate have been added successfully.'));
- return $this->response->redirect($this->helper->url->to('CurrencyController', 'index'));
+ $this->response->redirect($this->helper->url->to('CurrencyController', 'show'), true);
+ return;
} else {
$this->flash->failure(t('Unable to add this currency rate.'));
}
}
- return $this->index($values, $errors);
+ $this->create($values, $errors);
+ }
+
+ /**
+ * Change reference currency
+ *
+ * @access public
+ * @param array $values
+ * @param array $errors
+ */
+ public function change(array $values = array(), array $errors = array())
+ {
+ if (empty($values)) {
+ $values['application_currency'] = $this->configModel->get('application_currency');
+ }
+
+ $this->response->html($this->template->render('currency/change', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'currencies' => $this->currencyModel->getCurrencies(),
+ )));
}
/**
@@ -56,7 +89,7 @@ class CurrencyController extends BaseController
*
* @access public
*/
- public function reference()
+ public function update()
{
$values = $this->request->getValues();
@@ -66,6 +99,6 @@ class CurrencyController extends BaseController
$this->flash->failure(t('Unable to save your settings.'));
}
- $this->response->redirect($this->helper->url->to('CurrencyController', 'index'));
+ $this->response->redirect($this->helper->url->to('CurrencyController', 'show'), true);
}
}
diff --git a/app/Controller/CustomFilterController.php b/app/Controller/CustomFilterController.php
index e5f674cd..dfe1ffc4 100644
--- a/app/Controller/CustomFilterController.php
+++ b/app/Controller/CustomFilterController.php
@@ -18,17 +18,13 @@ class CustomFilterController extends BaseController
* Display list of filters
*
* @access public
- * @param array $values
- * @param array $errors
* @throws \Kanboard\Core\Controller\PageNotFoundException
*/
- public function index(array $values = array(), array $errors = array())
+ public function index()
{
$project = $this->getProject();
$this->response->html($this->helper->layout->project('custom_filter/index', array(
- 'values' => $values + array('project_id' => $project['id']),
- 'errors' => $errors,
'project' => $project,
'custom_filters' => $this->customFilterModel->getAll($project['id'], $this->userSession->getId()),
'title' => t('Custom filters'),
@@ -36,6 +32,24 @@ class CustomFilterController extends BaseController
}
/**
+ * Show creation form for custom filters
+ *
+ * @access public
+ * @param array $values
+ * @param array $errors
+ */
+ public function create(array $values = array(), array $errors = array())
+ {
+ $project = $this->getProject();
+
+ $this->response->html($this->template->render('custom_filter/create', array(
+ 'values' => $values + array('project_id' => $project['id']),
+ 'errors' => $errors,
+ 'project' => $project,
+ )));
+ }
+
+ /**
* Save a new custom filter
*
* @access public
@@ -52,13 +66,14 @@ class CustomFilterController extends BaseController
if ($valid) {
if ($this->customFilterModel->create($values) !== false) {
$this->flash->success(t('Your custom filter have been created successfully.'));
- return $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id'])));
+ $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id'])), true);
+ return;
} else {
$this->flash->failure(t('Unable to create your custom filter.'));
}
}
- return $this->index($values, $errors);
+ $this->create($values, $errors);
}
/**
@@ -152,13 +167,14 @@ class CustomFilterController extends BaseController
if ($valid) {
if ($this->customFilterModel->update($values)) {
$this->flash->success(t('Your custom filter have been updated successfully.'));
- return $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id'])));
+ $this->response->redirect($this->helper->url->to('CustomFilterController', 'index', array('project_id' => $project['id'])), true);
+ return;
} else {
$this->flash->failure(t('Unable to update custom filter.'));
}
}
- return $this->edit($values, $errors);
+ $this->edit($values, $errors);
}
private function checkPermission(array $project, array $filter)
diff --git a/app/Controller/ExportController.php b/app/Controller/ExportController.php
index b7ac92aa..19f73a7c 100644
--- a/app/Controller/ExportController.php
+++ b/app/Controller/ExportController.php
@@ -24,27 +24,29 @@ class ExportController extends BaseController
private function common($model, $method, $filename, $action, $page_title)
{
$project = $this->getProject();
- $from = $this->request->getStringParam('from');
- $to = $this->request->getStringParam('to');
- if ($from && $to) {
- $data = $this->$model->$method($project['id'], $from, $to);
- $this->response->withFileDownload($filename.'.csv');
- $this->response->csv($data);
- } else {
+ if ($this->request->isPost()) {
+ $values = $this->request->getValues();
+ $from = empty($values['from']) ? '' : $values['from'];
+ $to = empty($values['to']) ? '' : $values['to'];
- $this->response->html($this->helper->layout->project('export/'.$action, array(
- 'values' => array(
- 'controller' => 'ExportController',
- 'action' => $action,
+ if ($from && $to) {
+ $data = $this->$model->$method($project['id'], $from, $to);
+ $this->response->withFileDownload($filename.'.csv');
+ $this->response->csv($data);
+ return;
+ }
+ } else {
+ $this->response->html($this->template->render('export/'.$action, array(
+ 'values' => array(
'project_id' => $project['id'],
- 'from' => $from,
- 'to' => $to,
+ 'from' => '',
+ 'to' => '',
),
- 'errors' => array(),
+ 'errors' => array(),
'project' => $project,
- 'title' => $page_title,
- ), 'export/sidebar'));
+ 'title' => $page_title,
+ )));
}
}
diff --git a/app/Controller/FileViewerController.php b/app/Controller/FileViewerController.php
index 518f5b0b..49568912 100644
--- a/app/Controller/FileViewerController.php
+++ b/app/Controller/FileViewerController.php
@@ -15,11 +15,11 @@ class FileViewerController extends BaseController
/**
* Get file content from object storage
*
- * @access private
+ * @access protected
* @param array $file
* @return string
*/
- private function getFileContent(array $file)
+ protected function getFileContent(array $file)
{
$content = '';
@@ -35,6 +35,30 @@ class FileViewerController extends BaseController
}
/**
+ * Output file with cache
+ *
+ * @param array $file
+ * @param $mimetype
+ */
+ protected function renderFileWithCache(array $file, $mimetype)
+ {
+ $etag = md5($file['path']);
+
+ if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
+ $this->response->status(304);
+ } else {
+ try {
+ $this->response->withContentType($mimetype);
+ $this->response->withCache(5 * 86400, $etag);
+ $this->response->send();
+ $this->objectStorage->output($file['path']);
+ } catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
+ }
+ }
+
+ /**
* Show file content in a popover
*
* @access public
@@ -65,21 +89,18 @@ class FileViewerController extends BaseController
public function image()
{
$file = $this->getFile();
- $etag = md5($file['path']);
- $this->response->withContentType($this->helper->file->getImageMimeType($file['name']));
- $this->response->withCache(5 * 86400, $etag);
-
- if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
- $this->response->status(304);
- } else {
+ $this->renderFileWithCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
- try {
- $this->response->send();
- $this->objectStorage->output($file['path']);
- } catch (ObjectStorageException $e) {
- $this->logger->error($e->getMessage());
- }
- }
+ /**
+ * Display file in browser
+ *
+ * @access public
+ */
+ public function browser()
+ {
+ $file = $this->getFile();
+ $this->renderFileWithCache($file, $this->helper->file->getBrowserViewType($file['name']));
}
/**
diff --git a/app/Controller/GroupAjaxController.php b/app/Controller/GroupAjaxController.php
index 496e9ef2..308bba9e 100644
--- a/app/Controller/GroupAjaxController.php
+++ b/app/Controller/GroupAjaxController.php
@@ -2,8 +2,6 @@
namespace Kanboard\Controller;
-use Kanboard\Formatter\GroupAutoCompleteFormatter;
-
/**
* Group Ajax Controller
*
@@ -20,7 +18,7 @@ class GroupAjaxController extends BaseController
public function autocomplete()
{
$search = $this->request->getStringParam('term');
- $formatter = new GroupAutoCompleteFormatter($this->groupManager->find($search));
- $this->response->json($formatter->format());
+ $groups = $this->groupManager->find($search);
+ $this->response->json($this->groupAutoCompleteFormatter->withGroups($groups)->format());
}
}
diff --git a/app/Controller/ICalendarController.php b/app/Controller/ICalendarController.php
index e354c6f1..4fe8b78a 100644
--- a/app/Controller/ICalendarController.php
+++ b/app/Controller/ICalendarController.php
@@ -7,7 +7,6 @@ use Kanboard\Core\Filter\QueryBuilder;
use Kanboard\Filter\TaskAssigneeFilter;
use Kanboard\Filter\TaskProjectFilter;
use Kanboard\Filter\TaskStatusFilter;
-use Kanboard\Formatter\TaskICalFormatter;
use Kanboard\Model\TaskModel;
use Eluceo\iCal\Component\Calendar as iCalendar;
@@ -94,8 +93,6 @@ class ICalendarController extends BaseController
$end = $this->request->getStringParam('end', strtotime('+6 months'));
$this->helper->ical->addTaskDateDueEvents($queryBuilder, $calendar, $start, $end);
-
- $formatter = new TaskICalFormatter($this->container);
- $this->response->ical($formatter->setCalendar($calendar)->format());
+ $this->response->ical($this->taskICalFormatter->setCalendar($calendar)->format());
}
}
diff --git a/app/Controller/LinkController.php b/app/Controller/LinkController.php
index 477b25a4..2ad8a2b5 100644
--- a/app/Controller/LinkController.php
+++ b/app/Controller/LinkController.php
@@ -16,11 +16,11 @@ class LinkController extends BaseController
/**
* Get the current link
*
- * @access private
+ * @access protected
* @return array
* @throws PageNotFoundException
*/
- private function getLink()
+ protected function getLink()
{
$link = $this->linkModel->getById($this->request->getIntegerParam('link_id'));
@@ -32,19 +32,31 @@ class LinkController extends BaseController
}
/**
- * List of links
+ * List of labels
+ *
+ * @access public
+ */
+ public function show()
+ {
+ $this->response->html($this->helper->layout->config('link/show', array(
+ 'links' => $this->linkModel->getMergedList(),
+ 'title' => t('Settings').' &gt; '.t('Link labels'),
+ )));
+ }
+
+ /**
+ * Add new link label
*
* @access public
* @param array $values
* @param array $errors
*/
- public function index(array $values = array(), array $errors = array())
+ public function create(array $values = array(), array $errors = array())
{
- $this->response->html($this->helper->layout->config('link/index', array(
- 'links' => $this->linkModel->getMergedList(),
+ $this->response->html($this->template->render('link/create', array(
+ 'links' => $this->linkModel->getMergedList(),
'values' => $values,
'errors' => $errors,
- 'title' => t('Settings').' &gt; '.t('Task\'s links'),
)));
}
@@ -61,21 +73,22 @@ class LinkController extends BaseController
if ($valid) {
if ($this->linkModel->create($values['label'], $values['opposite_label']) !== false) {
$this->flash->success(t('Link added successfully.'));
- return $this->response->redirect($this->helper->url->to('LinkController', 'index'));
+ $this->response->redirect($this->helper->url->to('LinkController', 'show'), true);
+ return;
} else {
$this->flash->failure(t('Unable to create your link.'));
}
}
- return $this->index($values, $errors);
+ $this->create($values, $errors);
}
/**
* Edit form
*
* @access public
- * @param array $values
- * @param array $errors
+ * @param array $values
+ * @param array $errors
* @throws PageNotFoundException
*/
public function edit(array $values = array(), array $errors = array())
@@ -83,12 +96,11 @@ class LinkController extends BaseController
$link = $this->getLink();
$link['label'] = t($link['label']);
- $this->response->html($this->helper->layout->config('link/edit', array(
+ $this->response->html($this->template->render('link/edit', array(
'values' => $values ?: $link,
'errors' => $errors,
'labels' => $this->linkModel->getList($link['id']),
- 'link' => $link,
- 'title' => t('Link modification')
+ 'link' => $link,
)));
}
@@ -105,13 +117,14 @@ class LinkController extends BaseController
if ($valid) {
if ($this->linkModel->update($values)) {
$this->flash->success(t('Link updated successfully.'));
- return $this->response->redirect($this->helper->url->to('LinkController', 'index'));
+ $this->response->redirect($this->helper->url->to('LinkController', 'show'), true);
+ return;
} else {
$this->flash->failure(t('Unable to update your link.'));
}
}
- return $this->edit($values, $errors);
+ $this->edit($values, $errors);
}
/**
@@ -123,9 +136,8 @@ class LinkController extends BaseController
{
$link = $this->getLink();
- $this->response->html($this->helper->layout->config('link/remove', array(
+ $this->response->html($this->template->render('link/remove', array(
'link' => $link,
- 'title' => t('Remove a link')
)));
}
@@ -145,6 +157,6 @@ class LinkController extends BaseController
$this->flash->failure(t('Unable to remove this link.'));
}
- $this->response->redirect($this->helper->url->to('LinkController', 'index'));
+ $this->response->redirect($this->helper->url->to('LinkController', 'show'), true);
}
}
diff --git a/app/Controller/PluginController.php b/app/Controller/PluginController.php
index 7b9d64d9..dbb739d6 100644
--- a/app/Controller/PluginController.php
+++ b/app/Controller/PluginController.php
@@ -23,6 +23,7 @@ class PluginController extends BaseController
{
$this->response->html($this->helper->layout->plugin('plugin/show', array(
'plugins' => $this->pluginLoader->getPlugins(),
+ 'incompatible_plugins' => $this->pluginLoader->getIncompatiblePlugins(),
'title' => t('Installed Plugins'),
'is_configured' => Installer::isConfigured(),
)));
diff --git a/app/Controller/ProjectEditController.php b/app/Controller/ProjectEditController.php
index 228d681c..ae39fdf3 100644
--- a/app/Controller/ProjectEditController.php
+++ b/app/Controller/ProjectEditController.php
@@ -11,51 +11,23 @@ namespace Kanboard\Controller;
class ProjectEditController extends BaseController
{
/**
- * General edition (most common operations)
+ * Edit project
*
* @access public
* @param array $values
* @param array $errors
*/
- public function edit(array $values = array(), array $errors = array())
+ public function show(array $values = array(), array $errors = array())
{
- $this->renderView('project_edit/general', $values, $errors);
- }
-
- /**
- * Change start and end dates
- *
- * @access public
- * @param array $values
- * @param array $errors
- */
- public function dates(array $values = array(), array $errors = array())
- {
- $this->renderView('project_edit/dates', $values, $errors);
- }
-
- /**
- * Change project description
- *
- * @access public
- * @param array $values
- * @param array $errors
- */
- public function description(array $values = array(), array $errors = array())
- {
- $this->renderView('project_edit/description', $values, $errors);
- }
+ $project = $this->getProject();
- /**
- * Change task priority
- *
- * @access public
- * @param array $values
- * @param array $errors
- */
- public function priority(array $values = array(), array $errors = array())
- {
- $this->renderView('project_edit/task_priority', $values, $errors);
+ $this->response->html($this->helper->layout->project('project_edit/show', array(
+ 'owners' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true),
+ 'values' => empty($values) ? $project : $values,
+ 'errors' => $errors,
+ 'project' => $project,
+ 'title' => t('Edit project')
+ )));
}
/**
@@ -67,67 +39,42 @@ class ProjectEditController extends BaseController
{
$project = $this->getProject();
$values = $this->request->getValues();
- $redirect = $this->request->getStringParam('redirect', 'edit');
- $values = $this->prepareValues($redirect, $project, $values);
+ $values = $this->prepareValues($project, $values);
list($valid, $errors) = $this->projectValidator->validateModification($values);
if ($valid) {
if ($this->projectModel->update($values)) {
$this->flash->success(t('Project updated successfully.'));
- return $this->response->redirect($this->helper->url->to('ProjectEditController', $redirect, array('project_id' => $project['id'])), true);
+ return $this->response->redirect($this->helper->url->to('ProjectEditController', 'show', array('project_id' => $project['id'])), true);
} else {
$this->flash->failure(t('Unable to update this project.'));
}
}
- return $this->$redirect($values, $errors);
+ return $this->show($values, $errors);
}
/**
* Prepare form values
*
* @access private
- * @param string $redirect
* @param array $project
* @param array $values
* @return array
*/
- private function prepareValues($redirect, array $project, array $values)
+ private function prepareValues(array $project, array $values)
{
- if ($redirect === 'edit') {
- if (isset($values['is_private'])) {
- if (! $this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) {
- unset($values['is_private']);
- }
- } elseif ($project['is_private'] == 1 && ! isset($values['is_private'])) {
- if ($this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) {
- $values += array('is_private' => 0);
- }
+ if (isset($values['is_private'])) {
+ if (! $this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) {
+ unset($values['is_private']);
+ }
+ } elseif ($project['is_private'] == 1 && ! isset($values['is_private'])) {
+ if ($this->helper->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])) {
+ $values += array('is_private' => 0);
}
}
return $values;
}
-
- /**
- * Common method to render different views
- *
- * @access private
- * @param string $template
- * @param array $values
- * @param array $errors
- */
- private function renderView($template, array $values, array $errors)
- {
- $project = $this->getProject();
-
- $this->response->html($this->helper->layout->project($template, array(
- 'owners' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true),
- 'values' => empty($values) ? $project : $values,
- 'errors' => $errors,
- 'project' => $project,
- 'title' => t('Edit project')
- )));
- }
}
diff --git a/app/Controller/ProjectGanttController.php b/app/Controller/ProjectGanttController.php
index a70d9eee..8239005e 100644
--- a/app/Controller/ProjectGanttController.php
+++ b/app/Controller/ProjectGanttController.php
@@ -5,7 +5,6 @@ namespace Kanboard\Controller;
use Kanboard\Filter\ProjectIdsFilter;
use Kanboard\Filter\ProjectStatusFilter;
use Kanboard\Filter\ProjectTypeFilter;
-use Kanboard\Formatter\ProjectGanttFormatter;
use Kanboard\Model\ProjectModel;
/**
@@ -30,7 +29,7 @@ class ProjectGanttController extends BaseController
$filter->getQuery()->asc(ProjectModel::TABLE.'.start_date');
$this->response->html($this->helper->layout->app('project_gantt/show', array(
- 'projects' => $filter->format(new ProjectGanttFormatter($this->container)),
+ 'projects' => $filter->format($this->projectGanttFormatter),
'title' => t('Gantt chart for all projects'),
)));
}
diff --git a/app/Controller/TaskAjaxController.php b/app/Controller/TaskAjaxController.php
index 609dd23c..6d0b3fc2 100644
--- a/app/Controller/TaskAjaxController.php
+++ b/app/Controller/TaskAjaxController.php
@@ -8,8 +8,6 @@ use Kanboard\Filter\TaskProjectsFilter;
use Kanboard\Filter\TaskStartsWithIdFilter;
use Kanboard\Filter\TaskStatusFilter;
use Kanboard\Filter\TaskTitleFilter;
-use Kanboard\Formatter\TaskAutoCompleteFormatter;
-use Kanboard\Formatter\TaskSuggestMenuFormatter;
use Kanboard\Model\TaskModel;
/**
@@ -46,7 +44,7 @@ class TaskAjaxController extends BaseController
$filter->withFilter(new TaskTitleFilter($search));
}
- $this->response->json($filter->format(new TaskAutoCompleteFormatter($this->container)));
+ $this->response->json($filter->format($this->taskAutoCompleteFormatter));
}
}
@@ -66,7 +64,7 @@ class TaskAjaxController extends BaseController
->withFilter(new TaskStatusFilter(TaskModel::STATUS_OPEN))
->withFilter(new TaskStartsWithIdFilter($taskId));
- $this->response->json($filter->format(new TaskSuggestMenuFormatter($this->container)));
+ $this->response->json($filter->format($this->taskSuggestMenuFormatter));
}
}
}
diff --git a/app/Controller/TaskCreationController.php b/app/Controller/TaskCreationController.php
index ec53e211..20457568 100644
--- a/app/Controller/TaskCreationController.php
+++ b/app/Controller/TaskCreationController.php
@@ -24,10 +24,7 @@ class TaskCreationController extends BaseController
{
$project = $this->getProject();
$swimlanes_list = $this->swimlaneModel->getList($project['id'], false, true);
-
- if (empty($values)) {
- $values = $this->prepareValues($swimlanes_list);
- }
+ $values += $this->prepareValues($swimlanes_list);
$values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values));
$values = $this->hook->merge('controller:task-creation:form:default', $values, array('default_values' => $values));
diff --git a/app/Controller/TaskExternalLinkController.php b/app/Controller/TaskExternalLinkController.php
index 9c04eb00..df23f87b 100644
--- a/app/Controller/TaskExternalLinkController.php
+++ b/app/Controller/TaskExternalLinkController.php
@@ -76,12 +76,23 @@ class TaskExternalLinkController extends BaseController
$values = $this->request->getValues();
list($valid, $errors) = $this->externalLinkValidator->validateCreation($values);
- if ($valid && $this->taskExternalLinkModel->create($values) !== false) {
- $this->flash->success(t('Link added successfully.'));
- return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true);
+ if ($valid) {
+ if ($this->taskExternalLinkModel->create($values) !== false) {
+ $this->flash->success(t('Link added successfully.'));
+ } else {
+ $this->flash->success(t('Unable to create your link.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true);
+ } else {
+ $provider = $this->externalLinkManager->getProvider($values['link_type']);
+ $this->response->html($this->template->render('task_external_link/create', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'dependencies' => $provider->getDependencies(),
+ 'task' => $task,
+ )));
}
-
- return $this->edit($values, $errors);
}
/**
diff --git a/app/Controller/TaskGanttController.php b/app/Controller/TaskGanttController.php
index 868368e1..b03b9d00 100644
--- a/app/Controller/TaskGanttController.php
+++ b/app/Controller/TaskGanttController.php
@@ -3,7 +3,6 @@
namespace Kanboard\Controller;
use Kanboard\Filter\TaskProjectFilter;
-use Kanboard\Formatter\TaskGanttFormatter;
use Kanboard\Model\TaskModel;
/**
@@ -35,7 +34,7 @@ class TaskGanttController extends BaseController
'title' => $project['name'],
'description' => $this->helper->projectHeader->getDescription($project),
'sorting' => $sorting,
- 'tasks' => $filter->format(new TaskGanttFormatter($this->container)),
+ 'tasks' => $filter->format($this->taskGanttFormatter),
)));
}
diff --git a/app/Controller/TaskGanttCreationController.php b/app/Controller/TaskGanttCreationController.php
deleted file mode 100644
index c5046f60..00000000
--- a/app/Controller/TaskGanttCreationController.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-namespace Kanboard\Controller;
-
-/**
- * Class TaskGanttCreationController
- *
- * @package Kanboard\Controller
- * @author Frederic Guillot
- */
-class TaskGanttCreationController extends BaseController
-{
- /**
- * Simplified form to create a new task
- *
- * @access public
- * @param array $values
- * @param array $errors
- * @throws \Kanboard\Core\Controller\PageNotFoundException
- */
- public function show(array $values = array(), array $errors = array())
- {
- $project = $this->getProject();
-
- $values = $values + array(
- 'project_id' => $project['id'],
- 'column_id' => $this->columnModel->getFirstColumnId($project['id']),
- 'position' => 1
- );
-
- $values = $this->hook->merge('controller:task:form:default', $values, array('default_values' => $values));
- $values = $this->hook->merge('controller:gantt:task:form:default', $values, array('default_values' => $values));
-
- $this->response->html($this->template->render('task_gantt_creation/show', array(
- 'project' => $project,
- 'errors' => $errors,
- 'values' => $values,
- 'users_list' => $this->projectUserRoleModel->getAssignableUsersList($project['id'], true, false, true),
- 'categories_list' => $this->categoryModel->getList($project['id']),
- 'swimlanes_list' => $this->swimlaneModel->getList($project['id'], false, true),
- )));
- }
-
- /**
- * Validate and save a new task
- *
- * @access public
- */
- public function save()
- {
- $project = $this->getProject();
- $values = $this->request->getValues();
-
- list($valid, $errors) = $this->taskValidator->validateCreation($values);
-
- if ($valid && $this->taskCreationModel->create($values)) {
- $this->flash->success(t('Task created successfully.'));
- $this->response->redirect($this->helper->url->to('TaskGanttController', 'show', array('project_id' => $project['id'])));
- } else {
- $this->flash->failure(t('Unable to create your task.'));
- $this->show($values, $errors);
- }
- }
-}
diff --git a/app/Controller/TaskImportController.php b/app/Controller/TaskImportController.php
index 3ce275a5..2e323979 100644
--- a/app/Controller/TaskImportController.php
+++ b/app/Controller/TaskImportController.php
@@ -23,15 +23,14 @@ class TaskImportController extends BaseController
{
$project = $this->getProject();
- $this->response->html($this->helper->layout->project('task_import/show', array(
+ $this->response->html($this->template->render('task_import/show', array(
'project' => $project,
'values' => $values,
'errors' => $errors,
'max_size' => get_upload_max_size(),
'delimiters' => Csv::getDelimiters(),
'enclosures' => Csv::getEnclosures(),
- 'title' => t('Import tasks from CSV file'),
- ), 'task_import/sidebar'));
+ )));
}
/**
@@ -58,7 +57,7 @@ class TaskImportController extends BaseController
$this->flash->failure(t('Nothing have been imported!'));
}
- $this->response->redirect($this->helper->url->to('TaskImportController', 'show', array('project_id' => $project['id'])));
+ $this->response->redirect($this->helper->url->to('TaskImportController', 'show', array('project_id' => $project['id'])), true);
}
}
diff --git a/app/Controller/TaskMovePositionController.php b/app/Controller/TaskMovePositionController.php
index cb4afd04..39687b79 100644
--- a/app/Controller/TaskMovePositionController.php
+++ b/app/Controller/TaskMovePositionController.php
@@ -3,7 +3,6 @@
namespace Kanboard\Controller;
use Kanboard\Core\Controller\AccessForbiddenException;
-use Kanboard\Formatter\BoardFormatter;
use Kanboard\Model\TaskModel;
/**
@@ -20,7 +19,7 @@ class TaskMovePositionController extends BaseController
$this->response->html($this->template->render('task_move_position/show', array(
'task' => $task,
- 'board' => BoardFormatter::getInstance($this->container)
+ 'board' => $this->boardFormatter
->withProjectId($task['project_id'])
->withQuery($this->taskFinderModel->getExtendedQuery()
->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN)
@@ -39,7 +38,7 @@ class TaskMovePositionController extends BaseController
throw new AccessForbiddenException(e('You are not allowed to move this task.'));
}
- $result = $this->taskPositionModel->movePosition(
+ $this->taskPositionModel->movePosition(
$task['project_id'],
$task['id'],
$values['column_id'],
@@ -47,6 +46,6 @@ class TaskMovePositionController extends BaseController
$values['swimlane_id']
);
- $this->response->json(array('result' => $result));
+ $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
}
}
diff --git a/app/Controller/TaskStatusController.php b/app/Controller/TaskStatusController.php
index 82b4f9c4..56d38400 100644
--- a/app/Controller/TaskStatusController.php
+++ b/app/Controller/TaskStatusController.php
@@ -52,11 +52,11 @@ class TaskStatusController extends BaseController
$this->flash->failure($failure_message);
}
- return $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true);
+ $this->response->redirect($this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), true);
+ } else {
+ $this->response->html($this->template->render($template, array(
+ 'task' => $task,
+ )));
}
-
- return $this->response->html($this->template->render($template, array(
- 'task' => $task,
- )));
}
}
diff --git a/app/Controller/UserAjaxController.php b/app/Controller/UserAjaxController.php
index d93bfe9a..17567a00 100644
--- a/app/Controller/UserAjaxController.php
+++ b/app/Controller/UserAjaxController.php
@@ -3,8 +3,6 @@
namespace Kanboard\Controller;
use Kanboard\Filter\UserNameFilter;
-use Kanboard\Formatter\UserAutoCompleteFormatter;
-use Kanboard\Formatter\UserMentionFormatter;
use Kanboard\Model\UserModel;
/**
@@ -25,7 +23,7 @@ class UserAjaxController extends BaseController
$search = $this->request->getStringParam('term');
$filter = $this->userQuery->withFilter(new UserNameFilter($search));
$filter->getQuery()->asc(UserModel::TABLE.'.name')->asc(UserModel::TABLE.'.username');
- $this->response->json($filter->format(new UserAutoCompleteFormatter($this->container)));
+ $this->response->json($filter->format($this->userAutoCompleteFormatter));
}
/**
@@ -39,11 +37,7 @@ class UserAjaxController extends BaseController
$query = $this->request->getStringParam('search');
$users = $this->projectPermissionModel->findUsernames($project_id, $query);
- $this->response->json(
- UserMentionFormatter::getInstance($this->container)
- ->withUsers($users)
- ->format()
- );
+ $this->response->json($this->userMentionFormatter->withUsers($users)->format());
}
/**
diff --git a/app/Controller/UserCreationController.php b/app/Controller/UserCreationController.php
index 9c873f85..27f1687b 100644
--- a/app/Controller/UserCreationController.php
+++ b/app/Controller/UserCreationController.php
@@ -22,10 +22,7 @@ class UserCreationController extends BaseController
*/
public function show(array $values = array(), array $errors = array())
{
- $isRemote = $this->request->getIntegerParam('remote') == 1 || (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1);
- $template = $isRemote ? 'user_creation/remote' : 'user_creation/local';
-
- $this->response->html($this->template->render($template, array(
+ $this->response->html($this->template->render('user_creation/show', array(
'timezones' => $this->timezoneModel->getTimezones(true),
'languages' => $this->languageModel->getLanguages(true),
'roles' => $this->role->getApplicationRoles(),
@@ -57,7 +54,7 @@ class UserCreationController extends BaseController
*
* @param array $values
*/
- private function createUser(array $values)
+ protected function createUser(array $values)
{
$project_id = empty($values['project_id']) ? 0 : $values['project_id'];
unset($values['project_id']);
diff --git a/app/Controller/UserInviteController.php b/app/Controller/UserInviteController.php
new file mode 100644
index 00000000..8c77940c
--- /dev/null
+++ b/app/Controller/UserInviteController.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Kanboard\Controller;
+
+use Kanboard\Core\Controller\PageNotFoundException;
+use Kanboard\Core\Security\Role;
+use Kanboard\Notification\MailNotification;
+
+/**
+ * Class UserInviteController
+ *
+ * @package Kanboard\Controller
+ * @author Frederic Guillot
+ */
+class UserInviteController extends BaseController
+{
+ public function show(array $values = array(), array $errors = array())
+ {
+ $this->response->html($this->template->render('user_invite/show', array(
+ 'projects' => $this->projectModel->getList(),
+ 'errors' => $errors,
+ 'values' => $values,
+ )));
+ }
+
+ public function save()
+ {
+ $values = $this->request->getValues();
+
+ if (! empty($values['emails']) && isset($values['project_id'])) {
+ $emails = explode("\r\n", trim($values['emails']));
+ $nb = $this->inviteModel->createInvites($emails, $values['project_id']);
+ $this->flash->success($nb > 1 ? t('%d invitations were sent.', $nb) : t('%d invitation was sent.', $nb));
+ }
+
+ $this->response->redirect($this->helper->url->to('UserListController', 'show'));
+ }
+
+ public function signup(array $values = array(), array $errors = array())
+ {
+ $invite = $this->getInvite();
+
+ $this->response->html($this->helper->layout->app('user_invite/signup', array(
+ 'no_layout' => true,
+ 'not_editable' => true,
+ 'token' => $invite['token'],
+ 'errors' => $errors,
+ 'values' => $values + array('email' => $invite['email']),
+ 'timezones' => $this->timezoneModel->getTimezones(true),
+ 'languages' => $this->languageModel->getLanguages(true),
+ )));
+ }
+
+ public function register()
+ {
+ $invite = $this->getInvite();
+
+ $values = $this->request->getValues();
+ list($valid, $errors) = $this->userValidator->validateCreation($values);
+
+ if ($valid) {
+ $this->createUser($invite, $values);
+ } else {
+ $this->signup($values, $errors);
+ }
+ }
+
+ protected function getInvite()
+ {
+ $token = $this->request->getStringParam('token');
+
+ if (empty($token)) {
+ throw PageNotFoundException::getInstance()->withoutLayout();
+ }
+
+ $invite = $this->inviteModel->getByToken($token);
+
+ if (empty($invite)) {
+ throw PageNotFoundException::getInstance()->withoutLayout();
+ }
+
+ return $invite;
+ }
+
+ protected function createUser(array $invite, array $values)
+ {
+ $user_id = $this->userModel->create($values);
+
+ if ($user_id !== false) {
+ if ($invite['project_id'] != 0) {
+ $this->projectUserRoleModel->addUser($invite['project_id'], $user_id, Role::PROJECT_MEMBER);
+ }
+
+ if (! empty($values['notifications_enabled'])) {
+ $this->userNotificationTypeModel->saveSelectedTypes($user_id, array(MailNotification::TYPE));
+ }
+
+ $this->inviteModel->remove($invite['email']);
+
+ $this->flash->success(t('User created successfully.'));
+ $this->response->redirect($this->helper->url->to('AuthController', 'login'));
+ } else {
+ $this->flash->failure(t('Unable to create this user.'));
+ $this->response->redirect($this->helper->url->to('UserInviteController', 'signup'));
+ }
+ }
+}
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 881cccbd..17ed5b33 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -62,6 +62,21 @@ use Pimple\Container;
* @property \Kanboard\Decorator\ColumnRestrictionCacheDecorator $columnRestrictionCacheDecorator
* @property \Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator $columnMoveRestrictionCacheDecorator
* @property \Kanboard\Decorator\ProjectRoleRestrictionCacheDecorator $projectRoleRestrictionCacheDecorator
+ * @property \Kanboard\Formatter\BoardColumnFormatter $boardColumnFormatter
+ * @property \Kanboard\Formatter\BoardFormatter $boardFormatter
+ * @property \Kanboard\Formatter\BoardSwimlaneFormatter $boardSwimlaneFormatter
+ * @property \Kanboard\Formatter\BoardTaskFormatter $boardTaskFormatter
+ * @property \Kanboard\Formatter\GroupAutoCompleteFormatter $groupAutoCompleteFormatter
+ * @property \Kanboard\Formatter\ProjectActivityEventFormatter $projectActivityEventFormatter
+ * @property \Kanboard\Formatter\ProjectGanttFormatter $projectGanttFormatter
+ * @property \Kanboard\Formatter\SubtaskTimeTrackingCalendarFormatter $subtaskTimeTrackingCalendarFormatter
+ * @property \Kanboard\Formatter\TaskAutoCompleteFormatter $taskAutoCompleteFormatter
+ * @property \Kanboard\Formatter\TaskCalendarFormatter $taskCalendarFormatter
+ * @property \Kanboard\Formatter\TaskGanttFormatter $taskGanttFormatter
+ * @property \Kanboard\Formatter\TaskICalFormatter $taskICalFormatter
+ * @property \Kanboard\Formatter\TaskSuggestMenuFormatter $taskSuggestMenuFormatter
+ * @property \Kanboard\Formatter\UserAutoCompleteFormatter $userAutoCompleteFormatter
+ * @property \Kanboard\Formatter\UserMentionFormatter $userMentionFormatter
* @property \Kanboard\Model\ActionModel $actionModel
* @property \Kanboard\Model\ActionParameterModel $actionParameterModel
* @property \Kanboard\Model\AvatarFileModel $avatarFileModel
@@ -79,6 +94,7 @@ use Pimple\Container;
* @property \Kanboard\Model\ProjectFileModel $projectFileModel
* @property \Kanboard\Model\GroupModel $groupModel
* @property \Kanboard\Model\GroupMemberModel $groupMemberModel
+ * @property \Kanboard\Model\InviteModel $inviteModel
* @property \Kanboard\Model\LanguageModel $languageModel
* @property \Kanboard\Model\LastLoginModel $lastLoginModel
* @property \Kanboard\Model\LinkModel $linkModel
diff --git a/app/Core/DateParser.php b/app/Core/DateParser.php
index b9aa9230..9d012d12 100644
--- a/app/Core/DateParser.php
+++ b/app/Core/DateParser.php
@@ -13,7 +13,6 @@ use DateTime;
class DateParser extends Base
{
const DATE_FORMAT = 'm/d/Y';
- const DATE_TIME_FORMAT = 'm/d/Y H:i';
const TIME_FORMAT = 'H:i';
/**
@@ -35,7 +34,7 @@ class DateParser extends Base
*/
public function getUserDateTimeFormat()
{
- return $this->configModel->get('application_datetime_format', DateParser::DATE_TIME_FORMAT);
+ return $this->getUserDateFormat().' '.$this->getUserTimeFormat();
}
/**
@@ -292,11 +291,9 @@ class DateParser extends Base
{
foreach ($fields as $field) {
if (! empty($values[$field])) {
- if (! ctype_digit($values[$field])) {
- $values[$field] = strtotime($values[$field]);
+ if (ctype_digit($values[$field])) {
+ $values[$field] = date($format, $values[$field]);
}
-
- $values[$field] = date($format, $values[$field]);
} else {
$values[$field] = '';
}
diff --git a/app/Core/ExternalTask/ExternalTaskManager.php b/app/Core/ExternalTask/ExternalTaskManager.php
index 2ce6f106..102ec459 100644
--- a/app/Core/ExternalTask/ExternalTaskManager.php
+++ b/app/Core/ExternalTask/ExternalTaskManager.php
@@ -48,6 +48,11 @@ class ExternalTaskManager
public function getProvidersList()
{
$providers = array_keys($this->providers);
- return array_combine($providers, $providers);
+
+ if (count($providers)) {
+ return array_combine($providers, $providers);
+ }
+
+ return array();
}
}
diff --git a/app/Core/Filter/FormatterInterface.php b/app/Core/Filter/FormatterInterface.php
index b7c04c51..0ff84976 100644
--- a/app/Core/Filter/FormatterInterface.php
+++ b/app/Core/Filter/FormatterInterface.php
@@ -17,7 +17,7 @@ interface FormatterInterface
*
* @access public
* @param Table $query
- * @return FormatterInterface
+ * @return $this
*/
public function withQuery(Table $query);
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 9660c348..ab7c3b7b 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -20,6 +20,7 @@ use Pimple\Container;
* @property \Kanboard\Helper\FormHelper $form
* @property \Kanboard\Helper\HookHelper $hook
* @property \Kanboard\Helper\ICalHelper $ical
+ * @property \Kanboard\Helper\ModalHelper $modal
* @property \Kanboard\Helper\ModelHelper $model
* @property \Kanboard\Helper\SubtaskHelper $subtask
* @property \Kanboard\Helper\TaskHelper $task
diff --git a/app/Core/Http/Request.php b/app/Core/Http/Request.php
index 2e84958d..44bfdbe6 100644
--- a/app/Core/Http/Request.php
+++ b/app/Core/Http/Request.php
@@ -105,7 +105,7 @@ class Request extends Base
{
if (! empty($this->post) && ! empty($this->post['csrf_token']) && $this->token->validateCSRFToken($this->post['csrf_token'])) {
unset($this->post['csrf_token']);
- return $this->post;
+ return $this->filterValues($this->post);
}
return array();
@@ -344,4 +344,17 @@ class Request extends Base
{
return isset($this->server[$variable]) ? $this->server[$variable] : '';
}
+
+ protected function filterValues(array $values)
+ {
+ foreach ($values as $key => $value) {
+
+ // IE11 Workaround when submitting multipart/form-data
+ if (strpos($key, '-----------------------------') === 0) {
+ unset($values[$key]);
+ }
+ }
+
+ return $values;
+ }
}
diff --git a/app/Core/Mail/Transport/Mail.php b/app/Core/Mail/Transport/Mail.php
index d27925f0..c99cc8ba 100644
--- a/app/Core/Mail/Transport/Mail.php
+++ b/app/Core/Mail/Transport/Mail.php
@@ -33,8 +33,8 @@ class Mail extends Base implements ClientInterface
$message = Swift_Message::newInstance()
->setSubject($subject)
->setFrom(array($this->helper->mail->getMailSenderAddress() => $author))
- ->setBody($html, 'text/html')
- ->setTo(array($email => $name));
+ ->setTo(array($email => $name))
+ ->setBody($html, 'text/html');
Swift_Mailer::newInstance($this->getTransport())->send($message);
} catch (Swift_TransportException $e) {
diff --git a/app/Core/Mail/Transport/Smtp.php b/app/Core/Mail/Transport/Smtp.php
index 1f4e54ce..815dde5d 100644
--- a/app/Core/Mail/Transport/Smtp.php
+++ b/app/Core/Mail/Transport/Smtp.php
@@ -24,6 +24,7 @@ class Smtp extends Mail
$transport->setUsername(MAIL_SMTP_USERNAME);
$transport->setPassword(MAIL_SMTP_PASSWORD);
$transport->setEncryption(MAIL_SMTP_ENCRYPTION);
+
if (HTTP_VERIFY_SSL_CERTIFICATE === false) {
$transport->setStreamOptions(array(
'ssl' => array(
diff --git a/app/Core/Paginator.php b/app/Core/Paginator.php
index cfe89938..9075a713 100644
--- a/app/Core/Paginator.php
+++ b/app/Core/Paginator.php
@@ -232,6 +232,17 @@ class Paginator
}
/**
+ * Get the number of current page
+ *
+ * @access public
+ * @return integer
+ */
+ public function getPage()
+ {
+ return $this->page;
+ }
+
+ /**
* Set the default column order
*
* @access public
@@ -271,6 +282,16 @@ class Paginator
}
/**
+ * Get the maximum number of items per page.
+ *
+ * @return int
+ */
+ public function getMax()
+ {
+ return $this->limit;
+ }
+
+ /**
* Return true if the collection is empty
*
* @access public
@@ -353,7 +374,9 @@ class Paginator
'&larr; '.t('Previous'),
$this->controller,
$this->action,
- $this->getUrlParams($this->page - 1, $this->order, $this->direction)
+ $this->getUrlParams($this->page - 1, $this->order, $this->direction),
+ false,
+ 'js-modal-replace'
);
} else {
$html .= '&larr; '.t('Previous');
@@ -379,7 +402,9 @@ class Paginator
t('Next').' &rarr;',
$this->controller,
$this->action,
- $this->getUrlParams($this->page + 1, $this->order, $this->direction)
+ $this->getUrlParams($this->page + 1, $this->order, $this->direction),
+ false,
+ 'js-modal-replace'
);
} else {
$html .= t('Next').' &rarr;';
@@ -391,6 +416,17 @@ class Paginator
}
/**
+ * Generate the page showing.
+ *
+ * @access public
+ * @return string
+ */
+ public function generatPageShowing()
+ {
+ return '<span class="pagination-showing">'.t('Showing %d-%d of %d', (($this->getPage() - 1) * $this->getMax() + 1), min($this->getTotal(), $this->getPage() * $this->getMax()), $this->getTotal()).'</span>';
+ }
+
+ /**
* Return true if there is no pagination to show
*
* @access public
@@ -413,6 +449,7 @@ class Paginator
if (! $this->hasNothingtoShow()) {
$html .= '<div class="pagination">';
+ $html .= $this->generatPageShowing();
$html .= $this->generatePreviousLink();
$html .= $this->generateNextLink();
$html .= '</div>';
@@ -453,7 +490,9 @@ class Paginator
$label,
$this->controller,
$this->action,
- $this->getUrlParams($this->page, $column, $direction)
+ $this->getUrlParams($this->page, $column, $direction),
+ false,
+ 'js-modal-replace'
);
}
}
diff --git a/app/Core/Plugin/Base.php b/app/Core/Plugin/Base.php
index 9d8167a9..e0b5954a 100644
--- a/app/Core/Plugin/Base.php
+++ b/app/Core/Plugin/Base.php
@@ -131,4 +131,17 @@ abstract class Base extends \Kanboard\Core\Base
{
return '';
}
+
+ /**
+ * Get application compatibility version
+ *
+ * Examples: >=1.0.36, 1.0.37, APP_VERSION
+ *
+ * @access public
+ * @return string
+ */
+ public function getCompatibleVersion()
+ {
+ return APP_VERSION;
+ }
}
diff --git a/app/Core/Plugin/Directory.php b/app/Core/Plugin/Directory.php
index 27c3514e..dc32e655 100644
--- a/app/Core/Plugin/Directory.php
+++ b/app/Core/Plugin/Directory.php
@@ -36,18 +36,7 @@ class Directory extends BaseCore
*/
public function isCompatible(array $plugin, $appVersion = APP_VERSION)
{
- if (strpos($appVersion, 'master') !== false) {
- return true;
- }
-
- foreach (array('>=', '>') as $operator) {
- if (strpos($plugin['compatible_version'], $operator) === 0) {
- $pluginVersion = substr($plugin['compatible_version'], strlen($operator));
- return version_compare($appVersion, $pluginVersion, $operator);
- }
- }
-
- return $plugin['compatible_version'] === $appVersion;
+ return Version::isCompatible($plugin['compatible_version'], $appVersion);
}
/**
diff --git a/app/Core/Plugin/Loader.php b/app/Core/Plugin/Loader.php
index f2f6add7..38f41d39 100644
--- a/app/Core/Plugin/Loader.php
+++ b/app/Core/Plugin/Loader.php
@@ -4,6 +4,7 @@ namespace Kanboard\Core\Plugin;
use Composer\Autoload\ClassLoader;
use DirectoryIterator;
+use Exception;
use LogicException;
use Kanboard\Core\Tool;
@@ -22,6 +23,7 @@ class Loader extends \Kanboard\Core\Base
* @var array
*/
protected $plugins = array();
+ protected $incompatiblePlugins = array();
/**
* Get list of loaded plugins
@@ -35,6 +37,17 @@ class Loader extends \Kanboard\Core\Base
}
/**
+ * Get list of not compatible plugins
+ *
+ * @access public
+ * @return Base[]
+ */
+ public function getIncompatiblePlugins()
+ {
+ return $this->incompatiblePlugins;
+ }
+
+ /**
* Scan plugin folder and load plugins
*
* @access public
@@ -51,8 +64,7 @@ class Loader extends \Kanboard\Core\Base
foreach ($dir as $fileInfo) {
if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
$pluginName = $fileInfo->getFilename();
- $this->loadSchema($pluginName);
- $this->initializePlugin($pluginName, $this->loadPlugin($pluginName));
+ $this->initializePlugin($pluginName);
}
}
}
@@ -85,7 +97,7 @@ class Loader extends \Kanboard\Core\Base
$className = '\Kanboard\Plugin\\'.$pluginName.'\\Plugin';
if (! class_exists($className)) {
- throw new LogicException('Unable to load this plugin class '.$className);
+ throw new LogicException('Unable to load this plugin class: '.$className);
}
return new $className($this->container);
@@ -96,18 +108,30 @@ class Loader extends \Kanboard\Core\Base
*
* @access public
* @param string $pluginName
- * @param Base $plugin
*/
- public function initializePlugin($pluginName, Base $plugin)
+ public function initializePlugin($pluginName)
{
- if (method_exists($plugin, 'onStartup')) {
- $this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
- }
+ try {
+ $plugin = $this->loadPlugin($pluginName);
- Tool::buildDIC($this->container, $plugin->getClasses());
- Tool::buildDICHelpers($this->container, $plugin->getHelpers());
+ if (Version::isCompatible($plugin->getCompatibleVersion(), APP_VERSION)) {
+ $this->loadSchema($pluginName);
+
+ if (method_exists($plugin, 'onStartup')) {
+ $this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
+ }
- $plugin->initialize();
- $this->plugins[$pluginName] = $plugin;
+ Tool::buildDIC($this->container, $plugin->getClasses());
+ Tool::buildDICHelpers($this->container, $plugin->getHelpers());
+
+ $plugin->initialize();
+ $this->plugins[$pluginName] = $plugin;
+ } else {
+ $this->incompatiblePlugins[$pluginName] = $plugin;
+ $this->logger->error($pluginName.' is not compatible with this version');
+ }
+ } catch (Exception $e) {
+ $this->logger->critical($pluginName.': '.$e->getMessage());
+ }
}
}
diff --git a/app/Core/Plugin/PluginException.php b/app/Core/Plugin/PluginException.php
new file mode 100644
index 00000000..fae7de35
--- /dev/null
+++ b/app/Core/Plugin/PluginException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+use Exception;
+
+/**
+ * Class PluginException
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class PluginException extends Exception
+{
+}
diff --git a/app/Core/Plugin/PluginInstallerException.php b/app/Core/Plugin/PluginInstallerException.php
index 7d356c9b..31745f22 100644
--- a/app/Core/Plugin/PluginInstallerException.php
+++ b/app/Core/Plugin/PluginInstallerException.php
@@ -2,14 +2,12 @@
namespace Kanboard\Core\Plugin;
-use Exception;
-
/**
* Class PluginInstallerException
*
* @package Kanboard\Core\Plugin
* @author Frederic Guillot
*/
-class PluginInstallerException extends Exception
+class PluginInstallerException extends PluginException
{
}
diff --git a/app/Core/Plugin/Version.php b/app/Core/Plugin/Version.php
new file mode 100644
index 00000000..ba5e0443
--- /dev/null
+++ b/app/Core/Plugin/Version.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Kanboard\Core\Plugin;
+
+/**
+ * Class Version
+ *
+ * @package Kanboard\Core\Plugin
+ * @author Frederic Guillot
+ */
+class Version
+{
+ /**
+ * Check plugin version compatibility with application version
+ *
+ * @param string $pluginCompatibleVersion
+ * @param string $appVersion
+ * @return bool
+ */
+ public static function isCompatible($pluginCompatibleVersion, $appVersion = APP_VERSION)
+ {
+ if (strpos($appVersion, 'master') !== false) {
+ return true;
+ }
+
+ $appVersion = str_replace('v', '', $appVersion);
+ $pluginCompatibleVersion = str_replace('v', '', $pluginCompatibleVersion);
+
+ foreach (array('>=', '>', '<=', '<') as $operator) {
+ if (strpos($pluginCompatibleVersion, $operator) === 0) {
+ $pluginVersion = substr($pluginCompatibleVersion, strlen($operator));
+ return version_compare($appVersion, $pluginVersion, $operator);
+ }
+ }
+
+ return $pluginCompatibleVersion === $appVersion;
+ }
+}
diff --git a/app/Core/Queue/QueueManager.php b/app/Core/Queue/QueueManager.php
index dcf0ebf5..1d7c2d1e 100644
--- a/app/Core/Queue/QueueManager.php
+++ b/app/Core/Queue/QueueManager.php
@@ -64,7 +64,7 @@ class QueueManager extends Base
public function listen()
{
if ($this->queue === null) {
- throw new LogicException('No queue driver defined!');
+ throw new LogicException('No queue driver defined or unable to connect to broker!');
}
while ($job = $this->queue->pull()) {
diff --git a/app/Core/Tool.php b/app/Core/Tool.php
index 9b8820eb..6e457641 100644
--- a/app/Core/Tool.php
+++ b/app/Core/Tool.php
@@ -41,7 +41,7 @@ class Tool
}
/**
- * Build dependency injection container from an array
+ * Build dependency injection containers from an array
*
* @static
* @access public
@@ -64,6 +64,29 @@ class Tool
}
/**
+ * Build dependency injection container from an array
+ *
+ * @static
+ * @access public
+ * @param Container $container
+ * @param array $namespaces
+ * @return Container
+ */
+ public static function buildFactories(Container $container, array $namespaces)
+ {
+ foreach ($namespaces as $namespace => $classes) {
+ foreach ($classes as $name) {
+ $class = '\\Kanboard\\'.$namespace.'\\'.$name;
+ $container[lcfirst($name)] = $container->factory(function ($c) use ($class) {
+ return new $class($c);
+ });
+ }
+ }
+
+ return $container;
+ }
+
+ /**
* Build dependency injection container for custom helpers from an array
*
* @static
diff --git a/app/Formatter/BoardColumnFormatter.php b/app/Formatter/BoardColumnFormatter.php
index 85d31b5c..0d59f54e 100644
--- a/app/Formatter/BoardColumnFormatter.php
+++ b/app/Formatter/BoardColumnFormatter.php
@@ -79,7 +79,7 @@ class BoardColumnFormatter extends BaseFormatter implements FormatterInterface
{
foreach ($this->columns as &$column) {
$column['id'] = (int) $column['id'];
- $column['tasks'] = BoardTaskFormatter::getInstance($this->container)
+ $column['tasks'] = $this->boardTaskFormatter
->withTasks($this->tasks)
->withTags($this->tags)
->withSwimlaneId($this->swimlaneId)
diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php
index df443a52..3f47bfa9 100644
--- a/app/Formatter/BoardFormatter.php
+++ b/app/Formatter/BoardFormatter.php
@@ -59,7 +59,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface
$task_ids = array_column($tasks, 'id');
$tags = $this->taskTagModel->getTagsByTasks($task_ids);
- return BoardSwimlaneFormatter::getInstance($this->container)
+ return $this->boardSwimlaneFormatter
->withSwimlanes($swimlanes)
->withColumns($columns)
->withTasks($tasks)
diff --git a/app/Formatter/BoardSwimlaneFormatter.php b/app/Formatter/BoardSwimlaneFormatter.php
index ce67c8a8..18db259d 100644
--- a/app/Formatter/BoardSwimlaneFormatter.php
+++ b/app/Formatter/BoardSwimlaneFormatter.php
@@ -82,7 +82,7 @@ class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface
foreach ($this->swimlanes as &$swimlane) {
$swimlane['id'] = (int) $swimlane['id'];
- $swimlane['columns'] = BoardColumnFormatter::getInstance($this->container)
+ $swimlane['columns'] = $this->boardColumnFormatter
->withSwimlaneId($swimlane['id'])
->withColumns($this->columns)
->withTasks($this->tasks)
diff --git a/app/Formatter/GroupAutoCompleteFormatter.php b/app/Formatter/GroupAutoCompleteFormatter.php
index 4d552886..d811de7f 100644
--- a/app/Formatter/GroupAutoCompleteFormatter.php
+++ b/app/Formatter/GroupAutoCompleteFormatter.php
@@ -12,36 +12,26 @@ use PicoDb\Table;
* @package formatter
* @author Frederic Guillot
*/
-class GroupAutoCompleteFormatter implements FormatterInterface
+class GroupAutoCompleteFormatter extends BaseFormatter implements FormatterInterface
{
/**
* Groups found
*
- * @access private
+ * @access protected
* @var GroupProviderInterface[]
*/
- private $groups;
+ protected $groups;
/**
- * Format groups for the ajax auto-completion
+ * Set groups
*
* @access public
* @param GroupProviderInterface[] $groups
+ * @return $this
*/
- public function __construct(array $groups)
+ public function withGroups(array $groups)
{
$this->groups = $groups;
- }
-
- /**
- * Set query
- *
- * @access public
- * @param Table $query
- * @return FormatterInterface
- */
- public function withQuery(Table $query)
- {
return $this;
}
diff --git a/app/Formatter/UserAutoCompleteFormatter.php b/app/Formatter/UserAutoCompleteFormatter.php
index cd23a2a4..c81af00a 100644
--- a/app/Formatter/UserAutoCompleteFormatter.php
+++ b/app/Formatter/UserAutoCompleteFormatter.php
@@ -14,7 +14,7 @@ use Kanboard\Core\Filter\FormatterInterface;
class UserAutoCompleteFormatter extends BaseFormatter implements FormatterInterface
{
/**
- * Format the tasks for the ajax autocompletion
+ * Format the tasks for the ajax auto-completion
*
* @access public
* @return array
@@ -24,11 +24,11 @@ class UserAutoCompleteFormatter extends BaseFormatter implements FormatterInterf
$users = $this->query->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')->findAll();
foreach ($users as &$user) {
- $user['value'] = $user['username'].' (#'.$user['id'].')';
-
if (empty($user['name'])) {
+ $user['value'] = $user['username'].' (#'.$user['id'].')';
$user['label'] = $user['username'];
} else {
+ $user['value'] = $user['name'].' (#'.$user['id'].')';
$user['label'] = $user['name'].' ('.$user['username'].')';
}
}
diff --git a/app/Helper/AppHelper.php b/app/Helper/AppHelper.php
index 62062244..3b48d7d3 100644
--- a/app/Helper/AppHelper.php
+++ b/app/Helper/AppHelper.php
@@ -29,12 +29,12 @@ class AppHelper extends Base
*
* @access public
* @param string $param
- * @param mixed $default_value
+ * @param mixed $default
* @return mixed
*/
- public function config($param, $default_value = '')
+ public function config($param, $default = '')
{
- return $this->configModel->get($param, $default_value);
+ return $this->configModel->get($param, $default);
}
/**
diff --git a/app/Helper/CalendarHelper.php b/app/Helper/CalendarHelper.php
index 4f78b673..0942177d 100644
--- a/app/Helper/CalendarHelper.php
+++ b/app/Helper/CalendarHelper.php
@@ -5,8 +5,6 @@ namespace Kanboard\Helper;
use Kanboard\Core\Base;
use Kanboard\Core\Filter\QueryBuilder;
use Kanboard\Filter\TaskDueDateRangeFilter;
-use Kanboard\Formatter\SubtaskTimeTrackingCalendarFormatter;
-use Kanboard\Formatter\TaskCalendarFormatter;
/**
* Calendar Helper
@@ -44,7 +42,7 @@ class CalendarHelper extends Base
*/
public function getTaskDateDueEvents(QueryBuilder $queryBuilder, $start, $end)
{
- $formatter = new TaskCalendarFormatter($this->container);
+ $formatter = $this->taskCalendarFormatter;
$formatter->setFullDay();
$formatter->setColumns('date_due');
@@ -73,7 +71,7 @@ class CalendarHelper extends Base
'date_due'
));
- $formatter = new TaskCalendarFormatter($this->container);
+ $formatter = $this->taskCalendarFormatter;
$formatter->setColumns($startColumn, 'date_due');
return $queryBuilder->format($formatter);
@@ -90,8 +88,7 @@ class CalendarHelper extends Base
*/
public function getSubtaskTimeTrackingEvents($user_id, $start, $end)
{
- $formatter = new SubtaskTimeTrackingCalendarFormatter($this->container);
- return $formatter
+ return $this->subtaskTimeTrackingCalendarFormatter
->withQuery($this->subtaskTimeTrackingModel->getUserQuery($user_id)
->addCondition($this->getCalendarCondition(
$this->dateParser->getTimestampFromIsoFormat($start),
diff --git a/app/Helper/DateHelper.php b/app/Helper/DateHelper.php
index 7e2ec79c..3bc85b76 100644
--- a/app/Helper/DateHelper.php
+++ b/app/Helper/DateHelper.php
@@ -54,7 +54,7 @@ class DateHelper extends Base
*/
public function datetime($value)
{
- return date($this->configModel->get('application_datetime_format', 'm/d/Y H:i'), $value);
+ return date($this->dateParser->getUserDateTimeFormat(), $value);
}
/**
diff --git a/app/Helper/FileHelper.php b/app/Helper/FileHelper.php
index cabf371c..06589124 100644
--- a/app/Helper/FileHelper.php
+++ b/app/Helper/FileHelper.php
@@ -21,9 +21,7 @@ class FileHelper extends Base
*/
public function icon($filename)
{
- $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-
- switch ($extension) {
+ switch (get_file_extension($filename)) {
case 'jpeg':
case 'jpg':
case 'png':
@@ -70,9 +68,7 @@ class FileHelper extends Base
*/
public function getImageMimeType($filename)
{
- $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-
- switch ($extension) {
+ switch (get_file_extension($filename)) {
case 'jpeg':
case 'jpg':
return 'image/jpeg';
@@ -94,9 +90,7 @@ class FileHelper extends Base
*/
public function getPreviewType($filename)
{
- $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-
- switch ($extension) {
+ switch (get_file_extension($filename)) {
case 'md':
case 'markdown':
return 'markdown';
@@ -106,4 +100,21 @@ class FileHelper extends Base
return null;
}
+
+ /**
+ * Return the browser view mime-type based on the file extension.
+ *
+ * @access public
+ * @param $filename
+ * @return string
+ */
+ public function getBrowserViewType($filename)
+ {
+ switch (get_file_extension($filename)) {
+ case 'pdf':
+ return 'application/pdf';
+ }
+
+ return null;
+ }
}
diff --git a/app/Helper/ICalHelper.php b/app/Helper/ICalHelper.php
index dc399bf8..95723417 100644
--- a/app/Helper/ICalHelper.php
+++ b/app/Helper/ICalHelper.php
@@ -5,7 +5,6 @@ namespace Kanboard\Helper;
use Kanboard\Core\Base;
use Kanboard\Core\Filter\QueryBuilder;
use Kanboard\Filter\TaskDueDateRangeFilter;
-use Kanboard\Formatter\TaskICalFormatter;
use Eluceo\iCal\Component\Calendar as iCalendar;
/**
@@ -29,10 +28,10 @@ class ICalHelper extends Base
{
$queryBuilder->withFilter(new TaskDueDateRangeFilter(array($start, $end)));
- $formatter = new TaskICalFormatter($this->container);
- $formatter->setColumns('date_due');
- $formatter->setCalendar($calendar);
- $formatter->withQuery($queryBuilder->getQuery());
- $formatter->addFullDayEvents();
+ $this->taskICalFormatter
+ ->setColumns('date_due')
+ ->setCalendar($calendar)
+ ->withQuery($queryBuilder->getQuery())
+ ->addFullDayEvents();
}
}
diff --git a/app/Helper/LayoutHelper.php b/app/Helper/LayoutHelper.php
index 8d2e7e00..8be71757 100644
--- a/app/Helper/LayoutHelper.php
+++ b/app/Helper/LayoutHelper.php
@@ -22,7 +22,10 @@ class LayoutHelper extends Base
*/
public function app($template, array $params = array())
{
- if ($this->request->isAjax()) {
+ $isAjax = $this->request->isAjax();
+ $params['is_ajax'] = $isAjax;
+
+ if ($isAjax) {
return $this->template->render($template, $params);
}
@@ -160,7 +163,7 @@ class LayoutHelper extends Base
$params['title'] = $params['project']['name'].' &gt; '.$params['title'];
}
- return $this->subLayout('analytic/layout', 'analytic/sidebar', $template, $params);
+ return $this->subLayout('analytic/layout', 'analytic/sidebar', $template, $params, true);
}
/**
@@ -188,13 +191,16 @@ class LayoutHelper extends Base
* @param string $sidebar
* @param string $template
* @param array $params
+ * @param bool $ignoreAjax
* @return string
*/
- public function subLayout($sublayout, $sidebar, $template, array $params = array())
+ public function subLayout($sublayout, $sidebar, $template, array $params = array(), $ignoreAjax = false)
{
+ $isAjax = $this->request->isAjax();
+ $params['is_ajax'] = $isAjax;
$content = $this->template->render($template, $params);
- if ($this->request->isAjax()) {
+ if (!$ignoreAjax && $isAjax) {
return $content;
}
diff --git a/app/Helper/ModalHelper.php b/app/Helper/ModalHelper.php
new file mode 100644
index 00000000..efbe2c4d
--- /dev/null
+++ b/app/Helper/ModalHelper.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Kanboard\Helper;
+
+use Kanboard\Core\Base;
+
+/**
+ * Class ModalHelper
+ *
+ * @package Kanboard\Helper
+ * @author Frederic Guillot
+ */
+class ModalHelper extends Base
+{
+ public function submitButtons(array $params = array())
+ {
+ return $this->helper->app->component('submit-buttons', array(
+ 'submitLabel' => isset($params['submitLabel']) ? $params['submitLabel'] : t('Save'),
+ 'orLabel' => t('or'),
+ 'cancelLabel' => t('cancel'),
+ 'color' => isset($params['color']) ? $params['color'] : 'blue',
+ 'tabindex' => isset($params['tabindex']) ? $params['tabindex'] : null,
+ 'disabled' => isset($params['disabled']) ? true : false,
+ ));
+ }
+
+ public function confirmButtons($controller, $action, array $params = array(), $submitLabel = '', $tabindex = null)
+ {
+ return $this->helper->app->component('confirm-buttons', array(
+ 'url' => $this->helper->url->href($controller, $action, $params, true),
+ 'submitLabel' => $submitLabel ?: t('Yes'),
+ 'orLabel' => t('or'),
+ 'cancelLabel' => t('cancel'),
+ 'tabindex' => $tabindex,
+ ));
+ }
+
+ public function largeIcon($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-large" aria-hidden="true"></i>';
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-large', $label);
+ }
+
+ public function large($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-large" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-large');
+ }
+
+ public function medium($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-medium" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-medium');
+ }
+
+ public function small($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-small" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-small');
+ }
+
+ public function mediumButton($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-medium" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-medium btn');
+ }
+
+ public function confirm($icon, $label, $controller, $action, array $params = array())
+ {
+ $html = '<i class="fa fa-'.$icon.' fa-fw js-modal-confirm" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, false, 'js-modal-confirm');
+ }
+
+ public function confirmLink($label, $controller, $action, array $params = array())
+ {
+ return $this->helper->url->link($label, $controller, $action, $params, false, 'js-modal-confirm');
+ }
+
+ public function replaceLink($label, $controller, $action, array $params = array())
+ {
+ return $this->helper->url->link($label, $controller, $action, $params, false, 'js-modal-replace');
+ }
+}
diff --git a/app/Helper/ProjectActivityHelper.php b/app/Helper/ProjectActivityHelper.php
index 704cd4fe..480db3d5 100644
--- a/app/Helper/ProjectActivityHelper.php
+++ b/app/Helper/ProjectActivityHelper.php
@@ -6,7 +6,6 @@ use Kanboard\Core\Base;
use Kanboard\Filter\ProjectActivityProjectIdFilter;
use Kanboard\Filter\ProjectActivityProjectIdsFilter;
use Kanboard\Filter\ProjectActivityTaskIdFilter;
-use Kanboard\Formatter\ProjectActivityEventFormatter;
use Kanboard\Model\ProjectActivityModel;
/**
@@ -38,7 +37,7 @@ class ProjectActivityHelper extends Base
->limit(500)
;
- $events = $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
+ $events = $queryBuilder->format($this->projectActivityEventFormatter);
}
return $events;
@@ -62,7 +61,7 @@ class ProjectActivityHelper extends Base
->limit($limit)
;
- return $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
+ return $queryBuilder->format($this->projectActivityEventFormatter);
}
/**
@@ -83,7 +82,7 @@ class ProjectActivityHelper extends Base
->limit($limit)
;
- return $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
+ return $queryBuilder->format($this->projectActivityEventFormatter);
}
/**
@@ -100,6 +99,6 @@ class ProjectActivityHelper extends Base
$queryBuilder->getQuery()->desc(ProjectActivityModel::TABLE.'.id');
- return $queryBuilder->format(new ProjectActivityEventFormatter($this->container));
+ return $queryBuilder->format($this->projectActivityEventFormatter);
}
}
diff --git a/app/Helper/SubtaskHelper.php b/app/Helper/SubtaskHelper.php
index 833544a7..8e090f17 100644
--- a/app/Helper/SubtaskHelper.php
+++ b/app/Helper/SubtaskHelper.php
@@ -50,7 +50,7 @@ class SubtaskHelper extends Base
return $this->helper->url->link($this->getTitle($subtask), 'SubtaskStatusController', 'change', $params, false, $class);
}
- public function selectTitle(array $values, array $errors = array(), array $attributes = array())
+ public function renderTitleField(array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="1"', 'required', 'maxlength="255"'), $attributes);
@@ -60,7 +60,7 @@ class SubtaskHelper extends Base
return $html;
}
- public function selectAssignee(array $users, array $values, array $errors = array(), array $attributes = array())
+ public function renderAssigneeField(array $users, array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="2"'), $attributes);
@@ -74,7 +74,7 @@ class SubtaskHelper extends Base
return $html;
}
- public function selectTimeEstimated(array $values, array $errors = array(), array $attributes = array())
+ public function renderTimeEstimatedField(array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="3"'), $attributes);
@@ -85,7 +85,7 @@ class SubtaskHelper extends Base
return $html;
}
- public function selectTimeSpent(array $values, array $errors = array(), array $attributes = array())
+ public function renderTimeSpentField(array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="4"'), $attributes);
diff --git a/app/Helper/TaskHelper.php b/app/Helper/TaskHelper.php
index 92a9228c..71596b60 100644
--- a/app/Helper/TaskHelper.php
+++ b/app/Helper/TaskHelper.php
@@ -40,21 +40,28 @@ class TaskHelper extends Base
return $this->taskRecurrenceModel->getRecurrenceBasedateList();
}
- public function selectTitle(array $values, array $errors)
+ public function renderTitleField(array $values, array $errors)
{
- $html = $this->helper->form->label(t('Title'), 'title');
- $html .= $this->helper->form->text('title', $values, $errors, array('autofocus', 'required', 'maxlength="200"', 'tabindex="1"'), 'form-input-large');
- return $html;
+ return $this->helper->form->text(
+ 'title',
+ $values,
+ $errors,
+ array(
+ 'autofocus',
+ 'required',
+ 'maxlength="200"',
+ 'tabindex="1"',
+ 'placeholder="'.t('Title').'"'
+ )
+ );
}
- public function selectDescription(array $values, array $errors)
+ public function renderDescriptionField(array $values, array $errors)
{
- $html = $this->helper->form->label(t('Description'), 'description');
- $html .= $this->helper->form->textEditor('description', $values, $errors, array('tabindex' => 2));
- return $html;
+ return $this->helper->form->textEditor('description', $values, $errors, array('tabindex' => 2));
}
- public function selectTags(array $project, array $tags = array())
+ public function renderTagField(array $project, array $tags = array())
{
$options = $this->tagModel->getAssignableList($project['id']);
@@ -76,7 +83,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectColor(array $values)
+ public function renderColorField(array $values)
{
$colors = $this->colorModel->getList();
$html = $this->helper->form->label(t('Color'), 'color_id');
@@ -84,7 +91,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectAssignee(array $users, array $values, array $errors = array(), array $attributes = array())
+ public function renderAssigneeField(array $users, array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="3"'), $attributes);
@@ -98,7 +105,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectCategory(array $categories, array $values, array $errors = array(), array $attributes = array(), $allow_one_item = false)
+ public function renderCategoryField(array $categories, array $values, array $errors = array(), array $attributes = array(), $allow_one_item = false)
{
$attributes = array_merge(array('tabindex="4"'), $attributes);
$html = '';
@@ -111,7 +118,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectSwimlane(array $swimlanes, array $values, array $errors = array(), array $attributes = array())
+ public function renderSwimlaneField(array $swimlanes, array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="5"'), $attributes);
$html = '';
@@ -124,7 +131,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectColumn(array $columns, array $values, array $errors = array(), array $attributes = array())
+ public function renderColumnField(array $columns, array $values, array $errors = array(), array $attributes = array())
{
$attributes = array_merge(array('tabindex="6"'), $attributes);
@@ -134,7 +141,7 @@ class TaskHelper extends Base
return $html;
}
- public function selectPriority(array $project, array $values)
+ public function renderPriorityField(array $project, array $values)
{
$html = '';
@@ -150,9 +157,9 @@ class TaskHelper extends Base
return $html;
}
- public function selectScore(array $values, array $errors = array(), array $attributes = array())
+ public function renderScoreField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="8"'), $attributes);
+ $attributes = array_merge(array('tabindex="13"'), $attributes);
$html = $this->helper->form->label(t('Complexity'), 'score');
$html .= $this->helper->form->number('score', $values, $errors, $attributes);
@@ -160,9 +167,9 @@ class TaskHelper extends Base
return $html;
}
- public function selectReference(array $values, array $errors = array(), array $attributes = array())
+ public function renderReferenceField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="9"'), $attributes);
+ $attributes = array_merge(array('tabindex="14"'), $attributes);
$html = $this->helper->form->label(t('Reference'), 'reference');
$html .= $this->helper->form->text('reference', $values, $errors, $attributes, 'form-input-small');
@@ -170,9 +177,9 @@ class TaskHelper extends Base
return $html;
}
- public function selectTimeEstimated(array $values, array $errors = array(), array $attributes = array())
+ public function renderTimeEstimatedField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="10"'), $attributes);
+ $attributes = array_merge(array('tabindex="11"'), $attributes);
$html = $this->helper->form->label(t('Original estimate'), 'time_estimated');
$html .= $this->helper->form->numeric('time_estimated', $values, $errors, $attributes);
@@ -181,9 +188,9 @@ class TaskHelper extends Base
return $html;
}
- public function selectTimeSpent(array $values, array $errors = array(), array $attributes = array())
+ public function renderTimeSpentField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="11"'), $attributes);
+ $attributes = array_merge(array('tabindex="12"'), $attributes);
$html = $this->helper->form->label(t('Time spent'), 'time_spent');
$html .= $this->helper->form->numeric('time_spent', $values, $errors, $attributes);
@@ -192,15 +199,15 @@ class TaskHelper extends Base
return $html;
}
- public function selectStartDate(array $values, array $errors = array(), array $attributes = array())
+ public function renderStartDateField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="12"'), $attributes);
+ $attributes = array_merge(array('tabindex="10"'), $attributes);
return $this->helper->form->datetime(t('Start Date'), 'date_started', $values, $errors, $attributes);
}
- public function selectDueDate(array $values, array $errors = array(), array $attributes = array())
+ public function renderDueDateField(array $values, array $errors = array(), array $attributes = array())
{
- $attributes = array_merge(array('tabindex="13"'), $attributes);
+ $attributes = array_merge(array('tabindex="9"'), $attributes);
return $this->helper->form->date(t('Due Date'), 'date_due', $values, $errors, $attributes);
}
@@ -244,7 +251,7 @@ class TaskHelper extends Base
'step1',
array('project_id' => $projectId, 'swimlane_id' => $swimlaneId, 'column_id' => $columnId, 'provider_name' => $providerName),
false,
- 'popover-link'
+ 'js-modal-replace'
);
$html .= '<li><i class="fa fa-fw fa-plus-square" aria-hidden="true"></i> '.$link.'</li>';
diff --git a/app/Helper/UrlHelper.php b/app/Helper/UrlHelper.php
index 93177ed5..94412cf5 100644
--- a/app/Helper/UrlHelper.php
+++ b/app/Helper/UrlHelper.php
@@ -42,9 +42,32 @@ class UrlHelper extends Base
*/
public function button($icon, $label, $controller, $action, array $params = array(), $class = '')
{
- $icon = '<i class="fa '.$icon.' fa-fw"></i> ';
+ $html = '<i class="fa fa-'.$icon.' fa-fw"></i> '.$label;
$class = 'btn '.$class;
- return $this->link($icon.$label, $controller, $action, $params, false, $class);
+ return $this->link($html, $controller, $action, $params, false, $class);
+ }
+
+ /**
+ * Link element with icon
+ *
+ * @access public
+ * @param string $icon Icon name
+ * @param string $label Link label
+ * @param string $controller Controller name
+ * @param string $action Action name
+ * @param array $params Url parameters
+ * @param boolean $csrf Add a CSRF token
+ * @param string $class CSS class attribute
+ * @param string $title Link title
+ * @param boolean $newTab Open the link in a new tab
+ * @param string $anchor Link Anchor
+ * @param bool $absolute
+ * @return string
+ */
+ public function icon($icon, $label, $controller, $action, array $params = array(), $csrf = false, $class = '', $title = '', $newTab = false, $anchor = '', $absolute = false)
+ {
+ $html = '<i class="fa fa-fw fa-'.$icon.'" aria-hidden="true"></i>'.$label;
+ return $this->helper->url->link($html, $controller, $action, $params, $csrf, $class, $title, $newTab, $anchor, $absolute);
}
/**
@@ -58,14 +81,14 @@ class UrlHelper extends Base
* @param boolean $csrf Add a CSRF token
* @param string $class CSS class attribute
* @param string $title Link title
- * @param boolean $new_tab Open the link in a new tab
+ * @param boolean $newTab Open the link in a new tab
* @param string $anchor Link Anchor
* @param bool $absolute
* @return string
*/
- public function link($label, $controller, $action, array $params = array(), $csrf = false, $class = '', $title = '', $new_tab = false, $anchor = '', $absolute = false)
+ public function link($label, $controller, $action, array $params = array(), $csrf = false, $class = '', $title = '', $newTab = false, $anchor = '', $absolute = false)
{
- return '<a href="'.$this->href($controller, $action, $params, $csrf, $anchor, $absolute).'" class="'.$class.'" title=\''.$title.'\' '.($new_tab ? 'target="_blank"' : '').'>'.$label.'</a>';
+ return '<a href="'.$this->href($controller, $action, $params, $csrf, $anchor, $absolute).'" class="'.$class.'" title=\''.$title.'\' '.($newTab ? 'target="_blank"' : '').'>'.$label.'</a>';
}
/**
diff --git a/app/Locale/bs_BA/translations.php b/app/Locale/bs_BA/translations.php
index e27a4501..e689439c 100644
--- a/app/Locale/bs_BA/translations.php
+++ b/app/Locale/bs_BA/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d zadataka na tabli',
'%d tasks in total' => '%d zadataka ukupno',
'Unable to update this board.' => 'Nemogu da ažuriram ovu ploču.',
- 'Edit board' => 'Izmijeni ploču',
'Disable' => 'Onemogući',
'Enable' => 'Omogući',
'New project' => 'Novi projekat',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Naslov',
'Assigned to %s' => 'Dodijeljen korisniku %s',
'Remove a column' => 'Ukloni kolonu',
- 'Remove a column from a board' => 'Ukloni kolonu sa table',
'Unable to remove this column.' => 'Nemoguće uklanjanje kolone.',
'Do you really want to remove this column: "%s"?' => 'Da li zaista želiš da ukoniš ovu kolonu: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Ova akcija BRIŠE SVE ZADATKE vezane za ovu kolonu!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Broj zadataka',
'User' => 'Korisnik',
'Comments' => 'Komentari',
- 'Leave a comment' => 'Ostavi komentar',
'Comment is required' => 'Komentar je obavezan',
- 'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentar uspješno dodan',
'Unable to create your comment.' => 'Nemoguće kreiranje komentara',
'Due Date' => 'Treba biti gotovo do dana',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Pretraga',
'Nothing found.' => 'Ništa nije pronađeno',
'Due date' => 'Treba biti gotovo do dana',
- 'Others formats accepted: %s and %s' => 'Ostali podržani formati: %s i %s',
'Description' => 'Opis',
'%d comments' => '%d Komentara',
'%d comment' => '%d Komentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Kreirao %s',
'Tasks Export' => 'Izvoz zadataka',
'Start Date' => 'Početni datum',
- 'End Date' => 'Datum završetka',
'Execute' => 'Izvrši',
'Task Id' => 'Identifikator zadatka',
'Creator' => 'Autor',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Udaljeno',
'Enabled' => 'Omogućeno',
'Disabled' => 'Onemogućeno',
- 'Username:' => 'Korisničko ime:',
- 'Name:' => 'Ime i Prezime',
+ 'Login:' => 'Korisničko ime:',
+ 'Full Name:' => 'Ime i Prezime',
'Email:' => 'Email: ',
'Notifications:' => 'Obavještenja: ',
'Notifications' => 'Obavještenja',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Veza s etiketama',
'Link modification' => 'Veza modifikacija',
'Links' => 'Veze',
- 'Link settings' => 'Postavke veza',
'Opposite label' => 'Suprotna etiketa',
'Remove a link' => 'Ukloni vezu',
- 'Task\'s links' => 'Veze zadatka',
'The labels must be different' => 'Etikete moraju biti različite',
'There is no link.' => 'Ovdje nema veza',
'This label must be unique' => 'Ova etiketa mora biti jedinstvena',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompaktan pregled',
'Horizontal scrolling' => 'Horizontalno listanje',
'Compact/wide view' => 'Skupi/raširi pregled',
- 'No results match:' => 'Nema rezultata:',
'Currency' => 'Valuta',
'Private project' => 'Privatni projekat',
'AUD - Australian Dollar' => 'AUD - Australijski dolar',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japanski jen',
'NZD - New Zealand Dollar' => 'NZD - Novozelandski dolar',
'RSD - Serbian dinar' => 'RSD - Srpski dinar',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Američki dolar',
'Destination column' => 'Odredišna kolona',
'Move the task to another column when assigned to a user' => 'Premjesti zadatak u neku drugu kolonu kada se dodijeli izvršiocu',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Stopa valute',
'Rate' => 'Stopa',
'Change reference currency' => 'Promijeni referencu valute',
- 'Add a new currency rate' => 'Dodaj novu stopu valute',
'Reference currency' => 'Referentna valuta',
'The currency rate have been added successfully.' => 'Stopa valute je uspješno dodana.',
'Unable to add this currency rate.' => 'Nemoguće dodati stopu valute.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Zaustavi tajmer',
'Start timer' => 'Pokreni tajmer',
- 'Add project member' => 'Dodaj člana projekta',
'My activity stream' => 'Tok mojih aktivnosti',
'My calendar' => 'Moj kalendar',
'Search tasks' => 'Pretraga zadataka',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Vanjski korisnik',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Vanjski korisnik ne čuva šifru u Kanboard bazi, npr: LDAP, Google i Github korisnički računi.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Ako ste označili kvadratić "Zabrani prijavnu formu", unos pristupnih podataka u prijavnoj formi će biti ignorisan.',
- 'New remote user' => 'Novi vanjski korisnik',
- 'New local user' => 'Novi lokalni korisnik',
'Default task color' => 'Podrazumijevana boja zadatka',
'This feature does not work with all browsers.' => 'Ovaj funkcionalnost ne radi na svim internet pretraživačima.',
'There is no destination project available.' => 'Nema definisanog odredišta za projekat.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Vlasnik',
'Unread notifications' => 'Nepročitana obavještenja',
'Notification methods:' => 'Metode obavještenja:',
- 'Import tasks from CSV file' => 'Uvezi zadatke putem CSV fajla',
'Unable to read your file' => 'Nemoguće pročitati fajl',
'%d task(s) have been imported successfully.' => '%d zadataka uspješno uvezeno.',
'Nothing have been imported!' => 'Ništa nije uvezeno!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Vlasnik projekta:',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Identifikator projekta je opcionalan i mora biti alfanumerički, na primjer: MOJPROJEKAT.',
'Project owner' => 'Vlasnik projekta',
- 'Those dates are useful for the project Gantt chart.' => 'Ovi datumi su korisni za pravljenje Gantt dijagrama za projekat.',
'Private projects do not have users and groups management.' => 'Privatni projekti ne mogu imati korisnike ili grupe korisnika.',
'There is no project member.' => 'Nema članova projekta.',
'Priority' => 'Prioritet',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Početo:',
'Moved:' => 'Pomjereno:',
'Task #%d' => 'Zadatak #%d',
- 'Date and time format' => 'Format za datum i vrijeme',
'Time format' => 'Format za vrijeme',
'Start date: ' => 'Početni datum:',
'End date: ' => 'Krajnji datum:',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Korisnik uspješno onemogućen.',
'Unable to disable this user.' => 'Nemoguće onemogućiti ovog korisnika.',
'All files have been uploaded successfully.' => 'Svi fajlovi su uspješno dodani.',
- 'View uploaded files' => 'Pregled dodanih fajlova',
'The maximum allowed file size is %sB.' => 'Maksimalna dozvoljena veličina fajla je %sB.',
- 'Choose files again' => 'Izaberi ponovo fajlove',
'Drag and drop your files here' => 'Povuci i spusti svoje fajlove ovdje',
'choose files' => 'izaberi fajlove',
'View profile' => 'Pregledaj profil',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/cs_CZ/translations.php b/app/Locale/cs_CZ/translations.php
index 5091de00..6299f514 100644
--- a/app/Locale/cs_CZ/translations.php
+++ b/app/Locale/cs_CZ/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d úkolů na nástěnce',
'%d tasks in total' => '%d úkolů celkem',
'Unable to update this board.' => 'Nástěnku není možné aktualizovat',
- 'Edit board' => 'Editace nástěnky',
'Disable' => 'Zakázat projekt',
'Enable' => 'Povolit projekt',
'New project' => 'Nový projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Název',
'Assigned to %s' => 'Přiřazeno uživateli: %s',
'Remove a column' => 'Vyjmout sloupec',
- 'Remove a column from a board' => 'Vyjmout sloupec z nástěnky',
'Unable to remove this column.' => 'Tento sloupec nelze odstranit',
'Do you really want to remove this column: "%s"?' => 'Opravdu chcete vyjmout tento sloupec: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Tato akce vyjme všechny úkoly přiřazený k tomuto sloupci!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Počet úkolů',
'User' => 'Uživatel',
'Comments' => 'Komentáře',
- 'Leave a comment' => 'Zanechte komentář',
'Comment is required' => 'Komentář je vyžadován',
- 'Leave a description' => 'Vložte popis',
'Comment added successfully.' => 'Komentář byl úspěšně přidán.',
'Unable to create your comment.' => 'Komentář nelze vytvořit.',
'Due Date' => 'Datum splnění',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Vyhledat',
'Nothing found.' => 'Nenalezena žádná položka.',
'Due date' => 'Plánovaný termín',
- 'Others formats accepted: %s and %s' => 'Akceptovány jiné formáty: %s und %s',
'Description' => 'Podrobný popis',
'%d comments' => '%d komentářů',
'%d comment' => '%d komentář',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Vytvořeno uživatelem %s',
'Tasks Export' => 'Export úkolů',
'Start Date' => 'Počáteční datum',
- 'End Date' => 'Konečné datum',
'Execute' => 'Spustit',
'Task Id' => 'Úkol ID',
'Creator' => 'Vlastník',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Vzdálený',
'Enabled' => 'Povoleno',
'Disabled' => 'Zakázáno',
- 'Username:' => 'Uživatelské jméno:',
- 'Name:' => 'Jméno:',
+ 'Login:' => 'Uživatelské jméno:',
+ 'Full Name:' => 'Jméno:',
'Email:' => 'e-mail',
'Notifications:' => 'Upozornění:',
'Notifications' => 'Upozornění',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Seznam odkazů',
'Link modification' => 'Úpravy odkazů',
'Links' => 'Odkazy',
- 'Link settings' => 'Nastavení odkazů',
'Opposite label' => 'Opačný text',
'Remove a link' => 'Odstranit odkaz',
- 'Task\'s links' => 'Související odkazy',
'The labels must be different' => 'názvy musí být odlišné',
'There is no link.' => 'Nejsou zde žádné odkazy',
'This label must be unique' => 'Tento název musí být jedinečný',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompaktní zobrazení',
'Horizontal scrolling' => 'Horizontální rolování',
'Compact/wide view' => 'Kompaktní/plné zobrazení',
- 'No results match:' => 'Žádná shoda:',
'Currency' => 'Měna',
'Private project' => 'Soukromý projekt',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japanischer Yen',
'NZD - New Zealand Dollar' => 'NZD - Neuseeland-Dollar',
'RSD - Serbian dinar' => 'RSD - Serbische Dinar',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - US Dollar',
'Destination column' => 'Cílový sloupec',
'Move the task to another column when assigned to a user' => 'Přesunout úkol do jiného sloupce, když je úkol přiřazen uživateli.',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Aktuální kurzy',
'Rate' => 'Kurz',
'Change reference currency' => 'Změnit referenční měnu',
- 'Add a new currency rate' => 'Přidat nový směnný kurz',
'Reference currency' => 'Referenční měna',
'The currency rate have been added successfully.' => 'Směnný kurz byl úspěšně přidán.',
'Unable to add this currency rate.' => 'Nelze přidat tento směnný kurz',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30min.',
'Stop timer' => 'Zastavit časovač',
'Start timer' => 'Spustit časovač',
- 'Add project member' => 'Přidat člena projektu',
'My activity stream' => 'Přehled mých aktivit',
'My calendar' => 'Můj kalendář',
'Search tasks' => 'Hledání úkolů',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Vzdálený uživatel',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Hesla vzdáleným uživatelům se neukládají do databáze Kanboard. Naříklad: LDAP, Google a Github účty.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Pokud zaškrtnete políčko "Zakázat přihlašovací formulář", budou pověření zadané do přihlašovacího formuláře ignorovány.',
- 'New remote user' => 'Nový vzdálený uživatel',
- 'New local user' => 'Nový lokální uživatel',
'Default task color' => 'Výchozí barva úkolu',
'This feature does not work with all browsers.' => 'Tato funkcionalita nefunguje ve všech prohlížečích.',
'There is no destination project available.' => 'Není dostupný žádný cílový projekt.',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 2ca864e5..87d65e87 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d Opgaver på boardet',
'%d tasks in total' => '%d Opgaver i alt',
'Unable to update this board.' => 'Ikke muligt at opdatere dette board',
- 'Edit board' => 'Rediger board',
'Disable' => 'Deaktiver',
'Enable' => 'Aktiver',
'New project' => 'Nyt projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titel',
'Assigned to %s' => 'Ansvarlig: %s',
'Remove a column' => 'Fjern en kolonne',
- 'Remove a column from a board' => 'Fjern en kolonne fra et board',
'Unable to remove this column.' => 'Ikke muligt at fjerne denne kolonne',
'Do you really want to remove this column: "%s"?' => 'Vil du virkelig fjerne denne kolonne: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Denne handling vil SLETTE ALLE OPGAVER tilknyttet denne kolonne',
@@ -160,9 +158,7 @@ return array(
// 'Task count' => '',
'User' => 'Bruger',
'Comments' => 'Kommentarer',
- 'Leave a comment' => 'Efterlad en kommentar',
'Comment is required' => 'Kommentar er krævet',
- 'Leave a description' => 'Efterlad en beskrivelse...',
'Comment added successfully.' => 'Kommentaren er tilføjet.',
'Unable to create your comment.' => 'Din kommentar kunne ikke oprettes.',
'Due Date' => 'Forfaldsdato',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Søg',
'Nothing found.' => 'Intet fundet.',
'Due date' => 'Forfaldsdato',
- 'Others formats accepted: %s and %s' => 'Andre acceptable formater: %s und %s',
'Description' => 'Beskrivelse',
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Oprettet af %s',
'Tasks Export' => 'Opgave eksport',
'Start Date' => 'Start-dato',
- 'End Date' => 'Slut-dato',
'Execute' => 'Udfør',
'Task Id' => 'Opgave ID',
'Creator' => 'Skaber',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remote',
'Enabled' => 'Aktiv',
'Disabled' => 'Deaktiveret',
- 'Username:' => 'Brugernavn',
- 'Name:' => 'Navn:',
+ 'Login:' => 'Brugernavn',
+ 'Full Name:' => 'Navn:',
'Email:' => 'Email:',
'Notifications:' => 'Notifikationer:',
'Notifications' => 'Notifikationer',
@@ -516,10 +510,8 @@ return array(
// 'Link labels' => '',
// 'Link modification' => '',
// 'Links' => '',
- // 'Link settings' => '',
// 'Opposite label' => '',
// 'Remove a link' => '',
- // 'Task\'s links' => '',
// 'The labels must be different' => '',
// 'There is no link.' => '',
// 'This label must be unique' => '',
@@ -552,7 +544,6 @@ return array(
// 'Compact view' => '',
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
- // 'No results match:' => '',
// 'Currency' => '',
// 'Private project' => '',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
// 'JPY - Japanese Yen' => '',
// 'NZD - New Zealand Dollar' => '',
// 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
// 'USD - US Dollar' => '',
// 'Destination column' => '',
// 'Move the task to another column when assigned to a user' => '',
@@ -580,7 +572,6 @@ return array(
// 'Currency rates' => '',
// 'Rate' => '',
// 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
// 'Stop timer' => '',
// 'Start timer' => '',
- // 'Add project member' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
// 'Default task color' => '',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 950a3b77..adefbf13 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d Aufgaben auf dieser Pinnwand',
'%d tasks in total' => '%d Aufgaben insgesamt',
'Unable to update this board.' => 'Ändern dieser Pinnwand nicht möglich.',
- 'Edit board' => 'Pinnwand bearbeiten',
'Disable' => 'Deaktivieren',
'Enable' => 'Aktivieren',
'New project' => 'Neues Projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titel',
'Assigned to %s' => 'Zuständig: %s',
'Remove a column' => 'Spalte löschen',
- 'Remove a column from a board' => 'Spalte einer Pinnwand löschen',
'Unable to remove this column.' => 'Löschen dieser Spalte nicht möglich.',
'Do you really want to remove this column: "%s"?' => 'Soll diese Spalte wirklich gelöscht werden: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'ALLE AUFGABEN dieser Spalte werden GELÖSCHT!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Aufgabenanzahl',
'User' => 'Benutzer',
'Comments' => 'Kommentare',
- 'Leave a comment' => 'Kommentar eingeben',
'Comment is required' => 'Ein Kommentar wird benötigt',
- 'Leave a description' => 'Beschreibung eingeben',
'Comment added successfully.' => 'Kommentar erfolgreich hinzugefügt.',
'Unable to create your comment.' => 'Hinzufügen eines Kommentars nicht möglich.',
'Due Date' => 'Fällig am',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Suchen',
'Nothing found.' => 'Nichts gefunden.',
'Due date' => 'Fälligkeitsdatum',
- 'Others formats accepted: %s and %s' => 'Andere akzeptierte Formate: %s und %s',
'Description' => 'Beschreibung',
'%d comments' => '%d Kommentare',
'%d comment' => '%d Kommentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Erstellt durch %s',
'Tasks Export' => 'Aufgaben exportieren',
'Start Date' => 'Anfangsdatum',
- 'End Date' => 'Enddatum',
'Execute' => 'Ausführen',
'Task Id' => 'Aufgaben ID',
'Creator' => 'Erstellt von',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remote',
'Enabled' => 'angeschaltet',
'Disabled' => 'abgeschaltet',
- 'Username:' => 'Benutzername:',
- 'Name:' => 'Name:',
+ 'Login:' => 'Benutzername:',
+ 'Full Name:' => 'Vollständiger Name:',
'Email:' => 'E-Mail:',
'Notifications:' => 'Benachrichtigungen:',
'Notifications' => 'Benachrichtigungen',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Verbindungsbeschriftung',
'Link modification' => 'Verbindung ändern',
'Links' => 'Verbindungen',
- 'Link settings' => 'Verbindungseinstellungen',
'Opposite label' => 'Gegenteil',
'Remove a link' => 'Verbindung entfernen',
- 'Task\'s links' => 'Aufgaben-Verbindungen',
'The labels must be different' => 'Die Beschriftung muss unterschiedlich sein',
'There is no link.' => 'Es gibt keine Verbindung',
'This label must be unique' => 'Die Beschriftung muss einzigartig sein',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompaktansicht',
'Horizontal scrolling' => 'Horizontales Scrollen',
'Compact/wide view' => 'Kompakt/Breite-Ansicht',
- 'No results match:' => 'Keine Ergebnisse:',
'Currency' => 'Währung',
'Private project' => 'privates Projekt',
'AUD - Australian Dollar' => 'AUD - Australische Dollar',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japanische Yen',
'NZD - New Zealand Dollar' => 'NZD - Neuseeland-Dollar',
'RSD - Serbian dinar' => 'RSD - Serbische Dinar',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - US-Dollar',
'Destination column' => 'Zielspalte',
'Move the task to another column when assigned to a user' => 'Aufgabe in eine andere Spalte verschieben, wenn ein User zugeordnet wurde.',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Währungskurse',
'Rate' => 'Kurse',
'Change reference currency' => 'Referenzwährung ändern',
- 'Add a new currency rate' => 'Neuen Währungskurs hinzufügen',
'Reference currency' => 'Referenzwährung',
'The currency rate have been added successfully.' => 'Der Währungskurs wurde erfolgreich hinzugefügt.',
'Unable to add this currency rate.' => 'Währungskurs konnte nicht hinzugefügt werden',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30min',
'Stop timer' => 'Stoppe Timer',
'Start timer' => 'Starte Timer',
- 'Add project member' => 'Projektmitglied hinzufügen',
'My activity stream' => 'Aktivitätsstream',
'My calendar' => 'Mein Kalender',
'Search tasks' => 'Suche nach Aufgaben',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Remote-Benutzer',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Remote-Benutzer haben kein Passwort in der Kanboard Datenbank, Beispiel: LDAP, Google und Github Accounts',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Wenn die Box "Verbiete Login-Formular" angeschaltet ist, werden Eingaben in das Login Formular ignoriert.',
- 'New remote user' => 'Neuer Remote-Benutzer',
- 'New local user' => 'Neuer lokaler Benutzer',
'Default task color' => 'Voreingestellte Aufgabenfarbe',
'This feature does not work with all browsers.' => 'Diese Funktion funktioniert nicht mit allen Browsern',
'There is no destination project available.' => 'Es ist kein Zielprojekt vorhanden.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Eigentümer',
'Unread notifications' => 'Ungelesene Benachrichtigungen',
'Notification methods:' => 'Benachrichtigungs-Methoden:',
- 'Import tasks from CSV file' => 'Importiere Aufgaben aus CSV Datei',
'Unable to read your file' => 'Die Datei kann nicht gelesen werden',
'%d task(s) have been imported successfully.' => '%d Aufgabe(n) wurde(n) erfolgreich importiert',
'Nothing have been imported!' => 'Es wurde nichts importiert!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Projekt-Besitzer: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Die Projekt-Kennung ist optional und muss alphanumerisch sein, beispielsweise: MYPROJECT.',
'Project owner' => 'Projekt-Besitzer',
- 'Those dates are useful for the project Gantt chart.' => 'Diese Daten sind nützlich für das Gantt-Diagramm.',
'Private projects do not have users and groups management.' => 'Private Projekte haben kein Benutzer- und Gruppen-Management.',
'There is no project member.' => 'Es gibt kein Projekt-Mitglied.',
'Priority' => 'Priorität',
@@ -1009,7 +995,7 @@ return array(
'Add a new external link' => 'Füge eine neue externe Verbindung hinzu',
'Edit external link' => 'Externe Verbindung bearbeiten',
'External link' => 'Externe Verbindung',
- 'Copy and paste your link here...' => 'Kopieren Sie Ihren Link hier...',
+ 'Copy and paste your link here...' => 'Kopieren Sie Ihren Link hierher...',
'URL' => 'URL',
'Internal links' => 'Interne Verbindungen',
'Assign to me' => 'Mir zuweisen',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Gestarted:',
'Moved:' => 'Verschoben:',
'Task #%d' => 'Aufgabe #%d',
- 'Date and time format' => 'Datums- und Zeitformat',
'Time format' => 'Zeitformat',
'Start date: ' => 'Anfangsdatum: ',
'End date: ' => 'Enddatum: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Benutzer erfolgreich deaktiviert.',
'Unable to disable this user.' => 'Dieser Benutzer kann nicht deaktiviert werden.',
'All files have been uploaded successfully.' => 'Alle Dateien wurden erfolgreich hochgeladen.',
- 'View uploaded files' => 'Hochgeladene Dateien ansehen',
'The maximum allowed file size is %sB.' => 'Die maximal erlaubte Dateigröße ist %sB.',
- 'Choose files again' => 'Wählen Sie erneut Dateien aus',
'Drag and drop your files here' => 'Ziehen Sie Ihre Dateien hier hin',
'choose files' => 'Dateien auswählen',
'View profile' => 'Profil ansehen',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => 'E-Mail Absender Adresse',
'Email transport' => 'E-Mail Verkehr',
'Webhook token' => 'Webhook Token',
- 'Imports' => 'Importe',
'Project tags management' => 'Projektbezogenes Schlagwort-Management',
'Tag created successfully.' => 'Schlagwort erfolgreich erstellt.',
'Unable to create this tag.' => 'Das Schlagwort kann nicht erstellt werden.',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Aktivitätenstrom für %s',
'Calendar for %s' => 'Kalender für %s',
'Notifications for %s' => 'Benachrichtigungen für %s',
- 'Subtasks export' => 'Teilaufgaben Export',
- 'Tasks exportation' => 'Aufgaben Export',
'Assign a color when the task is moved to a specific swimlane' => 'Einer Aufgabe eine Farbe zuweisen, wenn diese in eine bestimmte Swimlane verschoben wird',
'Assign a priority when the task is moved to a specific swimlane' => 'Einer Aufgabe eine Priorität zuweisen, wenn diese in eine bestimmte Swimlane verschoben wird',
'User unlocked successfully.' => 'Benutzer erfolgreich entsperrt.',
@@ -1278,13 +1258,53 @@ return array(
'Moving a task is not permitted' => 'Verschieben einer Aufgabe ist nicht erlaubt',
'This value must be in the range %d to %d' => 'Dieser Wert muss im Bereich %d bis %d sein',
'You are not allowed to move this task.' => 'Sie haben nicht die Berechtigung, diese Aufgabe zu verschieben.',
- // 'API User Access' => '',
- // 'Preview' => '',
- // 'Write' => '',
- // 'Write your text in Markdown' => '',
- // 'New External Task: %s' => '',
- // 'No personal API access token registered.' => '',
- // 'Your personal API access token is "%s"' => '',
- // 'Remove your token' => '',
- // 'Generate a new token' => '',
+ 'API User Access' => 'API Benutzerzugriff',
+ 'Preview' => 'Vorschau',
+ 'Write' => 'Schreiben',
+ 'Write your text in Markdown' => 'Schreiben Sie iHren Text in Markdown',
+ 'New External Task: %s' => 'Neue externe Aufgabe: %s',
+ 'No personal API access token registered.' => 'Keine persönlichen API-Zugriffsinformationen registriert',
+ 'Your personal API access token is "%s"' => 'Ihre persönlichen API-Zugriffsinformationen: "%s"',
+ 'Remove your token' => 'Ihre Zugriffsinformationen entfernen',
+ 'Generate a new token' => 'Neue Zugriffsinformationen generieren',
+ 'Showing %d-%d of %d' => 'Zeige %d-%d of %d',
+ 'Outgoing Emails' => 'Ausgehende E-Mails',
+ 'Add or change currency rate' => 'Wechselkurs hinzufügen oder ändern',
+ 'Reference currency: %s' => 'Referenzwährung: %s',
+ 'Add custom filters' => 'Benutzerdefinierten Filter hinzufügen',
+ 'Export' => 'Exportieren',
+ 'Add link label' => 'Linkbeschreibung hinzufügen',
+ 'Incompatible Plugins' => 'Nicht-kompatible Plugins',
+ 'Compatibility' => 'Kompatibilität',
+ 'Permissions and ownership' => 'Berechtigungen und Besitz',
+ 'Priorities' => 'Prioritäten',
+ 'Close this window' => 'Dieses Fenster schließen',
+ 'Unable to upload this file.' => 'Diese Datei kann nicht hochgeladen werden',
+ 'Import tasks' => 'Aufgaben importieren',
+ 'Choose a project' => 'Wählen Sie ein Projekt',
+ 'Profile' => 'Profil',
+ 'Application role' => 'Anwendungsrolle',
+ '%d invitations were sent.' => '%d Einladungen wurden gesendet.',
+ '%d invitation was sent.' => '%d Einladung wurde gesendet.',
+ 'Unable to create this user.' => 'Dieser Benutzer kann nicht erstellt werden.',
+ 'Kanboard Invitation' => 'Kanboard Einladung',
+ 'Visible on dashboard' => 'Sichtbar auf dem Dashboard',
+ 'Created at:' => 'Erstellt am:',
+ 'Updated at:' => 'Aktualisiert am:',
+ 'There is no custom filter.' => 'Es gibt keinen benutzerdefinierten Filter.',
+ 'New User' => 'Neuer Benutzer',
+ 'Authentication' => 'Authentifizierung',
+ 'If checked, this user will use a third-party system for authentication.' => 'Wenn aktiviert, verwendet dieser Benutzer ein Drittanbieter-System für die Authentifizierung.',
+ 'The password is necessary only for local users.' => 'Das Passwort ist nur für lokale Benutzer erforderlich.',
+ 'You have been invited to register on Kanboard.' => 'Sie wurden eingeladen, sich auf Kanboard zu registrieren.',
+ 'Click here to join your team' => 'Klicken Sie hier, um Ihrem Team beizutreten',
+ 'Invite people' => 'Leute einladen',
+ 'Emails' => 'E-Mail',
+ 'Enter one email address by line.' => 'Geben Sie eine E-Mail-Adresse pro Zeile ein.',
+ 'Add these people to this project' => 'Füge diese Personen diesem Projekt hinzu',
+ 'Add this person to this project' => 'Füge diese Persone diesem Projekt hinzu',
+ 'Sign-up' => 'Anmelden',
+ 'Credentials' => 'Anmeldeinformationen',
+ 'New user' => 'Neuer Benutzer',
+ 'This username is already taken' => 'Dieser Benutzername ist bereits vergeben',
);
diff --git a/app/Locale/el_GR/translations.php b/app/Locale/el_GR/translations.php
index 7b7d855e..959b32d2 100644
--- a/app/Locale/el_GR/translations.php
+++ b/app/Locale/el_GR/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d εργασίες στον κεντρικό πίνακα έργου',
'%d tasks in total' => '%d εργασιών στο σύνολο',
'Unable to update this board.' => 'Αδύνατη η ενημέρωση αυτού του πίνακα',
- 'Edit board' => 'Ενημέρωση πίνακα',
'Disable' => 'Απενεργοποίηση',
'Enable' => 'Ενεργοποίηση',
'New project' => 'Νέο έργο',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Τίτλος',
'Assigned to %s' => 'Ανατιθεμένο στον %s',
'Remove a column' => 'Αφαίρεση στήλης',
- 'Remove a column from a board' => 'Αφαίρεση στήλης από τον πίνακα',
'Unable to remove this column.' => 'Αδύνατη η αφαίρεση της στήλης',
'Do you really want to remove this column: "%s"?' => 'Θέλετε να αφαιρέσετε τη στήλη: « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Αυτή η ενέργεια θα ΑΦΑΙΡΕΣΕΙ ΟΛΕΣ ΤΙΣ ΕΡΓΑΣΙΕΣ που είναι σχετικές με τη στήλη!!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Αρίθμηση εργασιών',
'User' => 'Χρήστης',
'Comments' => 'Σχόλια',
- 'Leave a comment' => 'Αφήστε ένα σχόλιο',
'Comment is required' => 'Το σχόλιο απαιτείται',
- 'Leave a description' => 'Αφήστε μια περιγραφή',
'Comment added successfully.' => 'Το σχόλιο σας προστέθηκε με επιτυχία.',
'Unable to create your comment.' => 'Δεν είναι δυνατή η προσθήκη του σχολίου σας.',
'Due Date' => 'Μέχρι την ημερομηνία',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Αναζήτηση',
'Nothing found.' => 'Δεν βρέθηκε.',
'Due date' => 'Μέχρι την ημερομηνία',
- 'Others formats accepted: %s and %s' => 'Άλλες δεκτές μορφοποιήσεις: %s και %s',
'Description' => 'Περιγραφή',
'%d comments' => '%d σχόλια',
'%d comment' => '%d σχόλιο',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Δημιουργήθηκε από %s',
'Tasks Export' => 'Εξαγωγή εργασιών',
'Start Date' => 'Ημερομηνία έναρξης',
- 'End Date' => 'ημερομηνία λήξης',
'Execute' => 'Εκτέλεση',
'Task Id' => 'Task Id',
'Creator' => 'Δημιουργός',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Απομακρυσμένη',
'Enabled' => 'Ενεργή',
'Disabled' => 'Απενεργοποιημένη',
- 'Username:' => 'Username:',
- 'Name:' => 'Όνομα:',
+ 'Login:' => 'Login:',
+ 'Full Name:' => 'Όνομα:',
'Email:' => 'Email:',
'Notifications:' => 'Ειδοποιήσεις:',
'Notifications' => 'Ειδοποιήσεις',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Link labels',
'Link modification' => 'Τροποποίηση Link ',
'Links' => 'Links',
- 'Link settings' => 'Ρυθμίσεις συνδέσμων',
'Opposite label' => 'Αντίθετο label',
'Remove a link' => 'Αφαίρεση ενός link',
- 'Task\'s links' => 'Σύνδεσμοι εργασιών',
'The labels must be different' => 'Τα label πρέπει να είναι διαφορετικά',
'There is no link.' => 'Δεν υπάρχει σύνδεσμος.',
'This label must be unique' => 'Το label πρέπει να είναι μοναδικό',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Συμπυκνωμένη προβολή',
'Horizontal scrolling' => 'Οριζόντια ολίσθηση',
'Compact/wide view' => 'Συμπυκνωμένη/Ευρεία Προβολή',
- 'No results match:' => 'Δεν ταιριάζει κανένα αποτέλεσμα:',
'Currency' => 'Νόμισμα',
'Private project' => 'Ιδιωτικό έργο',
'AUD - Australian Dollar' => 'AUD - Australian Dollar',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japanese Yen',
'NZD - New Zealand Dollar' => 'NZD - New Zealand Dollar',
'RSD - Serbian dinar' => 'RSD - Serbian dinar',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - US Dollar',
'Destination column' => 'Στήλη προορισμού',
'Move the task to another column when assigned to a user' => 'Μετακινήστε την εργασία σε άλλη στήλη όταν ανατεθεί σε ένα χρήστη',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Ισοτιμίες',
'Rate' => 'Τιμή',
'Change reference currency' => 'Αλλαγή ισοτιμίας',
- 'Add a new currency rate' => 'Προσθήκη ισοτιμίας',
'Reference currency' => 'Αναφορά ισοτιμίας',
'The currency rate have been added successfully.' => 'Η ισοτιμία προστέθηκε με επιτυχία.',
'Unable to add this currency rate.' => 'Αδύνατο να προστεθεί αυτή η ισοτιμία.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Διακοπή ρολογιού',
'Start timer' => 'Έναρξη ρολογιού',
- 'Add project member' => 'Προσθήκη νέου μέλους έργου',
'My activity stream' => 'Η ροή δραστηριοτήτων μου',
'My calendar' => 'Το ημερολόγιο μου',
'Search tasks' => 'Αναζήτηση εργασιών',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Απομακρυσμένος χρήστης',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Στους απομακρυσμένους χρήστες δεν αποθηκεύονται οι κωδικοί πρόσβασης εντός της βάσης δεδομένων της τρέχουσας εφαρμογής, Παραδείγματα: LDAP, Google and Github accounts.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Αν ενεργοποιήσετε την επιλογή "Απαγόρευση φόρμας σύνδεσης", τα στοιχεία που εισάγονται στη φόρμα σύνδεσης αγνοούνται.',
- 'New remote user' => 'Νέος απομακρυσμένος χρήστης',
- 'New local user' => 'Νέος τοπικός χρήστης',
'Default task color' => 'Προεπιλογή χρώματος εργασίας',
'This feature does not work with all browsers.' => 'Αυτή η δυνατότητα δεν δουλεύει σε όλους τους browsers',
'There is no destination project available.' => 'Δεν υπάρχει διαθέσιμο κανένα έργο προορισμού.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Ιδιοκτήτης',
'Unread notifications' => 'Αδιάβαστες ειδοποιήσεις',
'Notification methods:' => 'Μέθοδοι ειδοποίησης:',
- 'Import tasks from CSV file' => 'Εισαγωγή εργασιών μέσω αρχείου CSV',
'Unable to read your file' => 'Δεν είναι δυνατή η ανάγνωση του αρχείου',
'%d task(s) have been imported successfully.' => '%d η(οι) εργασία(ες) εισήχθησαν με επιτυχία.',
'Nothing have been imported!' => 'Τίποτα δεν εισήχθη',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Ιδιοκτήτης έργου: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Το αναγνωριστικό έργου είναι προαιρετικό και πρέπει να είναι αλφαριθμητικό, για παράδειγμα: MYPROJECT',
'Project owner' => 'Ιδιοκτήτης έργου',
- 'Those dates are useful for the project Gantt chart.' => 'Οι ημερομηνίες αυτές είανι χρήσιμες για το διάγραμμα Gantt του έργου',
'Private projects do not have users and groups management.' => 'Τα ιδιωτικά έργα δεν έχουν χρήστες και διαχείριση ομάδων',
'There is no project member.' => 'Δεν υπάρχει μέλος στο έργο',
'Priority' => 'Προτεραιότητα',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Ξεκίνησε:',
'Moved:' => 'Μετακινήθηκε:',
'Task #%d' => 'Εργασία #%d',
- 'Date and time format' => 'Μορφή ημερομηνίας και ώρας',
'Time format' => 'Μορφή ώρας',
'Start date: ' => 'Ημερομηνία έναρξης: ',
'End date: ' => 'Ημερομηνία λήξης: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Η απενεργοποίηση του χρήστη έγινε με επιτυχία',
'Unable to disable this user.' => 'Δεν είναι δυνατή η απενεργοποίηση του χρήστη',
'All files have been uploaded successfully.' => 'Όλα τα αρχεία ανέβηκαν με επιτυχία',
- 'View uploaded files' => 'Προβολή ανεβασμένων αρχείων',
'The maximum allowed file size is %sB.' => 'Το μέγιστο μέγεθος αρχείου που επιτρέπεται είναι %sB.',
- 'Choose files again' => 'Επιλογή κι άλλων αρχείων',
'Drag and drop your files here' => 'Σύρετε τα αρχεία σας εδώ',
'choose files' => 'Επιλογή αρχείων',
'View profile' => 'Προβολή προφίλ',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 984d42db..5f5d71e1 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tareas en el tablero',
'%d tasks in total' => '%d tareas en total',
'Unable to update this board.' => 'No se puede actualizar este tablero.',
- 'Edit board' => 'Modificar este tablero',
'Disable' => 'Desactivar',
'Enable' => 'Activar',
'New project' => 'Nuevo proyecto',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Título',
'Assigned to %s' => 'Asignada a %s',
'Remove a column' => 'Eliminar esta columna',
- 'Remove a column from a board' => 'Eliminar una columna de un tablero',
'Unable to remove this column.' => 'No se puede eliminar esta columna.',
'Do you really want to remove this column: "%s"?' => '¿De vedad que desea eliminar esta columna: «%s»?',
'This action will REMOVE ALL TASKS associated to this column!' => '¡Esta acción ELIMINARÁ TODAS LAS TAREAS asociadas a esta columna!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Contador de tareas',
'User' => 'Usuario',
'Comments' => 'Comentarios',
- 'Leave a comment' => 'Dejar un comentario',
'Comment is required' => 'El comentario es obligatorio',
- 'Leave a description' => 'Dejar una descripción',
'Comment added successfully.' => 'El comentario ha sido añadido correctamente.',
'Unable to create your comment.' => 'No se puede crear este comentario.',
'Due Date' => 'Fecha límite',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Buscar',
'Nothing found.' => 'No se ha encontrado nada.',
'Due date' => 'Fecha límite',
- 'Others formats accepted: %s and %s' => 'Otros formatos aceptados: %s y %s',
'Description' => 'Descripción',
'%d comments' => '%d comentarios',
'%d comment' => '%d comentario',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Creado por %s',
'Tasks Export' => 'Exportar tareas',
'Start Date' => 'Fecha de inicio',
- 'End Date' => 'Fecha final',
'Execute' => 'Ejecutar',
'Task Id' => 'Identificador de tarea',
'Creator' => 'Creador',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remota',
'Enabled' => 'Activada',
'Disabled' => 'Desactivada',
- 'Username:' => 'Nombre de usuario:',
- 'Name:' => 'Nombre:',
+ 'Login:' => 'Nombre de usuario:',
+ 'Full Name:' => 'Nombre:',
'Email:' => 'Correo electrónico:',
'Notifications:' => 'Notificaciones:',
'Notifications' => 'Notificaciones',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Etiquetas de enlace',
'Link modification' => 'Modificación del enlace',
'Links' => 'Enlaces',
- 'Link settings' => 'Preferencias de enlace',
'Opposite label' => 'Etiqueta opuesta',
'Remove a link' => 'Eliminar un enlace',
- 'Task\'s links' => 'Enlaces de tareas',
'The labels must be different' => 'Las etiquetas han de ser diferentes',
'There is no link.' => 'No hay enlace.',
'This label must be unique' => 'Esta etiqueta debe ser única',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Compactar vista',
'Horizontal scrolling' => 'Desplazamiento horizontal',
'Compact/wide view' => 'Vista compacta/amplia',
- 'No results match:' => 'No hay resultados coincidentes:',
'Currency' => 'Moneda',
'Private project' => 'Proyecto privado',
'AUD - Australian Dollar' => 'AUD - Dólar australiano',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Yen japonés',
'NZD - New Zealand Dollar' => 'NZD - Dóloar neocelandés',
'RSD - Serbian dinar' => 'RSD - Dinar serbio',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dólar estadounidense',
'Destination column' => 'Columna destino',
'Move the task to another column when assigned to a user' => 'Mover la tarea a otra columna al asignarse a un usuario',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Cambio de monedas',
'Rate' => 'Cambio',
'Change reference currency' => 'Cambiar moneda de referencia',
- 'Add a new currency rate' => 'Añadir nuevo cambio de moneda',
'Reference currency' => 'Moneda de referencia',
'The currency rate have been added successfully.' => 'El cambio de moneda se ha añadido correctamente.',
'Unable to add this currency rate.' => 'No se puede añadir este cambio de moneda.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Parar temporizador',
'Start timer' => 'Iniciar temporizador',
- 'Add project member' => 'Añadir miembro al proyecto',
'My activity stream' => 'Mi flujo de actividad',
'My calendar' => 'Mi calendario',
'Search tasks' => 'Buscar tareas',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Usuario remoto',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Los usuarios remotos no almacenan sus contraseñas en la base de datos Kanboard, por ejemplo: cuentas de LDAP, Google y Github.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si marcas la opción "Desactivar formulario de ingreso", se ignoran las credenciales introducidas en el formulario de ingreso.',
- 'New remote user' => 'Nuevo usuario remoto',
- 'New local user' => 'Nuevo usuario local',
'Default task color' => 'Color de la tarea por defecto',
'This feature does not work with all browsers.' => 'Esta característica no funciona en todos los navegadores.',
'There is no destination project available.' => 'No está disponible proyecto de destino.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Propietario',
'Unread notifications' => 'Notificaciones sin leer',
'Notification methods:' => 'Métodos de notificación:',
- 'Import tasks from CSV file' => 'Importar tareas desde archivo CSV',
'Unable to read your file' => 'No es posible leer el archivo',
'%d task(s) have been imported successfully.' => '%d tarea(s) han sido importadas correctamente.',
'Nothing have been imported!' => '¡No se ha importado nada!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Propietario del proyecto: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'El identificador del proyecto es opcional y debe ser alfanumérico. Ejemplo: MIPROYECTO',
'Project owner' => 'Propietario del proyecto',
- 'Those dates are useful for the project Gantt chart.' => 'Esas fechas son útiles para el diagrama de Gantt.',
'Private projects do not have users and groups management.' => 'Los proyectos privados no cuentan con gestión de usuarios y grupos.',
'There is no project member.' => 'No existe miembro del proyecto.',
'Priority' => 'Prioridad',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Iniciado:',
'Moved:' => 'Movido:',
'Task #%d' => 'Tarea #%d',
- 'Date and time format' => 'Formato de fecha y hora',
'Time format' => 'Formato de hora',
'Start date: ' => 'Fecha de inicio: ',
'End date: ' => 'Fecha de finalización: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Usuario deshabilitado correctamente.',
'Unable to disable this user.' => 'No es posible deshabilitar este usuario.',
'All files have been uploaded successfully.' => 'Todos los archivos han sido cargados correctamente.',
- 'View uploaded files' => 'Ver archivos cargados',
'The maximum allowed file size is %sB.' => 'El tamaño máximo de archivo es %sB.',
- 'Choose files again' => 'Elegir archivos de nuevo',
'Drag and drop your files here' => 'Arrastra y suelta tus archivos aquí',
'choose files' => 'elegir archivos',
'View profile' => 'Ver perfil',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => 'Dirección del remitente del correo electrónico',
'Email transport' => 'Transporte de correo electrónico',
'Webhook token' => 'Token del disparador web (webhook)',
- 'Imports' => 'Importaciones',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index 41e51fa1..685858aa 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tehtävää taululla',
'%d tasks in total' => '%d tehtävää yhteensä',
'Unable to update this board.' => 'Taulun muuttaminen ei onnistunut.',
- 'Edit board' => 'Muuta taulua',
'Disable' => 'Disabloi',
'Enable' => 'Aktivoi',
'New project' => 'Uusi projekti',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Nimi',
'Assigned to %s' => 'Tekijä: %s',
'Remove a column' => 'Poista sarake',
- 'Remove a column from a board' => 'Poista sarake taulusta',
'Unable to remove this column.' => 'Sarakkeen poistaminen ei onnistunut.',
'Do you really want to remove this column: "%s"?' => 'Haluatko varmasti poistaa sarakkeen "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Tämä toiminto POISTAA KAIKKI TEHTÄVÄT tästä sarakkeesta!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Tehtävien määrä',
'User' => 'Käyttäjät',
'Comments' => 'Kommentit',
- 'Leave a comment' => 'Lisää kommentti',
'Comment is required' => 'Kommentti vaaditaan',
- 'Leave a description' => 'Lisää kuvaus',
'Comment added successfully.' => 'Kommentti lisättiin onnistuneesti.',
'Unable to create your comment.' => 'Kommentin lisäys epäonnistui.',
'Due Date' => 'Deadline',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Etsi',
'Nothing found.' => 'Ei löytynyt.',
'Due date' => 'Deadline',
- 'Others formats accepted: %s and %s' => 'Muut hyväksytyt muodot: %s ja %s',
'Description' => 'Kuvaus',
'%d comments' => '%d kommenttia',
'%d comment' => '%d kommentti',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Luonut: %s',
'Tasks Export' => 'Tehtävien vienti',
'Start Date' => 'Aloituspäivä',
- 'End Date' => 'Lopetuspäivä',
'Execute' => 'Suorita',
'Task Id' => 'Tehtävän ID',
'Creator' => 'Luonut',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Etä',
'Enabled' => 'Käytössä',
'Disabled' => 'Pois käytöstä',
- 'Username:' => 'Käyttäjänimi:',
- 'Name:' => 'Nimi:',
+ 'Login:' => 'Käyttäjänimi:',
+ 'Full Name:' => 'Nimi:',
'Email:' => 'Sähköpostiosoite:',
'Notifications:' => 'Ilmoitukset:',
'Notifications' => 'Ilmoitukset',
@@ -516,10 +510,8 @@ return array(
// 'Link labels' => '',
// 'Link modification' => '',
// 'Links' => '',
- // 'Link settings' => '',
// 'Opposite label' => '',
// 'Remove a link' => '',
- // 'Task\'s links' => '',
// 'The labels must be different' => '',
// 'There is no link.' => '',
// 'This label must be unique' => '',
@@ -552,7 +544,6 @@ return array(
// 'Compact view' => '',
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
- // 'No results match:' => '',
// 'Currency' => '',
// 'Private project' => '',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
// 'JPY - Japanese Yen' => '',
// 'NZD - New Zealand Dollar' => '',
// 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
// 'USD - US Dollar' => '',
// 'Destination column' => '',
// 'Move the task to another column when assigned to a user' => '',
@@ -580,7 +572,6 @@ return array(
// 'Currency rates' => '',
// 'Rate' => '',
// 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
// 'Stop timer' => '',
// 'Start timer' => '',
- // 'Add project member' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
// 'Default task color' => '',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index daac98ed..824519f9 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tâches sur le tableau',
'%d tasks in total' => '%d tâches au total',
'Unable to update this board.' => 'Impossible de mettre à jour ce tableau.',
- 'Edit board' => 'Modifier le tableau',
'Disable' => 'Désactiver',
'Enable' => 'Activer',
'New project' => 'Nouveau projet',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titre',
'Assigned to %s' => 'Assigné à %s',
'Remove a column' => 'Supprimer une colonne',
- 'Remove a column from a board' => 'Supprimer une colonne d\'un tableau',
'Unable to remove this column.' => 'Impossible de supprimer cette colonne.',
'Do you really want to remove this column: "%s"?' => 'Voulez vraiment supprimer cette colonne : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Cette action va supprimer toutes les tâches associées à cette colonne !',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Nombre de tâches',
'User' => 'Utilisateur',
'Comments' => 'Commentaires',
- 'Leave a comment' => 'Laissez un commentaire',
'Comment is required' => 'Le commentaire est obligatoire',
- 'Leave a description' => 'Laissez une description',
'Comment added successfully.' => 'Commentaire ajouté avec succès.',
'Unable to create your comment.' => 'Impossible de sauvegarder votre commentaire.',
'Due Date' => 'Date d\'échéance',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Rechercher',
'Nothing found.' => 'Rien trouvé.',
'Due date' => 'Date d\'échéance',
- 'Others formats accepted: %s and %s' => 'Autres formats acceptés : %s et %s',
'Description' => 'Description',
'%d comments' => '%d commentaires',
'%d comment' => '%d commentaire',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Créé par %s',
'Tasks Export' => 'Exportation des tâches',
'Start Date' => 'Date de début',
- 'End Date' => 'Date de fin',
'Execute' => 'Exécuter',
'Task Id' => 'Identifiant de la tâche',
'Creator' => 'Créateur',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Distant',
'Enabled' => 'Activé',
'Disabled' => 'Désactivé',
- 'Username:' => 'Nom d\'utilisateur :',
- 'Name:' => 'Nom :',
+ 'Login:' => 'Nom d\'utilisateur :',
+ 'Full Name:' => 'Nom :',
'Email:' => 'Email :',
'Notifications:' => 'Notifications :',
'Notifications' => 'Notifications',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Libellé des liens',
'Link modification' => 'Modification d\'un lien',
'Links' => 'Liens',
- 'Link settings' => 'Paramètres des liens',
'Opposite label' => 'Nom du libellé opposé',
'Remove a link' => 'Supprimer un lien',
- 'Task\'s links' => 'Liens des tâches',
'The labels must be different' => 'Les libellés doivent être différents',
'There is no link.' => 'Il n\'y a aucun lien.',
'This label must be unique' => 'Ce libellé doit être unique',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Vue compacte',
'Horizontal scrolling' => 'Défilement horizontal',
'Compact/wide view' => 'Basculer entre la vue compacte et étendue',
- 'No results match:' => 'Aucun résultat :',
'Currency' => 'Devise',
'Private project' => 'Projet privé',
'AUD - Australian Dollar' => 'AUD - Dollar australien',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Yen',
'NZD - New Zealand Dollar' => 'NZD - Dollar néo-zélandais',
'RSD - Serbian dinar' => 'RSD - Dinar serbe',
+ 'CNY - Chinese Yuan' => 'CNY - Yuan (Chine)',
'USD - US Dollar' => 'USD - Dollar américain',
'Destination column' => 'Colonne de destination',
'Move the task to another column when assigned to a user' => 'Déplacer la tâche dans une autre colonne lorsque celle-ci est assignée à quelqu\'un',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Taux de change des devises',
'Rate' => 'Taux',
'Change reference currency' => 'Changer la monnaie de référence',
- 'Add a new currency rate' => 'Ajouter un nouveau taux pour une devise',
'Reference currency' => 'Devise de référence',
'The currency rate have been added successfully.' => 'Le taux de change a été ajouté avec succès.',
'Unable to add this currency rate.' => 'Impossible d\'ajouter ce taux de change',
@@ -675,7 +666,6 @@ return array(
'view the board on Kanboard' => 'voir le tableau sur Kanboard',
'The task have been moved to the first swimlane' => 'La tâche a été déplacée dans la première swimlane',
'The task have been moved to another swimlane:' => 'La tâche a été déplacée dans une autre swimlane :',
- // 'Overdue tasks for the project(s) "%s"' => 'Tâches en retard pour le projet « %s »',
'New title: %s' => 'Nouveau titre : %s',
'The task is not assigned anymore' => 'La tâche n\'est plus assignée maintenant',
'New assignee: %s' => 'Nouvel assigné : %s',
@@ -703,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Stopper le chrono',
'Start timer' => 'Démarrer le chrono',
- 'Add project member' => 'Ajouter un membre au projet',
'My activity stream' => 'Mon flux d\'activité',
'My calendar' => 'Mon agenda',
'Search tasks' => 'Rechercher des tâches',
@@ -758,8 +747,6 @@ return array(
'Remote user' => 'Utilisateur distant',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Les utilisateurs distants ne stockent pas leur mot de passe dans la base de données de Kanboard, exemples : comptes LDAP, Github ou Google.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si vous cochez la case « Interdire le formulaire d\'authentification », les identifiants entrés dans le formulaire d\'authentification seront ignorés.',
- 'New remote user' => 'Créer un utilisateur distant',
- 'New local user' => 'Créer un utilisateur local',
'Default task color' => 'Couleur par défaut des tâches',
'This feature does not work with all browsers.' => 'Cette fonctionnalité n\'est pas compatible avec tous les navigateurs',
'There is no destination project available.' => 'Il n\'y a pas de projet de destination disponible.',
@@ -840,7 +827,7 @@ return array(
'Swimlane changed for task #%d' => 'Changement de swimlane pour la tâche n°%d',
'Assignee changed on task #%d' => 'Changement de l\'assigné pour la tâche n°%d',
'%d overdue tasks' => '%d tâches en retard',
- 'Task #%d is overdue' => 'La tâche n°%d est retard',
+ 'Task #%d is overdue' => 'La tâche n°%d est en retard',
'No new notifications.' => 'Aucune notification.',
'Mark all as read' => 'Tout marquer comme lu',
'Mark as read' => 'Marquer comme lu',
@@ -853,7 +840,6 @@ return array(
'Owner' => 'Propriétaire',
'Unread notifications' => 'Notifications non lus',
'Notification methods:' => 'Méthodes de notifications :',
- 'Import tasks from CSV file' => 'Importer les tâches depuis un fichier CSV',
'Unable to read your file' => 'Impossible de lire votre fichier',
'%d task(s) have been imported successfully.' => '%d tâche(s) ont été importées avec succès.',
'Nothing have been imported!' => 'Rien n\'a été importé',
@@ -981,7 +967,6 @@ return array(
'Project owner: ' => 'Responsable du projet : ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'L\'identifiant du projet est optionnel et doit être alphanumérique, example: MONPROJET.',
'Project owner' => 'Responsable du projet',
- 'Those dates are useful for the project Gantt chart.' => 'Ces dates sont utiles pour le diagramme de Gantt des projets.',
'Private projects do not have users and groups management.' => 'Les projets privés n\'ont pas de gestion d\'utilisateurs et de groupes.',
'There is no project member.' => 'Il n\'y a aucun membre du projet.',
'Priority' => 'Priorité',
@@ -1038,7 +1023,6 @@ return array(
'Started:' => 'Commençé le :',
'Moved:' => 'Déplacé le : ',
'Task #%d' => 'Tâche n°%d',
- 'Date and time format' => 'Format de la date et de l\'heure',
'Time format' => 'Format de l\'heure',
'Start date: ' => 'Date de début : ',
'End date: ' => 'Date de fin : ',
@@ -1052,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Utilisateur désactivé avec succès.',
'Unable to disable this user.' => 'Impossible de désactiver cet utilisateur.',
'All files have been uploaded successfully.' => 'Tous les fichiers ont été uploadés avec succès.',
- 'View uploaded files' => 'Voir les fichiers uploadés',
'The maximum allowed file size is %sB.' => 'La taille maximale autorisée pour les fichiers est de %so.',
- 'Choose files again' => 'Choisir de nouveau des fichiers',
'Drag and drop your files here' => 'Glissez-déposez vos fichiers ici',
'choose files' => 'choisissez des fichiers',
'View profile' => 'Voir le profil',
@@ -1164,7 +1146,6 @@ return array(
'Email sender address' => 'Adresse email de l\'expéditeur',
'Email transport' => 'Transport des emails',
'Webhook token' => 'Jeton de sécurité des webhooks',
- 'Imports' => 'Importations',
'Project tags management' => 'Gestion des libellés pour le projet',
'Tag created successfully.' => 'Libellé créé avec succès.',
'Unable to create this tag.' => 'Imposssible de créer ce libellé.',
@@ -1211,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Flux d\'activité pour %s',
'Calendar for %s' => 'Calendrier pour %s',
'Notifications for %s' => 'Notifications pour %s',
- 'Subtasks export' => 'Export des sous-tâches',
- 'Tasks exportation' => 'Export des tâches',
'Assign a color when the task is moved to a specific swimlane' => 'Assigner une couleur lorsque une tâche est déplaçée dans une swimlane spécifique',
'Assign a priority when the task is moved to a specific swimlane' => 'Assigner une priorité lorsque une tâche est déplaçée dans une swimlane spécifique',
'User unlocked successfully.' => 'Utilisateur débloqué avec succès.',
@@ -1288,4 +1267,44 @@ return array(
'Your personal API access token is "%s"' => 'Votre jeton d\'accès personnel à l\'API est « %s »',
'Remove your token' => 'Supprimer votre jeton',
'Generate a new token' => 'Générer un nouveau jeton',
+ 'Showing %d-%d of %d' => 'Éléments %d à %d sur %d',
+ 'Outgoing Emails' => 'Emails sortants',
+ 'Add or change currency rate' => 'Ajouter ou changer le taux de change',
+ 'Reference currency: %s' => 'Monnaie de référence : %s',
+ 'Add custom filters' => 'Ajouter un filtre personnalisé',
+ 'Export' => 'Exporter',
+ 'Add link label' => 'Ajouter un libellé de lien',
+ 'Incompatible Plugins' => 'Extensions incompatibles',
+ 'Compatibility' => 'Compatibilité',
+ 'Permissions and ownership' => 'Permissions et propriétaire',
+ 'Priorities' => 'Priorités',
+ 'Close this window' => 'Fermer cette fenêtre',
+ 'Unable to upload this file.' => 'Impossible de téléverser ce fichier.',
+ 'Import tasks' => 'Importer des tâches',
+ 'Choose a project' => 'Choisir un projet',
+ 'Profile' => 'Profil',
+ 'Application role' => 'Rôle dans l\'application',
+ '%d invitations were sent.' => '%d invitations ont été envoyées.',
+ '%d invitation was sent.' => '%d invitation a été envoyée.',
+ 'Unable to create this user.' => 'Impossible de créer cet utilisateur.',
+ 'Kanboard Invitation' => 'Invitation pour Kanboard',
+ 'Visible on dashboard' => 'Visible sur le tableau de bord',
+ 'Created at:' => 'Créé le :',
+ 'Updated at:' => 'Mis à jour le :',
+ 'There is no custom filter.' => 'Il n\'y a aucun filtre personnalisé.',
+ 'New User' => 'Nouvel utilisateur',
+ 'Authentication' => 'Authentification',
+ 'If checked, this user will use a third-party system for authentication.' => 'Si coché, cet utilisateur va utiliser un système externe pour s\'authentifier.',
+ 'The password is necessary only for local users.' => 'Le mot de passe est nécessaire uniquement pour les utilisateurs locaux.',
+ 'You have been invited to register on Kanboard.' => 'Vous avez été invité à vous inscrire sur Kanboard.',
+ 'Click here to join your team' => 'Cliquez ici pour rejoindre votre équipe',
+ 'Invite people' => 'Inviter des gens',
+ 'Emails' => 'Emails',
+ 'Enter one email address by line.' => 'Entrez une adresse électronique par ligne.',
+ 'Add these people to this project' => 'Ajouter ces personnes à ce projet',
+ 'Add this person to this project' => 'Ajouter cet utilisateur à ce projet',
+ 'Sign-up' => 'Inscription',
+ 'Credentials' => 'Informations d\'identification',
+ 'New user' => 'Nouvel utilisateur',
+ 'This username is already taken' => 'Ce nom d\'utilisateur est déjà pris',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 784c27ba..4b8dedbe 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d feladat a táblán',
'%d tasks in total' => 'Összesen %d feladat',
'Unable to update this board.' => 'Nem lehet frissíteni a táblát.',
- 'Edit board' => 'Tábla szerkesztése',
'Disable' => 'Letiltás',
'Enable' => 'Engedélyezés',
'New project' => 'Új projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Cím',
'Assigned to %s' => 'Felelős: %s',
'Remove a column' => 'Oszlop törlése',
- 'Remove a column from a board' => 'Oszlop törlése a tábláról',
'Unable to remove this column.' => 'Az oszlop törlése nem lehetséges.',
'Do you really want to remove this column: "%s"?' => 'Valóban törölni akarja ezt az oszlopot: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Az oszlophoz rendelt ÖSSZES FELADAT TÖRLŐDNI FOG!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Feladatok száma',
'User' => 'Felhasználó',
'Comments' => 'Hozzászólások',
- 'Leave a comment' => 'Írjon hozzászólást ...',
'Comment is required' => 'A hozzászólás mező kötelező',
- 'Leave a description' => 'Írjon leírást ...',
'Comment added successfully.' => 'Hozzászólás sikeresen elküldve.',
'Unable to create your comment.' => 'Hozzászólás létrehozása nem lehetséges.',
'Due Date' => 'Határidő',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Keresés',
'Nothing found.' => 'Nincs találat.',
'Due date' => 'Határidő',
- 'Others formats accepted: %s and %s' => 'Egyéb érvényes formátumok: "%s" és "%s"',
'Description' => 'Leírás',
'%d comments' => '%d megjegyzés',
'%d comment' => '%d megjegyzés',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Készítette: %s',
'Tasks Export' => 'Feladatok exportálása',
'Start Date' => 'Kezdés dátuma',
- 'End Date' => 'Befejezés dátuma',
'Execute' => 'Végrehajt',
'Task Id' => 'Feladat ID',
'Creator' => 'Készítette',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Távoli',
'Enabled' => 'Engedélyezve',
'Disabled' => 'Letiltva',
- 'Username:' => 'Felhasználónév:',
- 'Name:' => 'Név:',
+ 'Login:' => 'Felhasználónév:',
+ 'Full Name:' => 'Név:',
'Email:' => 'E-mail:',
'Notifications:' => 'Értesítések:',
'Notifications' => 'Értesítések',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Hivatkozás címkék',
'Link modification' => 'Hivatkozás módosítás',
'Links' => 'Hivatkozások',
- 'Link settings' => 'Hivatkozás beállítasok',
'Opposite label' => 'Ellenkező címke',
'Remove a link' => 'Hivatkozás törlése',
- 'Task\'s links' => 'Feladat hivatkozások',
'The labels must be different' => 'A címkék nem lehetnek azonosak',
'There is no link.' => 'Nincs hivatkozás.',
'This label must be unique' => 'A címkének egyedinek kell lennie.',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompakt nézet',
'Horizontal scrolling' => 'Vízszintes görgetés',
'Compact/wide view' => 'Kompakt/széles nézet',
- 'No results match:' => 'Nincs találat:',
'Currency' => 'Pénznem',
'Private project' => 'Privát projekt',
'AUD - Australian Dollar' => 'AUD - Ausztrál dollár',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japán Yen',
'NZD - New Zealand Dollar' => 'NZD - Új-Zélandi dollár',
'RSD - Serbian dinar' => 'RSD - Szerb dínár',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Amerikai dollár',
'Destination column' => 'Cél oszlop',
'Move the task to another column when assigned to a user' => 'Feladat másik oszlopba helyezése felhasználóhoz rendélés után',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Árfolyamok',
'Rate' => 'Árfolyam',
'Change reference currency' => 'A bázis pénznem megváltoztatása',
- 'Add a new currency rate' => 'Új átváltási árfolyam megadása',
'Reference currency' => 'Bázis pénznem',
'The currency rate have been added successfully.' => 'Az átváltási árfolyammal történő bővítés sikerült',
'Unable to add this currency rate.' => 'Nem sikerült az átváltási árfolyam felvétele',
@@ -702,7 +693,6 @@ return array(
'<30m' => '30p',
'Stop timer' => 'Időmérő leállítása',
'Start timer' => 'Időmérő elindítása',
- 'Add project member' => 'Projekt tag hozzáadása',
'My activity stream' => 'Tevékenységem',
'My calendar' => 'Naptáram',
'Search tasks' => 'Feladatok közötti keresés',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Távoli felhasználó',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'A távoli felhasználók jelszava nem a Kanboard adatbázisban van tárolva. Példák: LDAP, Google és GitHub számlák.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Ha bekattintja a "Bejelentkezési ablak tiltása" jelölőnégyzetet, akkor a login ablakban megadott jelszó nem lesz figyelembe véve.',
- 'New remote user' => 'Új távoli felhasználó',
- 'New local user' => 'Új helyi felhasználó',
'Default task color' => 'A feladathoz rendelt alapszín',
'This feature does not work with all browsers.' => 'Ez a jellemző nem minden böngészőben működik.',
'There is no destination project available.' => 'Nincs ilyen cél projekt.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Tulajdonos',
'Unread notifications' => 'Olvasatlan értesítések',
'Notification methods:' => 'Értesítési módszerek:',
- 'Import tasks from CSV file' => 'Feladatok beolvasása CSV fájlból',
'Unable to read your file' => 'A fájl nem olvasható',
'%d task(s) have been imported successfully.' => '%d feladat sikeresen feldolgozva.',
'Nothing have been imported!' => 'Nem történt beolvasás!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'A projekt tulajdonosa: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'A projekt azonosító opcionális, és kötelezően alfanumerikus karakterekből áll, pl: MYPROJECT.',
'Project owner' => 'Projekt tulajdonos',
- 'Those dates are useful for the project Gantt chart.' => 'Ezek a dátumok a projekt Gantt diagramjához hasznosak.',
'Private projects do not have users and groups management.' => 'A privát projektekhez nem tartozik felhasználó kezelés és csoport kezelés.',
'There is no project member.' => 'A projektnek nincs tagja.',
'Priority' => 'Prioritás',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Elindult:',
'Moved:' => 'Elmozgatva:',
'Task #%d' => '#%d. feladat',
- 'Date and time format' => 'Dátum és idő formátum',
'Time format' => 'Idő formátum',
'Start date: ' => 'Kezdő datum: ',
'End date: ' => 'Vég dátum: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'A felhaszáló sikeresen le lett tiltva.',
'Unable to disable this user.' => 'Nem sikerült a felhasználó letiltása.',
'All files have been uploaded successfully.' => 'Az összes fájl sikeresen feltöltődött.',
- 'View uploaded files' => 'A feltöltött fájlok megtekintése',
'The maximum allowed file size is %sB.' => 'A fájl max. megengedett mérete %s bájt',
- 'Choose files again' => 'Válasszon újból fájlt',
'Drag and drop your files here' => 'Fogdd-és-vidd módszerrel dobja ide a fájlt',
'choose files' => 'válasszon fájlt',
'View profile' => 'Profil megtekintés',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/id_ID/translations.php b/app/Locale/id_ID/translations.php
index 9398d51d..45c93b06 100644
--- a/app/Locale/id_ID/translations.php
+++ b/app/Locale/id_ID/translations.php
@@ -5,7 +5,7 @@ return array(
'number.thousands_separator' => ' ',
'None' => 'Tidak satupun',
'edit' => 'modifikasi',
- 'Edit' => 'Modifikasi',
+ 'Edit' => 'Edit',
'remove' => 'hapus',
'Remove' => 'Hapus',
'Yes' => 'Ya',
@@ -30,11 +30,11 @@ return array(
'Amber' => 'Amber',
'Save' => 'Simpan',
'Login' => 'Masuk',
- 'Official website:' => 'Situs resmi :',
+ 'Official website:' => 'Situs resmi:',
'Unassigned' => 'Belum ditugaskan',
'View this task' => 'Lihat tugas ini',
'Remove user' => 'Hapus pengguna',
- 'Do you really want to remove this user: "%s"?' => 'Anda yakin akan menghapus pengguna ini : « %s » ?',
+ 'Do you really want to remove this user: "%s"?' => 'Anda yakin mau menghapus pengguna ini: "%s"?',
'All users' => 'Semua pengguna',
'Username' => 'Nama pengguna',
'Password' => 'Kata sandi',
@@ -44,10 +44,10 @@ return array(
'No user' => 'Tidak ada pengguna',
'Forbidden' => 'Terlarang',
'Access Forbidden' => 'Akses Dilarang',
- 'Edit user' => 'Rubah Pengguna',
+ 'Edit user' => 'Edit pengguna',
'Logout' => 'Keluar',
- 'Bad username or password' => 'Nama pengguna atau kata sandri buruk',
- 'Edit project' => 'Rubah proyek',
+ 'Bad username or password' => 'Nama pengguna atau password salah',
+ 'Edit project' => 'Edit proyek',
'Name' => 'Nama',
'Projects' => 'Proyek',
'No project' => 'Tidak ada proyek',
@@ -60,31 +60,29 @@ return array(
'Active' => 'Aktif',
'%d tasks on the board' => '%d tugas di papan',
'%d tasks in total' => '%d tugas di total',
- 'Unable to update this board.' => 'Tidak dapat memperbaharui papan ini',
- 'Edit board' => 'Rubah papan',
+ 'Unable to update this board.' => 'Tidak dapat memperbarui papan ini',
'Disable' => 'Nonaktifkan',
'Enable' => 'Aktifkan',
- 'New project' => 'Proyek Baru',
- 'Do you really want to remove this project: "%s"?' => 'Apakah anda yakin akan menghapus proyek ini : « %s » ?',
+ 'New project' => 'Proyek baru',
+ 'Do you really want to remove this project: "%s"?' => 'Apakah Anda yakin mau menghapus proyek ini: "%s"?',
'Remove project' => 'Hapus proyek',
- 'Edit the board for "%s"' => 'Rubah papan untuk « %s »',
+ 'Edit the board for "%s"' => 'Edit papan untuk "%s"',
'Add a new column' => 'Tambah kolom baru',
'Title' => 'Judul',
- 'Assigned to %s' => 'Ditugaskan ke %s',
+ 'Assigned to %s' => 'Ditugaskan kepada %s',
'Remove a column' => 'Hapus kolom',
- 'Remove a column from a board' => 'Hapus kolom dari papan',
'Unable to remove this column.' => 'Tidak dapat menghapus kolom ini.',
- 'Do you really want to remove this column: "%s"?' => 'Apakah anda yakin akan menghapus kolom ini : « %s » ?',
- 'This action will REMOVE ALL TASKS associated to this column!' => 'tindakan ini akan MENGHAPUS SEMUA TUGAS yang terkait dengan kolom ini!',
+ 'Do you really want to remove this column: "%s"?' => 'Apakah Anda yakin mau menghapus kolom ini: "%s"?',
+ 'This action will REMOVE ALL TASKS associated to this column!' => 'Tindakan ini akan MENGHAPUS SEMUA TUGAS yang berkaitan dengan kolom ini!',
'Settings' => 'Pengaturan',
'Application settings' => 'Pengaturan aplikasi',
'Language' => 'Bahasa',
- 'Webhook token:' => 'Token webhook :',
- 'API token:' => 'Token API :',
- 'Database size:' => 'Ukuran basis data :',
- 'Download the database' => 'Unduh basis data',
- 'Optimize the database' => 'Optimasi basis data',
- '(VACUUM command)' => '(perintah VACUUM)',
+ 'Webhook token:' => 'Token Webhook:',
+ 'API token:' => 'Token API:',
+ 'Database size:' => 'Ukuran database:',
+ 'Download the database' => 'Unduh database',
+ 'Optimize the database' => 'Optimasi database',
+ '(VACUUM command)' => '(Perintah VACUUM)',
'(Gzip compressed Sqlite file)' => '(File Sqlite yang terkompress Gzip)',
'Close a task' => 'Tutup tugas',
'Column' => 'Kolom',
@@ -93,38 +91,38 @@ return array(
'Create another task' => 'Buat tugas lain',
'New task' => 'Tugas baru',
'Open a task' => 'Buka tugas',
- 'Do you really want to open this task: "%s"?' => 'Apakah anda yakin akan membuka tugas ini : « %s » ?',
+ 'Do you really want to open this task: "%s"?' => 'Apakah Anda yakin mau membuka tugas ini: "%s"?',
'Back to the board' => 'Kembali ke papan',
'There is nobody assigned' => 'Tidak ada orang yand ditugaskan',
- 'Column on the board:' => 'Kolom di dalam papan : ',
+ 'Column on the board:' => 'Kolom di dalam papan:',
'Close this task' => 'Tutup tugas ini',
'Open this task' => 'Buka tugas ini',
'There is no description.' => 'Tidak ada deskripsi.',
'Add a new task' => 'Tambah tugas baru',
- 'The username is required' => 'nama pengguna diperlukan',
+ 'The username is required' => 'Nama pengguna dibutuhkan',
'The maximum length is %d characters' => 'Panjang maksimum adalah %d karakter',
'The minimum length is %d characters' => 'Panjang minimum adalah %d karakter',
- 'The password is required' => 'Kata sandi diperlukan',
+ 'The password is required' => 'Password dibutuhkan',
'This value must be an integer' => 'Nilai ini harus integer',
'The username must be unique' => 'Nama pengguna harus unik',
- 'The user id is required' => 'Id Pengguna diperlukan',
- 'Passwords don\'t match' => 'Kata sandi tidak cocok',
+ 'The user id is required' => 'ID pengguna diperlukan',
+ 'Passwords don\'t match' => 'Password tidak cocok',
'The confirmation is required' => 'Konfirmasi diperlukan',
'The project is required' => 'Proyek diperlukan',
- 'The id is required' => 'Id diperlukan',
- 'The project id is required' => 'Id proyek diperlukan',
+ 'The id is required' => 'ID diperlukan',
+ 'The project id is required' => 'ID proyek diperlukan',
'The project name is required' => 'Nama proyek diperlukan',
'The title is required' => 'Judul diperlukan',
'Settings saved successfully.' => 'Pengaturan berhasil disimpan.',
'Unable to save your settings.' => 'Tidak dapat menyimpan pengaturan anda.',
- 'Database optimization done.' => 'Optimasi basis data selesai.',
+ 'Database optimization done.' => 'Optimasi database selesai.',
'Your project have been created successfully.' => 'Proyek anda berhasil dibuat.',
'Unable to create your project.' => 'Tidak dapat membuat proyek anda.',
- 'Project updated successfully.' => 'Proyek berhasil diperbaharui.',
- 'Unable to update this project.' => 'Tidak dapat memperbaharui proyek ini.',
+ 'Project updated successfully.' => 'Proyek berhasil diperbarui.',
+ 'Unable to update this project.' => 'Tidak dapat memperbarui proyek ini.',
'Unable to remove this project.' => 'Tidak dapat menghapus proyek ini.',
'Project removed successfully.' => 'Proyek berhasil dihapus.',
- 'Project activated successfully.' => 'Proyek berhasil diaktivasi.',
+ 'Project activated successfully.' => 'Proyek berhasil diaktifkan.',
'Unable to activate this project.' => 'Tidak dapat mengaktifkan proyek ini.',
'Project disabled successfully.' => 'Proyek berhasil dinonaktifkan.',
'Unable to disable this project.' => 'Tidak dapat menonaktifkan proyek ini.',
@@ -132,61 +130,59 @@ return array(
'Task opened successfully.' => 'Tugas berhasil dibuka.',
'Unable to close this task.' => 'Tidak dapat menutup tugas ini.',
'Task closed successfully.' => 'Tugas berhasil ditutup.',
- 'Unable to update your task.' => 'Tidak dapat memperbaharui tugas ini.',
- 'Task updated successfully.' => 'Tugas berhasil diperbaharui.',
+ 'Unable to update your task.' => 'Tidak dapat memperbarui tugas ini.',
+ 'Task updated successfully.' => 'Tugas berhasil diperbarui.',
'Unable to create your task.' => 'Tidak dapat membuat tugas anda.',
'Task created successfully.' => 'Tugas berhasil dibuat.',
'User created successfully.' => 'Pengguna berhasil dibuat.',
- 'Unable to create your user.' => 'Tidak dapat membuat pengguna anda.',
- 'User updated successfully.' => 'Pengguna berhasil diperbaharui.',
- 'Unable to update your user.' => 'Tidak dapat memperbaharui pengguna anda.',
- 'User removed successfully.' => 'pengguna berhasil dihapus.',
+ 'Unable to create your user.' => 'Tidak dapat membuat pengguna Anda.',
+ 'User updated successfully.' => 'Pengguna berhasil diperbarui.',
+ 'Unable to update your user.' => 'Tidak dapat memperbarui pengguna anda.',
+ 'User removed successfully.' => 'Pengguna berhasil dihapus.',
'Unable to remove this user.' => 'Tidak dapat menghapus pengguna ini.',
'Board updated successfully.' => 'Papan berhasil diperbaharui.',
'Ready' => 'Siap',
'Backlog' => 'Tertunda',
'Work in progress' => 'Sedang dalam pengerjaan',
'Done' => 'Selesai',
- 'Application version:' => 'Versi aplikasi :',
- 'Id' => 'Id.',
+ 'Application version:' => 'Versi aplikasi:',
+ 'Id' => 'ID',
'%d closed tasks' => '%d tugas yang ditutup',
'No task for this project' => 'Tidak ada tugas dalam proyek ini',
'Public link' => 'Tautan publik',
'Timezone' => 'Zona waktu',
- 'Sorry, I didn\'t find this information in my database!' => 'Maaf, saya tidak menemukan informasi ini dalam basis data saya !',
+ 'Sorry, I didn\'t find this information in my database!' => 'Maaf, saya tidak dapat menemukan informasi ini dalam database saya!',
'Page not found' => 'Halaman tidak ditemukan',
'Complexity' => 'Kompleksitas',
- 'Task limit' => 'Batas tugas.',
+ 'Task limit' => 'Batas tugas',
'Task count' => 'Jumlah tugas',
'User' => 'Pengguna',
'Comments' => 'Komentar',
- 'Leave a comment' => 'Tinggalkan komentar',
- 'Comment is required' => 'Komentar diperlukan',
- 'Leave a description' => 'Tinggalkan deskripsi',
+ 'Comment is required' => 'Komentar dibutuhkan',
'Comment added successfully.' => 'Komentar berhasil ditambahkan.',
- 'Unable to create your comment.' => 'Tidak dapat menambahkan komentar anda.',
+ 'Unable to create your comment.' => 'Tidak dapat menambahkan komentar Anda.',
'Due Date' => 'Batas Tanggal Terakhir',
- 'Invalid date' => 'Tanggal tidak valid',
+ 'Invalid date' => 'Tanggal tidak sesuai',
'Automatic actions' => 'Tindakan otomatis',
- 'Your automatic action have been created successfully.' => 'Tindakan otomatis anda berhasil dibuat.',
- 'Unable to create your automatic action.' => 'Tidak dapat membuat tindakan otomatis anda.',
+ 'Your automatic action have been created successfully.' => 'Tindakan otomatis Anda berhasil dibuat.',
+ 'Unable to create your automatic action.' => 'Tidak dapat membuat tindakan otomatis Anda.',
'Remove an action' => 'Hapus tindakan',
- 'Unable to remove this action.' => 'Tidak dapat menghapus tindakan ini',
+ 'Unable to remove this action.' => 'Tidak dapat menghapus tindakan ini.',
'Action removed successfully.' => 'Tindakan berhasil dihapus.',
- 'Automatic actions for the project "%s"' => 'Tindakan otomatis untuk proyek ini « %s »',
+ 'Automatic actions for the project "%s"' => 'Tindakan otomatis untuk proyek ini "%s"',
'Add an action' => 'Tambah tindakan',
'Event name' => 'Nama acara',
'Action name' => 'Nama tindakan',
'Action parameters' => 'Parameter tindakan',
'Action' => 'Tindakan',
'Event' => 'Acara',
- 'When the selected event occurs execute the corresponding action.' => 'Ketika acara yang dipilih terjadi, melakukan tindakan yang sesuai.',
+ 'When the selected event occurs execute the corresponding action.' => 'Ketika acara yang dipilih terjadi, tindakan yang berhubungan dengan acara akan dieksekusi.',
'Next step' => 'Langkah selanjutnya',
'Define action parameters' => 'Definisi parameter tindakan',
- 'Do you really want to remove this action: "%s"?' => 'Apakah anda yakin akan menghapus tindakan ini « %s » ?',
+ 'Do you really want to remove this action: "%s"?' => 'Apakah Anda yakin mau menghapus tindakan ini: "%s"?',
'Remove an automatic action' => 'Hapus tindakan otomatis',
- 'Assign the task to a specific user' => 'Menetapkan tugas untuk pengguna tertentu',
- 'Assign the task to the person who does the action' => 'Memberikan tugas untuk orang yang melakukan tindakan',
+ 'Assign the task to a specific user' => 'Berikan tugas pada pengguna tertentu',
+ 'Assign the task to the person who does the action' => 'Berikan tugas pada orang yang melakukan tindakan',
'Duplicate the task to another project' => 'Duplikasi tugas ke proyek lain',
'Move a task to another column' => 'Pindahkan tugas ke kolom lain',
'Task modification' => 'Modifikasi tugas',
@@ -196,65 +192,64 @@ return array(
'Column title' => 'Judul kolom',
'Position' => 'Posisi',
'Duplicate to another project' => 'Duplikasi ke proyek lain',
- 'Duplicate' => 'Duplikasi',
+ 'Duplicate' => 'Duplikat',
'link' => 'tautan',
- 'Comment updated successfully.' => 'Komentar berhasil diperbaharui.',
- 'Unable to update your comment.' => 'Tidak dapat memperbaharui komentar anda.',
+ 'Comment updated successfully.' => 'Komentar berhasil diperbarui.',
+ 'Unable to update your comment.' => 'Tidak dapat memperbarui komentar Anda.',
'Remove a comment' => 'Hapus komentar',
'Comment removed successfully.' => 'Komentar berhasil dihapus.',
'Unable to remove this comment.' => 'Tidak dapat menghapus komentar ini.',
- 'Do you really want to remove this comment?' => 'Apakah anda yakin akan menghapus komentar ini ?',
- 'Current password for the user "%s"' => 'Kata sandi saat ini untuk pengguna « %s »',
- 'The current password is required' => 'Kata sandi saat ini diperlukan',
- 'Wrong password' => 'Kata sandi salah',
+ 'Do you really want to remove this comment?' => 'Apakah Anda yakin mau menghapus komentar ini?',
+ 'Current password for the user "%s"' => 'Password saat ini untuk pengguna "%s"',
+ 'The current password is required' => 'Password saat ini diperlukan',
+ 'Wrong password' => 'Password salah',
'Unknown' => 'Tidak diketahui',
'Last logins' => 'Masuk terakhir',
'Login date' => 'Tanggal masuk',
'Authentication method' => 'Metode otentifikasi',
'IP address' => 'Alamat IP',
- 'User agent' => 'Agen Pengguna',
- 'Persistent connections' => 'Koneksi persisten',
+ 'User agent' => 'Agen pengguna',
+ 'Persistent connections' => 'Koneksi tetap',
'No session.' => 'Tidak ada sesi.',
'Expiration date' => 'Tanggal kadaluarsa',
'Remember Me' => 'Ingat Saya',
- 'Creation date' => 'Tanggal dibuat',
+ 'Creation date' => 'Tanggal pembuatan',
'Everybody' => 'Semua orang',
'Open' => 'Terbuka',
'Closed' => 'Ditutup',
'Search' => 'Cari',
'Nothing found.' => 'Tidak ditemukan.',
'Due date' => 'Batas tanggal terakhir',
- 'Others formats accepted: %s and %s' => 'Format lain yang didukung : %s et %s',
'Description' => 'Deskripsi',
'%d comments' => '%d komentar',
'%d comment' => '%d komentar',
- 'Email address invalid' => 'Alamat email tidak valid',
- 'Your external account is not linked anymore to your profile.' => 'Akun eksternal anda tidak lagi terhubung ke profil anda.',
- 'Unable to unlink your external account.' => 'Tidak dapat memutuskan akun eksternal anda.',
+ 'Email address invalid' => 'Alamat email tidak sesuai',
+ 'Your external account is not linked anymore to your profile.' => 'Akun eksternal Anda tidak lagi terhubung ke profil anda.',
+ 'Unable to unlink your external account.' => 'Tidak dapat memutuskan akun eksternal Anda.',
'External authentication failed' => 'Otentifikasi eksternal gagal',
- 'Your external account is linked to your profile successfully.' => 'Akun eksternal anda berhasil dihubungkan ke profil anda.',
+ 'Your external account is linked to your profile successfully.' => 'Akun eksternal Anda berhasil dihubungkan ke profil anda.',
'Email' => 'Email',
'Task removed successfully.' => 'Tugas berhasil dihapus.',
'Unable to remove this task.' => 'Tidak dapat menghapus tugas ini.',
'Remove a task' => 'Hapus tugas',
- 'Do you really want to remove this task: "%s"?' => 'Apakah anda yakin akan menghapus tugas ini « %s » ?',
+ 'Do you really want to remove this task: "%s"?' => 'Apakah Anda yakin mau menghapus tugas ini: "%s"?',
'Assign automatically a color based on a category' => 'Otomatis menetapkan warna berdasarkan kategori',
'Assign automatically a category based on a color' => 'Otomatis menetapkan kategori berdasarkan warna',
- 'Task creation or modification' => 'Tugas dibuat atau di mofifikasi',
+ 'Task creation or modification' => 'Tugas dibuat atau di modifikasi',
'Category' => 'Kategori',
- 'Category:' => 'Kategori :',
+ 'Category:' => 'Kategori:',
'Categories' => 'Kategori',
- 'Your category have been created successfully.' => 'Kategori anda berhasil dibuat.',
- 'Unable to create your category.' => 'Tidak dapat membuat kategori anda.',
- 'Your category have been updated successfully.' => 'Kategori anda berhasil diperbaharui.',
- 'Unable to update your category.' => 'Tidak dapat memperbaharui kategori anda.',
+ 'Your category have been created successfully.' => 'Kategori Anda berhasil dibuat.',
+ 'Unable to create your category.' => 'Tidak dapat membuat kategori Anda.',
+ 'Your category have been updated successfully.' => 'Kategori Anda berhasil diperbarui.',
+ 'Unable to update your category.' => 'Tidak dapat memperbarui kategori Anda.',
'Remove a category' => 'Hapus kategori',
'Category removed successfully.' => 'Kategori berhasil dihapus.',
'Unable to remove this category.' => 'Tidak dapat menghapus kategori ini.',
- 'Category modification for the project "%s"' => 'Modifikasi kategori untuk proyek « %s »',
+ 'Category modification for the project "%s"' => 'Modifikasi kategori untuk proyek "%s"',
'Category Name' => 'Nama Kategori',
'Add a new category' => 'Tambah kategori baru',
- 'Do you really want to remove this category: "%s"?' => 'Apakah anda yakin akan menghapus kategori ini « %s » ?',
+ 'Do you really want to remove this category: "%s"?' => 'Apakah Anda yakin mau menghapus kategori ini: "%s"?',
'All categories' => 'Semua kategori',
'No category' => 'Tidak ada kategori',
'The name is required' => 'Nama diperlukan',
@@ -262,35 +257,35 @@ return array(
'Unable to remove this file.' => 'Tidak dapat menghapus berkas ini.',
'File removed successfully.' => 'Berkas berhasil dihapus.',
'Attach a document' => 'Lampirkan dokumen',
- 'Do you really want to remove this file: "%s"?' => 'Apakah anda yakin akan menghapus berkas ini « %s » ?',
+ 'Do you really want to remove this file: "%s"?' => 'Apakah Anda yakin akan menghapus berkas ini: "%s"?',
'Attachments' => 'Lampiran',
- 'Edit the task' => 'Modifikasi tugas',
+ 'Edit the task' => 'Edit tugas',
'Add a comment' => 'Tambahkan komentar',
- 'Edit a comment' => 'Modifikasi komentar',
+ 'Edit a comment' => 'Edit komentar',
'Summary' => 'Ringkasan',
'Time tracking' => 'Pelacakan waktu',
- 'Estimate:' => 'Estimasi :',
+ 'Estimate:' => 'Estimasi:',
'Spent:' => 'Menghabiskan:',
- 'Do you really want to remove this sub-task?' => 'Apakah anda yakin akan menghapus sub-tugas ini ?',
+ 'Do you really want to remove this sub-task?' => 'Apakah Anda yakin mau menghapus sub-tugas ini?',
'Remaining:' => 'Tersisa:',
'hours' => 'jam',
- 'spent' => 'menghabiskan',
+ 'spent' => 'dihabiskan',
'estimated' => 'perkiraan',
'Sub-Tasks' => 'Sub-tugas',
'Add a sub-task' => 'Tambahkan sub-tugas',
'Original estimate' => 'Perkiraan semula',
'Create another sub-task' => 'Tambahkan sub-tugas lainnya',
'Time spent' => 'Waktu yang dihabiskan',
- 'Edit a sub-task' => 'Modifikasi sub-tugas',
+ 'Edit a sub-task' => 'Edit sub-tugas',
'Remove a sub-task' => 'Hapus sub-tugas',
- 'The time must be a numeric value' => 'Waktu harus berisikan numerik',
+ 'The time must be a numeric value' => 'Waktu harus berupa angka',
'Todo' => 'Yang harus dilakukan',
- 'In progress' => 'Sedang proses',
+ 'In progress' => 'Dalam proses',
'Sub-task removed successfully.' => 'Sub-tugas berhasil dihapus.',
'Unable to remove this sub-task.' => 'Tidak dapat menghapus sub-tugas.',
- 'Sub-task updated successfully.' => 'Sub-tugas berhasil diperbaharui.',
- 'Unable to update your sub-task.' => 'Tidak dapat memperbaharui sub-tugas anda.',
- 'Unable to create your sub-task.' => 'Tidak dapat membuat sub-tugas anda.',
+ 'Sub-task updated successfully.' => 'Sub-tugas berhasil diperbarui.',
+ 'Unable to update your sub-task.' => 'Tidak dapat memperbarui sub-tugas Anda.',
+ 'Unable to create your sub-task.' => 'Tidak dapat membuat sub-tugas Anda.',
'Sub-task added successfully.' => 'Sub-tugas berhasil dibuat.',
'Maximum size: ' => 'Ukuran maksimum: ',
'Unable to upload the file.' => 'Tidak dapat mengunggah berkas.',
@@ -298,9 +293,8 @@ return array(
'Created by %s' => 'Dibuat oleh %s',
'Tasks Export' => 'Ekspor Tugas',
'Start Date' => 'Tanggal Mulai',
- 'End Date' => 'Tanggal Berakhir',
'Execute' => 'Eksekusi',
- 'Task Id' => 'Id Tugas',
+ 'Task Id' => 'ID Tugas',
'Creator' => 'Pembuat',
'Modification date' => 'Tanggal modifikasi',
'Completion date' => 'Tanggal penyelesaian',
@@ -308,19 +302,19 @@ return array(
'Project cloned successfully.' => 'Kloning proyek berhasil.',
'Unable to clone this project.' => 'Tidak dapat mengkloning proyek.',
'Enable email notifications' => 'Aktifkan pemberitahuan dari email',
- 'Task position:' => 'Posisi tugas :',
+ 'Task position:' => 'Posisi tugas:',
'The task #%d have been opened.' => 'Tugas #%d telah dibuka.',
'The task #%d have been closed.' => 'Tugas #%d telah ditutup.',
- 'Sub-task updated' => 'Sub-tugas diperbaharui',
- 'Title:' => 'Judul :',
- 'Status:' => 'Status :',
- 'Assignee:' => 'Ditugaskan ke :',
- 'Time tracking:' => 'Pelacakan waktu :',
+ 'Sub-task updated' => 'Sub-tugas diperbarui',
+ 'Title:' => 'Judul:',
+ 'Status:' => 'Status:',
+ 'Assignee:' => 'Ditugaskan ke:',
+ 'Time tracking:' => 'Pelacakan waktu:',
'New sub-task' => 'Sub-tugas baru',
- 'New attachment added "%s"' => 'Lampiran baru ditambahkan « %s »',
- 'New comment posted by %s' => 'Komentar baru ditambahkan oleh « %s »',
+ 'New attachment added "%s"' => 'Lampiran baru ditambahkan "%s"',
+ 'New comment posted by %s' => 'Komentar baru ditambahkan oleh %s',
'New comment' => 'Komentar baru',
- 'Comment updated' => 'Komentar diperbaharui',
+ 'Comment updated' => 'Komentar diperbarui',
'New subtask' => 'Sub-tugas baru',
'I want to receive notifications only for those projects:' => 'Saya ingin menerima pemberitahuan hanya untuk proyek-proyek yang dipilih :',
'view the task on Kanboard' => 'lihat tugas di Kanboard',
@@ -329,125 +323,125 @@ return array(
'Disable public access' => 'Nonaktifkan akses publik',
'Enable public access' => 'Aktifkan akses publik',
'Public access disabled' => 'Akses publik dinonaktifkan',
- 'Do you really want to disable this project: "%s"?' => 'Apakah anda yakin akan menonaktifkan proyek ini : « %s » ?',
- 'Do you really want to enable this project: "%s"?' => 'Apakah anda yakin akan mengaktifkan proyek ini : « %s » ?',
+ 'Do you really want to disable this project: "%s"?' => 'Apakah Anda yakin mau menonaktifkan proyek ini: "%s"?',
+ 'Do you really want to enable this project: "%s"?' => 'Apakah Anda yakin mau mengaktifkan proyek ini: "%s"?',
'Project activation' => 'Aktivasi proyek',
'Move the task to another project' => 'Pindahkan tugas ke proyek lain',
'Move to another project' => 'Pindahkan ke proyek lain',
- 'Do you really want to duplicate this task?' => 'Apakah anda yakin akan menduplikasi tugas ini ?',
+ 'Do you really want to duplicate this task?' => 'Apakah Anda yakin mau menduplikasi tugas ini?',
'Duplicate a task' => 'Duplikasi tugas',
'External accounts' => 'Akun eksternal',
'Account type' => 'Tipe akun',
'Local' => 'Lokal',
- 'Remote' => 'Jauh',
+ 'Remote' => 'Jarak Jauh',
'Enabled' => 'Aktif',
'Disabled' => 'Nonaktif',
- 'Username:' => 'Nama pengguna :',
- 'Name:' => 'Nama :',
- 'Email:' => 'Email :',
- 'Notifications:' => 'Pemberitahuan :',
+ // 'Login:' => '',
+ // 'Full Name:' => '',
+ 'Email:' => 'Email:',
+ 'Notifications:' => 'Pemberitahuan:',
'Notifications' => 'Pemberitahuan',
- 'Account type:' => 'Tipe akun :',
- 'Edit profile' => 'Modifikasi profil',
- 'Change password' => 'Rubah kata sandri',
- 'Password modification' => 'Modifikasi kata sandi',
+ 'Account type:' => 'Tipe akun:',
+ 'Edit profile' => 'Edit profil',
+ 'Change password' => 'Ganti password',
+ 'Password modification' => 'Modifikasi password',
'External authentications' => 'Otentifikasi eksternal',
'Never connected.' => 'Tidak pernah terhubung.',
'No external authentication enabled.' => 'Tidak ada otentifikasi eksternal yang aktif.',
- 'Password modified successfully.' => 'Kata sandi berhasil dimodifikasi.',
- 'Unable to change the password.' => 'Tidak dapat merubah kata sandir.',
- 'Change category' => 'Rubah kategori',
- '%s updated the task %s' => '%s memperbaharui tugas %s',
+ 'Password modified successfully.' => 'Password berhasil dimodifikasi.',
+ 'Unable to change the password.' => 'Tidak dapat mengganti kata sandi.',
+ 'Change category' => 'Ganti kategori',
+ '%s updated the task %s' => '%s memperbarui tugas %s',
'%s opened the task %s' => '%s membuka tugas %s',
- '%s moved the task %s to the position #%d in the column "%s"' => '%s memindahkan tugas %s ke posisi n°%d dalam kolom « %s »',
- '%s moved the task %s to the column "%s"' => '%s memindahkan tugas %s ke kolom « %s »',
+ '%s moved the task %s to the position #%d in the column "%s"' => '%s memindahkan tugas %s ke posisi #%d dalam kolom "%s"',
+ '%s moved the task %s to the column "%s"' => '%s memindahkan tugas %s ke kolom "%s"',
'%s created the task %s' => '%s membuat tugas %s',
'%s closed the task %s' => '%s menutup tugas %s',
- '%s created a subtask for the task %s' => '%s membuat subtugas untuk tugas %s',
- '%s updated a subtask for the task %s' => '%s memperbaharui subtugas untuk tugas %s',
- 'Assigned to %s with an estimate of %s/%sh' => 'Ditugaskan untuk %s dengan perkiraan %s/%sh',
+ '%s created a subtask for the task %s' => '%s membuat sub-tugas untuk tugas %s',
+ '%s updated a subtask for the task %s' => '%s memperbarui sub-tugas untuk tugas %s',
+ 'Assigned to %s with an estimate of %s/%sh' => 'Ditugaskan pada %s dengan perkiraan %s/%sh',
'Not assigned, estimate of %sh' => 'Tidak ada yang ditugaskan, perkiraan %sh',
- '%s updated a comment on the task %s' => '%s memperbaharui komentar pada tugas %s',
+ '%s updated a comment on the task %s' => '%s memperbarui komentar pada tugas %s',
'%s commented the task %s' => '%s memberikan komentar pada tugas %s',
'%s\'s activity' => 'Aktifitas dari %s',
- 'RSS feed' => 'RSS feed',
- '%s updated a comment on the task #%d' => '%s memperbaharui komentar pada tugas n°%d',
- '%s commented on the task #%d' => '%s memberikan komentar pada tugas n°%d',
- '%s updated a subtask for the task #%d' => '%s memperbaharui subtugas untuk tugas n°%d',
- '%s created a subtask for the task #%d' => '%s membuat subtugas untuk tugas n°%d',
- '%s updated the task #%d' => '%s memperbaharui tugas n°%d',
- '%s created the task #%d' => '%s membuat tugas n°%d',
- '%s closed the task #%d' => '%s menutup tugas n°%d',
- '%s opened the task #%d' => '%s membuka tugas n°%d',
+ 'RSS feed' => 'Umpan RSS',
+ '%s updated a comment on the task #%d' => '%s memperbarui komentar pada tugas #%d',
+ '%s commented on the task #%d' => '%s memberikan komentar pada tugas #%d',
+ '%s updated a subtask for the task #%d' => '%s memperbarui sub-tugas untuk tugas #%d',
+ '%s created a subtask for the task #%d' => '%s membuat sub-tugas untuk tugas #%d',
+ '%s updated the task #%d' => '%s memperbarui tugas #%d',
+ '%s created the task #%d' => '%s membuat tugas #%d',
+ '%s closed the task #%d' => '%s menutup tugas #%d',
+ '%s opened the task #%d' => '%s membuka tugas #%d',
'Activity' => 'Aktifitas',
- 'Default values are "%s"' => 'Standar nilai adalah« %s »',
+ 'Default values are "%s"' => 'Nilai default adalah "%s"',
'Default columns for new projects (Comma-separated)' => 'Kolom default untuk proyek baru (dipisahkan dengan koma)',
- 'Task assignee change' => 'Mengubah orang ditugaskan untuk tugas',
- '%s changed the assignee of the task #%d to %s' => '%s rubah orang yang ditugaskan dari tugas n%d ke %s',
- '%s changed the assignee of the task %s to %s' => '%s mengubah orang yang ditugaskan dari tugas %s ke %s',
- 'New password for the user "%s"' => 'Kata sandi baru untuk pengguna « %s »',
+ 'Task assignee change' => 'Ganti orang yang ditugaskan',
+ '%s changed the assignee of the task #%d to %s' => '%s mengganti orang yang ditugaskan dari tugas #%d ke %s',
+ '%s changed the assignee of the task %s to %s' => '%s mengganti orang yang ditugaskan dari tugas %s ke %s',
+ 'New password for the user "%s"' => 'Password baru untuk pengguna "%s"',
'Choose an event' => 'Pilih acara',
- 'Create a task from an external provider' => 'Buat tugas dari pemasok eksternal',
- 'Change the assignee based on an external username' => 'Rubah penugasan berdasarkan nama pengguna eksternal',
- 'Change the category based on an external label' => 'Rubah kategori berdasarkan label eksternal',
+ 'Create a task from an external provider' => 'Buat tugas dari penyedia eksternal',
+ 'Change the assignee based on an external username' => 'Ganti penugasan berdasarkan nama pengguna eksternal',
+ 'Change the category based on an external label' => 'Ganti kategori berdasarkan label eksternal',
'Reference' => 'Referensi',
'Label' => 'Label',
- 'Database' => 'Basis data',
+ 'Database' => 'Database',
'About' => 'Tentang',
- 'Database driver:' => 'Driver basis data :',
+ 'Database driver:' => 'Driver database:',
'Board settings' => 'Pengaturan papan',
- 'Webhook settings' => 'Pengaturan webhook',
- 'Reset token' => 'Mereset token',
+ 'Webhook settings' => 'Pengaturan Webhook',
+ 'Reset token' => 'Reset token',
'API endpoint:' => 'API endpoint :',
'Refresh interval for private board' => 'Interval pembaruan untuk papan pribadi',
'Refresh interval for public board' => 'Interval pembaruan untuk papan publik',
- 'Task highlight period' => 'Periode puncak tugas',
- 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode (dalam detik) untuk mempertimbangkan tugas yang baru dimodifikasi (0 untuk menonaktifkan, standar 2 hari)',
- 'Frequency in second (60 seconds by default)' => 'Frequensi dalam detik (standar 60 detik)',
- 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frequensi dalam detik (0 untuk menonaktifkan fitur ini, standar 10 detik)',
+ 'Task highlight period' => 'Periode penyorotan tugas',
+ 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode (dalam detik) untuk mempertimbangkan tugas yang baru dimodifikasi (0 untuk menonaktifkan, default 2 hari)',
+ 'Frequency in second (60 seconds by default)' => 'Frekuensi dalam detik (default 60 detik)',
+ 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekuensi dalam detik (0 untuk menonaktifkan fitur ini, default 10 detik)',
'Application URL' => 'URL Aplikasi',
'Token regenerated.' => 'Token diregenerasi.',
'Date format' => 'Format tanggal',
- 'ISO format is always accepted, example: "%s" and "%s"' => 'Format ISO selalu diterima, contoh : « %s » et « %s »',
+ 'ISO format is always accepted, example: "%s" and "%s"' => 'Format ISO selalu diterima, contoh: "%s" dan "%s"',
'New private project' => 'Proyek pribadi baru',
- 'This project is private' => 'Proyek ini adalah pribadi',
+ 'This project is private' => 'Proyek ini pribadi',
'Add' => 'Tambah',
'Start date' => 'Tanggal mulai',
'Time estimated' => 'Perkiraan waktu',
- 'There is nothing assigned to you.' => 'Tidak ada yang diberikan kepada anda.',
+ 'There is nothing assigned to you.' => 'Tidak ada tugas yang diberikan pada Anda.',
'My tasks' => 'Tugas saya',
'Activity stream' => 'Arus aktifitas',
'Dashboard' => 'Dasbor',
'Confirmation' => 'Konfirmasi',
- 'Allow everybody to access to this project' => 'Memungkinkan semua orang untuk mengakses proyek ini',
+ 'Allow everybody to access to this project' => 'Izinkan semua orang untuk mengakses proyek ini',
'Everybody have access to this project.' => 'Semua orang mendapat akses untuk proyek ini.',
'Webhooks' => 'Webhooks',
'API' => 'API',
- 'Create a comment from an external provider' => 'Buat komentar dari pemasok eksternal',
+ 'Create a comment from an external provider' => 'Buat komentar dari penyedia eksternal',
'Project management' => 'Manajemen proyek',
'My projects' => 'Proyek saya',
'Columns' => 'Kolom',
'Task' => 'Tugas',
- 'Your are not member of any project.' => 'Anda bukan anggota dari setiap proyek.',
+ 'Your are not member of any project.' => 'Anda bukan anggota dari proyek apapun.',
'Percentage' => 'Persentasi',
'Number of tasks' => 'Jumlah dari tugas',
'Task distribution' => 'Pembagian tugas',
- 'Analytics' => 'Analitis',
- 'Subtask' => 'Subtugas',
- 'My subtasks' => 'Subtugas saya',
+ 'Analytics' => 'Analitik',
+ 'Subtask' => 'Sub-tugas',
+ 'My subtasks' => 'Sub-tugas saya',
'User repartition' => 'Partisi ulang pengguna',
- 'Clone this project' => 'Gandakan proyek ini',
+ 'Clone this project' => 'Klon proyek ini',
'Column removed successfully.' => 'Kolom berhasil dihapus.',
'Not enough data to show the graph.' => 'Tidak cukup data untuk menampilkan grafik.',
'Previous' => 'Sebelumnya',
- 'The id must be an integer' => 'Id harus integer',
- 'The project id must be an integer' => 'Id proyek harus integer',
+ 'The id must be an integer' => 'ID harus integer',
+ 'The project id must be an integer' => 'ID proyek harus integer',
'The status must be an integer' => 'Status harus integer',
- 'The subtask id is required' => 'Id subtugas diperlukan',
- 'The subtask id must be an integer' => 'Id subtugas harus integer',
- 'The task id is required' => 'Id tugas diperlukan',
- 'The task id must be an integer' => 'Id tugas harus integer',
- 'The user id must be an integer' => 'Id user harus integer',
+ 'The subtask id is required' => 'ID sub-tugas diperlukan',
+ 'The subtask id must be an integer' => 'ID sub-tugas harus integer',
+ 'The task id is required' => 'ID tugas diperlukan',
+ 'The task id must be an integer' => 'ID tugas harus integer',
+ 'The user id must be an integer' => 'ID user harus integer',
'This value is required' => 'Nilai ini diperlukan',
'This value must be numeric' => 'Nilai ini harus angka',
'Unable to create this task.' => 'Tidak dapat membuat tugas ini',
@@ -455,121 +449,119 @@ return array(
'Daily project summary' => 'Ringkasan proyek harian',
'Daily project summary export' => 'Ekspor ringkasan proyek harian',
'Exports' => 'Ekspor',
- 'This export contains the number of tasks per column grouped per day.' => 'Ekspor ini berisi jumlah dari tugas per kolom dikelompokan perhari.',
+ 'This export contains the number of tasks per column grouped per day.' => 'Ekspor ini berisi jumlah dari tugas per kolom yang dikelompokan per hari.',
'Active swimlanes' => 'Swimlanes aktif',
'Add a new swimlane' => 'Tambah swimlane baru',
- 'Change default swimlane' => 'Modifikasi standar swimlane',
- 'Default swimlane' => 'Standar swimlane',
- 'Do you really want to remove this swimlane: "%s"?' => 'Apakah anda yakin akan menghapus swimlane ini : « %s » ?',
+ 'Change default swimlane' => 'Ganti swimlane default',
+ 'Default swimlane' => 'Swimlane default',
+ 'Do you really want to remove this swimlane: "%s"?' => 'Apakah Anda yakin mau menghapus swimlane ini: "%s"?',
'Inactive swimlanes' => 'Swimlanes tidak aktif',
- 'Remove a swimlane' => 'Supprimer une swimlane',
- 'Show default swimlane' => 'Perlihatkan standar swimlane',
- 'Swimlane modification for the project "%s"' => 'Modifikasi swimlane untuk proyek « %s »',
+ 'Remove a swimlane' => 'Hapus swimlane',
+ 'Show default swimlane' => 'Lihat swimlane default',
+ 'Swimlane modification for the project "%s"' => 'Modifikasi swimlane untuk proyek "%s"',
'Swimlane removed successfully.' => 'Swimlane berhasil dihapus.',
'Swimlanes' => 'Swimlanes',
- 'Swimlane updated successfully.' => 'Swimlane berhasil diperbaharui.',
- 'The default swimlane have been updated successfully.' => 'Standar swimlane berhasil diperbaharui.',
+ 'Swimlane updated successfully.' => 'Swimlane berhasil diperbarui.',
+ 'The default swimlane have been updated successfully.' => 'Swimlane default berhasil diperbarui.',
'Unable to remove this swimlane.' => 'Tidak dapat menghapus swimlane ini.',
- 'Unable to update this swimlane.' => 'Tidak dapat memperbaharui swimlane ini.',
- 'Your swimlane have been created successfully.' => 'Swimlane anda berhasil dibuat.',
- 'Example: "Bug, Feature Request, Improvement"' => 'Contoh: « Insiden, Permintaan Fitur, Perbaikan »',
- 'Default categories for new projects (Comma-separated)' => 'Standar kategori untuk proyek baru (dipisahkan dengan koma)',
+ 'Unable to update this swimlane.' => 'Tidak dapat memperbarui swimlane ini.',
+ 'Your swimlane have been created successfully.' => 'Swimlane Anda berhasil dibuat.',
+ 'Example: "Bug, Feature Request, Improvement"' => 'Contoh: "Bug, Permintaan Fitur, Peningkatan"',
+ 'Default categories for new projects (Comma-separated)' => 'Kategori default untuk proyek baru (dipisahkan dengan koma)',
'Integrations' => 'Integrasi',
'Integration with third-party services' => 'Integrasi dengan layanan pihak ketiga',
- 'Subtask Id' => 'Id Subtugas',
- 'Subtasks' => 'Subtugas',
- 'Subtasks Export' => 'Ekspor Subtugas',
+ 'Subtask Id' => 'ID Sub-tugas',
+ 'Subtasks' => 'Sub-tugas',
+ 'Subtasks Export' => 'Ekspor Sub-tugas',
'Task Title' => 'Judul Tugas',
- 'Untitled' => 'Tanpa nama',
- 'Application default' => 'Aplikasi standar',
- 'Language:' => 'Bahasa :',
- 'Timezone:' => 'Zona waktu :',
+ 'Untitled' => 'Tanpa Nama',
+ 'Application default' => 'Default aplikasi',
+ 'Language:' => 'Bahasa:',
+ 'Timezone:' => 'Zona waktu:',
'All columns' => 'Semua kolom',
'Calendar' => 'Kalender',
'Next' => 'Selanjutnya',
- '#%d' => 'n˚%d',
+ '#%d' => '#%d',
'All swimlanes' => 'Semua swimlane',
'All colors' => 'Semua warna',
'Moved to column %s' => 'Pindah ke kolom %s',
'User dashboard' => 'Dasbor pengguna',
- 'Allow only one subtask in progress at the same time for a user' => 'Izinkan hanya satu subtugas dalam proses secara bersamaan untuk satu pengguna',
- 'Edit column "%s"' => 'Modifikasi kolom « %s »',
- 'Select the new status of the subtask: "%s"' => 'Pilih status baru untuk subtugas : « %s »',
- 'Subtask timesheet' => 'Subtugas absen',
- 'There is nothing to show.' => 'Tidak ada yang dapat diperlihatkan.',
- 'Time Tracking' => 'Pelacakan waktu',
- 'You already have one subtask in progress' => 'Anda sudah ada satu subtugas dalam proses',
- 'Which parts of the project do you want to duplicate?' => 'Bagian dalam proyek mana yang ingin anda duplikasi?',
+ 'Allow only one subtask in progress at the same time for a user' => 'Izinkan hanya satu sub-tugas dalam proses secara bersamaan untuk satu pengguna',
+ 'Edit column "%s"' => 'Edit kolom "%s"',
+ 'Select the new status of the subtask: "%s"' => 'Pilih status baru untuk sub-tugas: "%s"',
+ 'Subtask timesheet' => 'Absen sub-tugas',
+ 'There is nothing to show.' => 'Tidak ada yang bisa diperlihatkan.',
+ 'Time Tracking' => 'Pelacakan Waktu',
+ 'You already have one subtask in progress' => 'Anda sudah memiliki satu sub-tugas dalam proses',
+ 'Which parts of the project do you want to duplicate?' => 'Bagian proyek mana yang ingin Anda duplikasi?',
'Disallow login form' => 'Larang formulir masuk',
'Start' => 'Mulai',
'End' => 'Selesai',
'Task age in days' => 'Usia tugas dalam hari',
'Days in this column' => 'Hari dalam kolom ini',
- '%dd' => '%dj',
+ '%dd' => '%dd',
'Add a new link' => 'Tambah tautan baru',
- 'Do you really want to remove this link: "%s"?' => 'Apakah anda yakin akan menghapus tautan ini : « %s » ?',
- 'Do you really want to remove this link with task #%d?' => 'Apakah anda yakin akan menghapus tautan ini dengan tugas n°%d ?',
- 'Field required' => 'Field diperlukan',
+ 'Do you really want to remove this link: "%s"?' => 'Apakah Anda yakin mau menghapus tautan ini: "%s"?',
+ 'Do you really want to remove this link with task #%d?' => 'Apakah Anda yakin mau menghapus tautan ini dengan tugas #%d ?',
+ 'Field required' => 'Bidang dibutuhkan',
'Link added successfully.' => 'Tautan berhasil ditambahkan.',
- 'Link updated successfully.' => 'Tautan berhasil diperbaharui.',
+ 'Link updated successfully.' => 'Tautan berhasil diperbarui.',
'Link removed successfully.' => 'Tautan berhasil dihapus.',
'Link labels' => 'Label tautan',
'Link modification' => 'Modifikasi tautan',
'Links' => 'Tautan',
- 'Link settings' => 'Pengaturan tautan',
'Opposite label' => 'Label berlawanan',
'Remove a link' => 'Hapus tautan',
- 'Task\'s links' => 'Tautan tugas',
'The labels must be different' => 'Label harus berbeda',
'There is no link.' => 'Tidak ada tautan.',
'This label must be unique' => 'Label ini harus unik',
- 'Unable to create your link.' => 'Tidak dapat membuat tautan anda.',
- 'Unable to update your link.' => 'Tidak dapat memperbaharui tautan anda.',
+ 'Unable to create your link.' => 'Tidak dapat membuat tautan Anda.',
+ 'Unable to update your link.' => 'Tidak dapat memperbarui tautan Anda.',
'Unable to remove this link.' => 'Tidak dapat menghapus tautan ini.',
'relates to' => 'berhubungan dengan',
- 'blocks' => 'blok',
+ 'blocks' => 'blokir',
'is blocked by' => 'diblokir oleh',
'duplicates' => 'duplikat',
'is duplicated by' => 'diduplikasi oleh',
'is a child of' => 'anak dari',
- 'is a parent of' => 'orant tua dari',
- 'targets milestone' => 'milestone target',
- 'is a milestone of' => 'adalah milestone dari',
+ 'is a parent of' => 'induk dari',
+ 'targets milestone' => 'target batu pijakan',
+ 'is a milestone of' => 'adalah batu pijakan dari',
'fixes' => 'perbaikan',
'is fixed by' => 'diperbaiki oleh',
'This task' => 'Tugas ini',
'<1h' => '<1h',
'%dh' => '%dh',
'Expand tasks' => 'Perluas tugas',
- 'Collapse tasks' => 'Lipat tugas',
- 'Expand/collapse tasks' => 'Perluas/lipat tugas',
+ 'Collapse tasks' => 'Tutup tugas',
+ 'Expand/collapse tasks' => 'Perluas/tutup tugas',
'Close dialog box' => 'Tutup kotak dialog',
- 'Submit a form' => 'Submit formulir',
- 'Board view' => 'Table halaman',
- 'Keyboard shortcuts' => 'pintas keyboard',
- 'Open board switcher' => 'Buka table switcher',
+ 'Submit a form' => 'Kirim formulir',
+ 'Board view' => 'Tampilan papan',
+ 'Keyboard shortcuts' => 'Pintasan keyboard',
+ 'Open board switcher' => 'Buka switcher papan',
'Application' => 'Aplikasi',
'Compact view' => 'Tampilan kompak',
- 'Horizontal scrolling' => 'Horisontal bergulir',
- 'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas',
- 'No results match:' => 'Tidak ada hasil :',
+ 'Horizontal scrolling' => 'Gulir horizontal',
+ 'Compact/wide view' => 'Tampilan kompak/lebar',
'Currency' => 'Mata uang',
'Private project' => 'Proyek pribadi',
- 'AUD - Australian Dollar' => 'AUD - Dollar Australia',
- 'CAD - Canadian Dollar' => 'CAD - Dollar Kanada',
- 'CHF - Swiss Francs' => 'CHF - Swiss Prancis',
- 'Custom Stylesheet' => 'Kustomisasi Stylesheet',
+ 'AUD - Australian Dollar' => 'AUD - Dolar Australia',
+ 'CAD - Canadian Dollar' => 'CAD - Dolar Kanada',
+ 'CHF - Swiss Francs' => 'CHF - Francs Swiss',
+ 'Custom Stylesheet' => 'Kustomisasi CSS',
'download' => 'unduh',
'EUR - Euro' => 'EUR - Euro',
- 'GBP - British Pound' => 'GBP - Poundsterling inggris',
+ 'GBP - British Pound' => 'GBP - Poundsterling Inggris',
'INR - Indian Rupee' => 'INR - Rupe India',
'JPY - Japanese Yen' => 'JPY - Yen Jepang',
- 'NZD - New Zealand Dollar' => 'NZD - Dollar Selandia baru',
+ 'NZD - New Zealand Dollar' => 'NZD - Dolar Selandia baru',
'RSD - Serbian dinar' => 'RSD - Dinar Serbia',
- 'USD - US Dollar' => 'USD - Dollar Amerika',
+ // 'CNY - Chinese Yuan' => '',
+ 'USD - US Dollar' => 'USD - Dolar Amerika',
'Destination column' => 'Kolom tujuan',
- 'Move the task to another column when assigned to a user' => 'Pindahkan tugas ke kolom lain ketika ditugaskan ke pengguna',
- 'Move the task to another column when assignee is cleared' => 'Pindahkan tugas ke kolom lain ketika orang yang ditugaskan dibersihkan',
+ 'Move the task to another column when assigned to a user' => 'Pindahkan tugas ke kolom lain saat ditugaskan ke pengguna',
+ 'Move the task to another column when assignee is cleared' => 'Pindahkan tugas ke kolom lain saat orang yang ditugaskan kosong',
'Source column' => 'Sumber kolom',
'Transitions' => 'Transisi',
'Executer' => 'Eksekusi',
@@ -579,77 +571,76 @@ return array(
'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Laporan ini berisi semua kolom yang pindah untuk setiap tugas dengan tanggal, pengguna dan waktu yang dihabiskan untuk setiap transisi.',
'Currency rates' => 'Nilai tukar mata uang',
'Rate' => 'Tarif',
- 'Change reference currency' => 'Mengubah referensi mata uang',
- 'Add a new currency rate' => 'Tambahkan nilai tukar mata uang baru',
+ 'Change reference currency' => 'Ganti referensi mata uang',
'Reference currency' => 'Referensi mata uang',
'The currency rate have been added successfully.' => 'Nilai tukar mata uang berhasil ditambahkan.',
'Unable to add this currency rate.' => 'Tidak dapat menambahkan nilai tukar mata uang',
- 'Webhook URL' => 'URL webhook',
+ 'Webhook URL' => 'URL Webhook',
'%s removed the assignee of the task %s' => '%s menghapus penugasan dari tugas %s',
- 'Enable Gravatar images' => 'Mengaktifkan gambar Gravatar',
+ 'Enable Gravatar images' => 'Aktifkan gambar Gravatar',
'Information' => 'Informasi',
'Check two factor authentication code' => 'Cek dua faktor kode otentifikasi',
- 'The two factor authentication code is not valid.' => 'Kode dua faktor kode otentifikasi tidak valid.',
- 'The two factor authentication code is valid.' => 'Kode dua faktor kode otentifikasi valid.',
+ 'The two factor authentication code is not valid.' => 'Kode dua faktor kode otentifikasi tidak sesuai.',
+ 'The two factor authentication code is valid.' => 'Kode dua faktor kode otentifikasi sesuai.',
'Code' => 'Kode',
'Two factor authentication' => 'Dua faktor otentifikasi',
- 'This QR code contains the key URI: ' => 'kode QR ini mengandung kunci URI : ',
- 'Check my code' => 'Memeriksa kode saya',
- 'Secret key: ' => 'Kunci rahasia : ',
- 'Test your device' => 'Menguji perangkat anda',
- 'Assign a color when the task is moved to a specific column' => 'Menetapkan warna ketika tugas tersebut dipindahkan ke kolom tertentu',
+ 'This QR code contains the key URI: ' => 'Kode QR ini mengandung kunci URI: ',
+ 'Check my code' => 'Periksa kode saya',
+ 'Secret key: ' => 'Kunci rahasia: ',
+ 'Test your device' => 'Uji perangkat Anda',
+ 'Assign a color when the task is moved to a specific column' => 'Tetapkan warna ketika tugas tersebut dipindahkan ke kolom tertentu',
'%s via Kanboard' => '%s via Kanboard',
'Burndown chart' => 'Grafik Burndown',
'This chart show the task complexity over the time (Work Remaining).' => 'Grafik ini menunjukkan kompleksitas tugas dari waktu ke waktu (Sisa Pekerjaan).',
'Screenshot taken %s' => 'Screenshot diambil %s',
'Add a screenshot' => 'Tambah screenshot',
- 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Mengambil screenshot dan tekan CTRL + V atau ⌘ + V untuk paste di sini.',
+ 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Ambil screenshot dan tekan CTRL+V atau ⌘+V untuk ditempel di sini.',
'Screenshot uploaded successfully.' => 'Screenshot berhasil diunggah.',
'SEK - Swedish Krona' => 'SEK - Krona Swedia',
'Identifier' => 'Identifier',
'Disable two factor authentication' => 'Matikan dua faktor otentifikasi',
- 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Apakah anda yakin akan mematikan dua faktor otentifikasi untuk pengguna ini : « %s » ?',
- 'Edit link' => 'Modifikasi tautan',
+ 'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Apakah Anda yakin mau mematikan dua faktor otentifikasi untuk pengguna ini: "%s"?',
+ 'Edit link' => 'Edit tautan',
'Start to type task title...' => 'Mulai mengetik judul tugas...',
- 'A task cannot be linked to itself' => 'Sebuah tugas tidak dapat dikaitkan dengan dirinya sendiri',
+ 'A task cannot be linked to itself' => 'Tugas tidak dapat dikaitkan dengan dirinya sendiri',
'The exact same link already exists' => 'Tautan yang sama persis sudah ada',
- 'Recurrent task is scheduled to be generated' => 'Tugas berulang dijadwalkan akan dihasilkan',
+ 'Recurrent task is scheduled to be generated' => 'Tugas berulang dijadwalkan untuk di generate',
'Score' => 'Skor',
'The identifier must be unique' => 'Identifier harus unik',
- 'This linked task id doesn\'t exists' => 'Id tugas terkait tidak ada',
+ 'This linked task id doesn\'t exists' => 'ID tugas terkait tidak ada',
'This value must be alphanumeric' => 'Nilai harus alfanumerik',
- 'Edit recurrence' => 'Modifikasi pengulangan',
- 'Generate recurrent task' => 'Menghasilkan tugas berulang',
- 'Trigger to generate recurrent task' => 'Memicu untuk menghasilkan tugas berulang',
+ 'Edit recurrence' => 'Edit pengulangan',
+ 'Generate recurrent task' => 'Generate tugas berulang',
+ 'Trigger to generate recurrent task' => 'Pemicu untuk menghasilkan tugas berulang',
'Factor to calculate new due date' => 'Faktor untuk menghitung tanggal jatuh tempo baru',
'Timeframe to calculate new due date' => 'Jangka waktu untuk menghitung tanggal jatuh tempo baru',
'Base date to calculate new due date' => 'Tanggal dasar untuk menghitung tanggal jatuh tempo baru',
'Action date' => 'Tanggal aksi',
'Base date to calculate new due date: ' => 'Tanggal dasar untuk menghitung tanggal jatuh tempo baru: ',
- 'This task has created this child task: ' => 'Tugas ini telah menciptakan tugas anak ini: ',
+ 'This task has created this child task: ' => 'Tugas ini telah membuat tugas anak ini: ',
'Day(s)' => 'Hari',
'Existing due date' => 'Batas waktu yang ada',
'Factor to calculate new due date: ' => 'Faktor untuk menghitung tanggal jatuh tempo baru: ',
'Month(s)' => 'Bulan',
'Recurrence' => 'Pengulangan',
- 'This task has been created by: ' => 'Tugas ini telah dibuat oleh:',
- 'Recurrent task has been generated:' => 'Tugas berulang telah dihasilkan:',
+ 'This task has been created by: ' => 'Tugas ini telah dibuat oleh: ',
+ 'Recurrent task has been generated:' => 'Tugas berulang telah di generate:',
'Timeframe to calculate new due date: ' => 'Jangka waktu untuk menghitung tanggal jatuh tempo baru: ',
'Trigger to generate recurrent task: ' => 'Pemicu untuk menghasilkan tugas berulang: ',
- 'When task is closed' => 'Ketika tugas ditutup',
- 'When task is moved from first column' => 'Ketika tugas dipindahkan dari kolom pertama',
- 'When task is moved to last column' => 'Ketika tugas dipindahkan ke kolom terakhir',
+ 'When task is closed' => 'Saat tugas ditutup',
+ 'When task is moved from first column' => 'Saat tugas dipindahkan dari kolom pertama',
+ 'When task is moved to last column' => 'Saat tugas dipindahkan ke kolom terakhir',
'Year(s)' => 'Tahun',
'Calendar settings' => 'Pengaturan kalender',
'Project calendar view' => 'Tampilan kalender proyek',
'Project settings' => 'Pengaturan proyek',
- 'Show subtasks based on the time tracking' => 'Tampilkan subtugas berdasarkan pelacakan waktu',
+ 'Show subtasks based on the time tracking' => 'Tampilkan sub-tugas berdasarkan pelacakan waktu',
'Show tasks based on the creation date' => 'Tampilkan tugas berdasarkan tanggal pembuatan',
'Show tasks based on the start date' => 'Tampilkan tugas berdasarkan tanggal mulai',
- 'Subtasks time tracking' => 'Pelacakan waktu subtgas',
- 'User calendar view' => 'Pengguna tampilan kalender',
- 'Automatically update the start date' => 'Memperbarui tanggal mulai otomatis',
- 'iCal feed' => 'iCal feed',
+ 'Subtasks time tracking' => 'Pelacakan waktu sub-tugas',
+ 'User calendar view' => 'Tampilan kalender pengguna',
+ 'Automatically update the start date' => 'Otomatis memperbarui tanggal permulaan',
+ 'iCal feed' => 'Umpan iCal',
'Preferences' => 'Preferensi',
'Security' => 'Keamanan',
'Two factor authentication disabled' => 'Otentifikasi dua faktor dimatikan',
@@ -657,40 +648,40 @@ return array(
'Unable to update this user.' => 'Tidak dapat memperbarui pengguna ini.',
'There is no user management for private projects.' => 'Tidak ada manajemen pengguna untuk proyek-proyek pribadi.',
'User that will receive the email' => 'Pengguna yang akan menerima email',
- 'Email subject' => 'Subjek Email',
+ 'Email subject' => 'Subyek Email',
'Date' => 'Tanggal',
'Add a comment log when moving the task between columns' => 'Menambahkan log komentar ketika memindahkan tugas antara kolom',
'Move the task to another column when the category is changed' => 'Pindahkan tugas ke kolom lain ketika kategori berubah',
'Send a task by email to someone' => 'Kirim tugas melalui email ke seseorang',
- 'Reopen a task' => 'Membuka kembali tugas',
+ 'Reopen a task' => 'Buka kembali tugas',
'Notification' => 'Pemberitahuan',
- '%s moved the task #%d to the first swimlane' => '%s memindahkan tugas n°%d ke swimlane pertama',
+ '%s moved the task #%d to the first swimlane' => '%s memindahkan tugas #%d ke swimlane pertama',
'Swimlane' => 'Swimlane',
'Gravatar' => 'Gravatar',
'%s moved the task %s to the first swimlane' => '%s memindahkan tugas %s ke swimlane pertama',
- '%s moved the task %s to the swimlane "%s"' => '%s memindahkan tugas %s ke swimlane « %s »',
- 'This report contains all subtasks information for the given date range.' => 'Laporan ini berisi semua informasi subtugas untuk rentang tanggal tertentu.',
+ '%s moved the task %s to the swimlane "%s"' => '%s memindahkan tugas %s ke swimlane "%s"',
+ 'This report contains all subtasks information for the given date range.' => 'Laporan ini berisi semua informasi sub-tugas untuk rentang tanggal tertentu.',
'This report contains all tasks information for the given date range.' => 'Laporan ini berisi semua informasi tugas untuk rentang tanggal tertentu.',
- 'Project activities for %s' => 'Aktifitas proyek untuk « %s »',
+ 'Project activities for %s' => 'Aktifitas proyek untuk "%s"',
'view the board on Kanboard' => 'lihat papan di Kanboard',
'The task have been moved to the first swimlane' => 'Tugas telah dipindahkan ke swimlane pertama',
'The task have been moved to another swimlane:' => 'Tugas telah dipindahkan ke swimlane lain:',
- 'New title: %s' => 'Judul baru : %s',
+ 'New title: %s' => 'Judul baru: %s',
'The task is not assigned anymore' => 'Tugas tidak ditugaskan lagi',
- 'New assignee: %s' => 'Penerima baru : %s',
- 'There is no category now' => 'Tidak ada kategori untuk sekarang',
- 'New category: %s' => 'Kategori baru : %s',
- 'New color: %s' => 'Warna baru : %s',
- 'New complexity: %d' => 'Kompleksitas baru : %d',
+ 'New assignee: %s' => 'Penerima baru: %s',
+ 'There is no category now' => 'Tidak ada kategori untuk saat ini',
+ 'New category: %s' => 'Kategori baru: %s',
+ 'New color: %s' => 'Warna baru: %s',
+ 'New complexity: %d' => 'Kompleksitas baru: %d',
'The due date have been removed' => 'Tanggal jatuh tempo telah dihapus',
'There is no description anymore' => 'Tidak ada deskripsi lagi',
'Recurrence settings have been modified' => 'Pengaturan pengulangan telah dimodifikasi',
- 'Time spent changed: %sh' => 'Waktu yang dihabiskan berubah : %sh',
- 'Time estimated changed: %sh' => 'Perkiraan waktu berubah : %sh',
- 'The field "%s" have been updated' => 'Field « %s » telah diperbaharui',
+ 'Time spent changed: %sh' => 'Waktu yang dihabiskan telah diganti: %sh',
+ 'Time estimated changed: %sh' => 'Perkiraan waktu telah diganti: %sh',
+ 'The field "%s" have been updated' => 'Bidang "%s" telah diperbarui',
'The description has been modified:' => 'Deskripsi telah dimodifikasi',
- 'Do you really want to close the task "%s" as well as all subtasks?' => 'Apakah anda yakin akan menutup tugas « %s » beserta semua sub-tugasnya ?',
- 'I want to receive notifications for:' => 'Saya ingin menerima pemberitahuan untuk :',
+ 'Do you really want to close the task "%s" as well as all subtasks?' => 'Apakah Anda yakin mau menutup tugas "%s" beserta semua sub-tugasnya?',
+ 'I want to receive notifications for:' => 'Saya ingin menerima pemberitahuan untuk:',
'All tasks' => 'Semua tugas',
'Only for tasks assigned to me' => 'Hanya untuk tugas yang ditugaskan ke saya',
'Only for tasks created by me' => 'Hanya untuk tugas yang dibuat oleh saya',
@@ -702,84 +693,81 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Hentikan timer',
'Start timer' => 'Mulai timer',
- 'Add project member' => 'Tambahkan anggota proyek',
'My activity stream' => 'Aliran kegiatan saya',
'My calendar' => 'Kalender saya',
'Search tasks' => 'Cari tugas',
- 'Reset filters' => 'Reset ulang filter',
+ 'Reset filters' => 'Reset saringan',
'My tasks due tomorrow' => 'Tugas saya yang berakhir besok',
'Tasks due today' => 'Tugas yang berakhir hari ini',
'Tasks due tomorrow' => 'Tugas yang berakhir besok',
'Tasks due yesterday' => 'Tugas yang berakhir kemarin',
'Closed tasks' => 'Tugas yang ditutup',
- 'Open tasks' => 'Buka Tugas',
+ 'Open tasks' => 'Tugas terbuka',
'Not assigned' => 'Tidak ditugaskan',
'View advanced search syntax' => 'Lihat sintaks pencarian lanjutan',
- 'Overview' => 'Ikhtisar',
+ 'Overview' => 'Ringkasan',
'Board/Calendar/List view' => 'Tampilan Papan/Kalender/Daftar',
'Switch to the board view' => 'Beralih ke tampilan papan',
'Switch to the calendar view' => 'Beralih ke tampilan kalender',
'Switch to the list view' => 'Beralih ke tampilan daftar',
- 'Go to the search/filter box' => 'Pergi ke kotak pencarian/filter',
- 'There is no activity yet.' => 'Tidak ada aktifitas saat ini.',
+ 'Go to the search/filter box' => 'Pergi ke kotak pencarian/saringan',
+ 'There is no activity yet.' => 'Belum ada aktifitas.',
'No tasks found.' => 'Tidak ada tugas yang ditemukan.',
- 'Keyboard shortcut: "%s"' => 'Keyboard shortcut : « %s »',
+ 'Keyboard shortcut: "%s"' => 'Pintasan keyboard: "%s"',
'List' => 'Daftar',
- 'Filter' => 'Filter',
+ 'Filter' => 'Saringan',
'Advanced search' => 'Pencarian lanjutan',
'Example of query: ' => 'Contoh dari query : ',
- 'Search by project: ' => 'Pencarian berdasarkan proyek : ',
- 'Search by column: ' => 'Pencarian berdasarkan kolom : ',
- 'Search by assignee: ' => 'Pencarian berdasarkan penerima : ',
- 'Search by color: ' => 'Pencarian berdasarkan warna : ',
- 'Search by category: ' => 'Pencarian berdasarkan kategori : ',
- 'Search by description: ' => 'Pencarian berdasarkan deskripsi : ',
- 'Search by due date: ' => 'Pencarian berdasarkan tanggal jatuh tempo : ',
+ 'Search by project: ' => 'Cari berdasarkan proyek: ',
+ 'Search by column: ' => 'Cari berdasarkan kolom: ',
+ 'Search by assignee: ' => 'Cari berdasarkan penerima tugas: ',
+ 'Search by color: ' => 'Cari berdasarkan warna: ',
+ 'Search by category: ' => 'Cari berdasarkan kategori: ',
+ 'Search by description: ' => 'Cari berdasarkan deskripsi: ',
+ 'Search by due date: ' => 'Cari berdasarkan tanggal jatuh tempo: ',
'Average time spent into each column' => 'Rata-rata waktu yang dihabiskan dalam setiap kolom',
'Average time spent' => 'Rata-rata waktu yang dihabiskan',
- 'This chart show the average time spent into each column for the last %d tasks.' => 'Grafik ini menunjukkan rata-rata waktu yang dihabiskan dalam setiap kolom untuk %d tugas.',
- 'Average Lead and Cycle time' => 'Rata-rata Memimpin dan Siklus waktu',
- 'Average lead time: ' => 'Rata-rata waktu pimpinan : ',
- 'Average cycle time: ' => 'Rata-rata siklus waktu : ',
- 'Cycle Time' => 'Siklus Waktu',
+ 'This chart show the average time spent into each column for the last %d tasks.' => 'Grafik ini menunjukkan rata-rata waktu yang dihabiskan dalam setiap kolom untuk %d tugas terakhir.',
+ 'Average Lead and Cycle time' => 'Rata-rata Lead dan Cycle time',
+ 'Average lead time: ' => 'Rata-rata lead time: ',
+ 'Average cycle time: ' => 'Rata-rata cycle time: ',
+ 'Cycle Time' => 'Cycle Time',
'Lead Time' => 'Lead Time',
- 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Grafik ini menunjukkan memimpin rata-rata dan waktu siklus untuk %d tugas terakhir dari waktu ke waktu.',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Grafik ini menunjukkan rata-rata waktu lead dan cycle time untuk %d tugas terakhir dari waktu ke waktu.',
'Average time into each column' => 'Rata-rata waktu ke setiap kolom',
- 'Lead and cycle time' => 'Lead dan siklus waktu',
- 'Lead time: ' => 'Lead time : ',
- 'Cycle time: ' => 'Siklus waktu : ',
+ 'Lead and cycle time' => 'Lead dan cycle time',
+ 'Lead time: ' => 'Lead time: ',
+ 'Cycle time: ' => 'Cycle time: ',
'Time spent into each column' => 'Waktu yang dihabiskan di setiap kolom',
'The lead time is the duration between the task creation and the completion.' => 'Lead time adalah durasi antara pembuatan tugas dan penyelesaian.',
- 'The cycle time is the duration between the start date and the completion.' => 'Siklus waktu adalah durasi antara tanggal mulai dan tanggal penyelesaian.',
- 'If the task is not closed the current time is used instead of the completion date.' => 'Jika tugas tidak ditutup waktu saat ini yang digunakan sebagai pengganti tanggal penyelesaian.',
+ 'The cycle time is the duration between the start date and the completion.' => 'Cycle time adalah durasi antara tanggal mulai dan tanggal penyelesaian.',
+ 'If the task is not closed the current time is used instead of the completion date.' => 'Jika tugas tidak ditutup, waktu saat ini akan digunakan sebagai pengganti tanggal penyelesaian.',
'Set automatically the start date' => 'Secara otomatis mengatur tanggal mulai',
- 'Edit Authentication' => 'Modifikasi Otentifikasi',
+ 'Edit Authentication' => 'Edit Otentifikasi',
'Remote user' => 'Pengguna jauh',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Pengguna jauh tidak menyimpan kata sandi mereka dalam basis data Kanboard, contoh: akun LDAP, Google dan Github.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Jika anda mencentang kotak "Larang formulir login", kredensial masuk ke formulis login akan diabaikan.',
- 'New remote user' => 'Pengguna baru jauh',
- 'New local user' => 'Pengguna baru lokal',
- 'Default task color' => 'Standar warna tugas',
- 'This feature does not work with all browsers.' => 'Fitur ini tidak dapat digunakan di semua browsers',
- 'There is no destination project available.' => 'Tidak ada destinasi proyek yang tersedia.',
- 'Trigger automatically subtask time tracking' => 'Otomatis memicu pelacakan untuk subtugas',
- 'Include closed tasks in the cumulative flow diagram' => 'Termasuk tugas yang ditutup pada diagram aliran kumulatif',
- 'Current swimlane: %s' => 'Swimlane saat ini : %s',
- 'Current column: %s' => 'Kolom saat ini : %s',
- 'Current category: %s' => 'Kategori saat ini : %s',
+ 'Default task color' => 'Warna tugas default',
+ 'This feature does not work with all browsers.' => 'Fitur ini tidak dapat digunakan di semua peramban',
+ 'There is no destination project available.' => 'Tidak ada tujuan proyek yang tersedia.',
+ 'Trigger automatically subtask time tracking' => 'Otomatis memicu pelacakan waktu untuk sub-tugas',
+ 'Include closed tasks in the cumulative flow diagram' => 'Sertakan tugas yang ditutup dalam diagram alir kumulatif',
+ 'Current swimlane: %s' => 'Swimlane saat ini: %s',
+ 'Current column: %s' => 'Kolom saat ini: %s',
+ 'Current category: %s' => 'Kategori saat ini: %s',
'no category' => 'tidak ada kategori',
- 'Current assignee: %s' => 'Saat ini ditugaskan : %s',
- 'not assigned' => 'Belum ditugaskan',
- 'Author:' => 'Penulis :',
+ 'Current assignee: %s' => 'Orang yang ditugaskan saat ini: %s',
+ 'not assigned' => 'belum ditugaskan',
+ 'Author:' => 'Penulis:',
'contributors' => 'kontributor',
- 'License:' => 'Lisensi :',
+ 'License:' => 'Lisensi:',
'License' => 'Lisensi',
'Enter the text below' => 'Masukkan teks di bawah',
'Sort by position' => 'Urutkan berdasarkan posisi',
'Sort by date' => 'Urutkan berdasarkan tanggal',
'Add task' => 'Tambah tugas',
- 'Start date:' => 'Tanggal mulai :',
- 'Due date:' => 'Batas waktu :',
+ 'Start date:' => 'Tanggal mulai:',
+ 'Due date:' => 'Batas waktu:',
'There is no start date or due date for this task.' => 'Tidak ada tanggal mulai dan batas waktu untuk tugas ini.',
'Moving or resizing a task will change the start and due date of the task.' => 'Memindahkan atau mengubah ukuran tugas anda akan mengubah tanggal mulai dan batas waktu dari tugas ini.',
'There is no task in your project.' => 'Tidak ada tugas didalam proyek anda.',
@@ -791,7 +779,7 @@ return array(
'Hide this column' => 'Sembunyikan kolom ini',
'open file' => 'buka berkas',
'End date' => 'Waktu berakhir',
- 'Users overview' => 'Ikhtisar pengguna',
+ 'Users overview' => 'Ringkasan pengguna',
'Members' => 'Anggota',
'Shared project' => 'Proyek bersama',
'Project managers' => 'Manajer proyek',
@@ -799,15 +787,15 @@ return array(
'Projects list' => 'Daftar proyek',
'Gantt chart for this project' => 'Grafik Gantt untuk proyek ini',
'Project board' => 'Papan proyek',
- 'End date:' => 'Waktu berakhir :',
+ 'End date:' => 'Waktu berakhir:',
'There is no start date or end date for this project.' => 'Tidak ada waktu mulai atau waktu berakhir untuk proyek ini',
- 'Projects Gantt chart' => 'Proyek grafik Gantt',
- 'Change task color when using a specific task link' => 'Rubah warna tugas ketika menggunakan tautan tugas yang spesifik',
+ 'Projects Gantt chart' => 'Grafik Gantt proyek',
+ 'Change task color when using a specific task link' => 'Ganti warna tugas ketika menggunakan tautan tugas yang spesifik',
'Task link creation or modification' => 'Tautan pembuatan atau modifikasi tugas ',
'Milestone' => 'Milestone',
- 'Documentation: %s' => 'Dokumentasi : %s',
+ 'Documentation: %s' => 'Dokumentasi: %s',
'Switch to the Gantt chart view' => 'Beralih ke tampilan grafik Gantt',
- 'Reset the search/filter box' => 'Atur ulang pencarian/kotak filter',
+ 'Reset the search/filter box' => 'Reset kotak pencarian/saringan',
'Documentation' => 'Dokumentasi',
'Table of contents' => 'Daftar isi',
'Gantt' => 'Gantt',
@@ -816,44 +804,43 @@ return array(
'Plugins' => 'Plugin',
'There is no plugin loaded.' => 'Tidak ada plugin yang dimuat',
'My notifications' => 'Notifikasi saya',
- 'Custom filters' => 'Filter kustom',
- 'Your custom filter have been created successfully.' => 'Filter kustom anda telah berhasil dibuat',
- 'Unable to create your custom filter.' => 'Tidak dapat membuat filter kustom',
- 'Custom filter removed successfully.' => 'Filter kustom berhail dihapus',
- 'Unable to remove this custom filter.' => 'Tidak dapat menghapus filter kustom',
- 'Edit custom filter' => 'Modifikasi filter kustom',
- 'Your custom filter have been updated successfully.' => 'Filter kustom anda telah berhasil diperbaharui',
- 'Unable to update custom filter.' => 'Tidak dapat memperbaharui filter kustom',
+ 'Custom filters' => 'Saringan kustom',
+ 'Your custom filter have been created successfully.' => 'Saringan kustom Anda berhasil dibuat',
+ 'Unable to create your custom filter.' => 'Tidak dapat membuat saringan kustom',
+ 'Custom filter removed successfully.' => 'Saringan kustom berhasil dihapus',
+ 'Unable to remove this custom filter.' => 'Tidak dapat menghapus saringan kustom',
+ 'Edit custom filter' => 'Edit saringan kustom',
+ 'Your custom filter have been updated successfully.' => 'Saringan kustom Anda berhasil diperbarui',
+ 'Unable to update custom filter.' => 'Tidak dapat memperbarui saringan kustom',
'Web' => 'Web',
'New attachment on task #%d: %s' => 'Lampiran baru pada tugas #%d: %s',
'New comment on task #%d' => 'Komentar baru pada tugas #%d',
- 'Comment updated on task #%d' => 'Komentar diperbaharui pada tugas #%d',
- 'New subtask on task #%d' => 'Subtask baru pada tugas #%d',
- 'Subtask updated on task #%d' => 'Subtask diperbaharui pada tugas #%d',
+ 'Comment updated on task #%d' => 'Komentar diperbarui pada tugas #%d',
+ 'New subtask on task #%d' => 'Sub-tugas baru pada tugas #%d',
+ 'Subtask updated on task #%d' => 'Sub-tugas diperbarui pada tugas #%d',
'New task #%d: %s' => 'Tugas baru #%d: %s',
- 'Task updated #%d' => 'Tugas diperbaharui #%d',
+ 'Task updated #%d' => 'Tugas diperbarui #%d',
'Task #%d closed' => 'Tugas #%d ditutup',
'Task #%d opened' => 'Tugas #%d dibuka',
- 'Column changed for task #%d' => 'Kolom berubah untuk tugas #%d',
+ 'Column changed for task #%d' => 'Kolom diganti untuk tugas #%d',
'New position for task #%d' => 'Posisi baru untuk tugas #%d',
- 'Swimlane changed for task #%d' => 'Swimlane berubah untuk tugas #%d',
- 'Assignee changed on task #%d' => 'Orang yang ditugaskan berubah pada tugas #%d',
- '%d overdue tasks' => '%d tugas terlambat',
- 'Task #%d is overdue' => 'Tugas #%d terlambat',
+ 'Swimlane changed for task #%d' => 'Swimlane diganti untuk tugas #%d',
+ 'Assignee changed on task #%d' => 'Orang yang ditugaskan diganti pada tugas #%d',
+ '%d overdue tasks' => '%d tugas kadaluarsa',
+ 'Task #%d is overdue' => 'Tugas #%d sudah kadaluarsa',
'No new notifications.' => 'Tidak ada notifikasi baru',
'Mark all as read' => 'Tandai semua sebagai sudah dibaca',
'Mark as read' => 'Tandai sebagai sudah dibaca',
- 'Total number of tasks in this column across all swimlanes' => 'Total jumlah tugas di kolom ini di semua swimlanes',
- 'Collapse swimlane' => 'Lipat swimlane',
+ 'Total number of tasks in this column across all swimlanes' => 'Total tugas di kolom ini untuk semua swimlane',
+ 'Collapse swimlane' => 'Tutup swimlane',
'Expand swimlane' => 'Perluas swimlane',
- 'Add a new filter' => 'Tambah filter baru',
- 'Share with all project members' => 'Bagikan dengan semua member proyek',
+ 'Add a new filter' => 'Tambah saringan baru',
+ 'Share with all project members' => 'Bagikan dengan semua anggota proyek',
'Shared' => 'Dibagikan',
'Owner' => 'Pemilik',
'Unread notifications' => 'Notifikasi belum terbaca',
'Notification methods:' => 'Metode pemberitahuan',
- 'Import tasks from CSV file' => 'Impor tugas dari berkas CSV',
- 'Unable to read your file' => 'Tidak dapat membaca berkas anda',
+ 'Unable to read your file' => 'Tidak dapat membaca berkas Anda',
'%d task(s) have been imported successfully.' => '%d tugas telah berhasil di impor',
'Nothing have been imported!' => 'Tidak ada yang dapat di impor',
'Import users from CSV file' => 'Impor pengguna dari berkas CSV',
@@ -865,14 +852,14 @@ return array(
'Double Quote' => 'Kutip Ganda',
'Single Quote' => 'Kutip Satu',
'%s attached a file to the task #%d' => '%s berkas dilampirkan untuk tugas #%d',
- 'There is no column or swimlane activated in your project!' => 'Tidak ada kolom atau swimlane aktif untuk proyek anda',
- 'Append filter (instead of replacement)' => 'Tambahkan filter (bukan pengganti)',
+ 'There is no column or swimlane activated in your project!' => 'Tidak ada kolom atau swimlane aktif untuk proyek Anda',
+ 'Append filter (instead of replacement)' => 'Tambahkan saringan (ketimbang pengganti)',
'Append/Replace' => 'Tambah/Ganti',
'Append' => 'Tambahkan',
'Replace' => 'Ganti',
'Import' => 'Impor',
- 'change sorting' => 'rubah sortir',
- 'Tasks Importation' => 'Tugas Impor',
+ 'change sorting' => 'ubah pengurutan',
+ 'Tasks Importation' => 'Importasi Tugas',
'Delimiter' => 'Pembatas',
'Enclosure' => 'Lampiran',
'CSV File' => 'Berkas CSV',
@@ -880,33 +867,33 @@ return array(
'Your file must use the predefined CSV format' => 'Berkas Anda harus menggunakan format CSV yang telah ditetapkan',
'Your file must be encoded in UTF-8' => 'Berkas anda harus di kodekan dalam bentuk UTF-8',
'The first row must be the header' => 'Baris pertama harus header',
- 'Duplicates are not verified for you' => 'Duplikasi tidak diverifikasi untuk anda',
+ 'Duplicates are not verified for you' => 'Duplikasi tidak diverifikasikan untuk Anda',
'The due date must use the ISO format: YYYY-MM-DD' => 'Tanggal jatuh tempo harus menggunakan format ISO: YYYY-MM-DD',
'Download CSV template' => 'Unduh template CSV',
- 'No external integration registered.' => 'Tidak ada integrasi eksternal terdaftar',
+ 'No external integration registered.' => 'Tidak ada integrasi eksternal yang terdaftar',
'Duplicates are not imported' => 'Duplikasi tidak diimpor',
- 'Usernames must be lowercase and unique' => 'Username harus huruf kecil dan unik',
+ 'Usernames must be lowercase and unique' => 'Nama pengguna harus huruf kecil dan unik',
'Passwords will be encrypted if present' => 'Kata sandi akan di enkripsi jika ada',
- '%s attached a new file to the task %s' => '%s berkas baru dilampirkan untuk tugas %s',
+ '%s attached a new file to the task %s' => '%s melampirkan berkas baru untuk tugas %s',
'Link type' => 'Tipe tautan',
- 'Assign automatically a category based on a link' => 'Menetapkan otomatis kategori berdasarkan tautan',
+ 'Assign automatically a category based on a link' => 'Otomatis menetapkan kategori berdasarkan tautan',
'BAM - Konvertible Mark' => 'BAM - Konvertible Mark',
- 'Assignee Username' => 'Username yang ditugaskan',
- 'Assignee Name' => 'Nama yang ditugaskan',
+ 'Assignee Username' => 'Nama pengguna orang yang ditugaskan',
+ 'Assignee Name' => 'Nama orang yang ditugaskan',
'Groups' => 'Grup',
'Members of %s' => 'Anggota dari %s',
'New group' => 'Grup baru',
'Group created successfully.' => 'Grup berhasil dibuat',
- 'Unable to create your group.' => 'Tidak dapat membuat grup anda',
- 'Edit group' => 'Rubah grup',
- 'Group updated successfully.' => 'Grup berhasil diperbaharui',
- 'Unable to update your group.' => 'Tidak dapat memperbaharui grup anda',
+ 'Unable to create your group.' => 'Tidak dapat membuat grup Anda',
+ 'Edit group' => 'Edit grup',
+ 'Group updated successfully.' => 'Grup berhasil diperbarui',
+ 'Unable to update your group.' => 'Tidak dapat memperbarui grup anda',
'Add group member to "%s"' => 'Tambahkan anggota grup ke "%s"',
'Group member added successfully.' => 'Anggota grup berhasil ditambahkan',
'Unable to add group member.' => 'Tidak dapat menambahkan anggota grup',
- 'Remove user from group "%s"' => 'hapus pengguna dari grup "%s"',
+ 'Remove user from group "%s"' => 'Hapus pengguna dari grup "%s"',
'User removed successfully from this group.' => 'Pengguna berhasil dihapus dari grup ini',
- 'Unable to remove this user from the group.' => 'Tidak dapat menghapus pengguna dari grup',
+ 'Unable to remove this user from the group.' => 'Tidak dapat menghapus pengguna ini dari grup',
'Remove group' => 'Hapus grup',
'Group removed successfully.' => 'Grup berhasil dihapus',
'Unable to remove this group.' => 'Tidak dapat menghapus grup ini',
@@ -916,75 +903,74 @@ return array(
'Project Member' => 'Anggota Proyek',
'Project Viewer' => 'Penonton Proyek',
'Your account is locked for %d minutes' => 'Akun anda dikunci untuk %d menit',
- 'Invalid captcha' => 'Captcha tidak valid',
+ 'Invalid captcha' => 'Captcha tidak sesuai',
'The name must be unique' => 'Nama harus unik',
'View all groups' => 'Lihat semua grup',
'There is no user available.' => 'Tidak ada pengguna yang tersedia',
- 'Do you really want to remove the user "%s" from the group "%s"?' => 'Anda yakin akan menghapus pengguna "%s" dari grup "%s"?',
+ 'Do you really want to remove the user "%s" from the group "%s"?' => 'Anda yakin mau menghapus pengguna "%s" dari grup "%s"?',
'There is no group.' => 'Tidak ada grup',
- 'External Id' => 'Id Eksternal',
+ 'External Id' => 'ID Eksternal',
'Add group member' => 'Tambah anggota grup',
- 'Do you really want to remove this group: "%s"?' => 'Anda yakin akan menghapus grup ini: "%s"?',
+ 'Do you really want to remove this group: "%s"?' => 'Anda yakin mau menghapus grup ini: "%s"?',
'There is no user in this group.' => 'Tidak ada pengguna dalam grup ini',
'Remove this user' => 'Hapus pengguna ini',
'Permissions' => 'Izin',
- 'Allowed Users' => 'Pengguna Yang Diperbolehkan',
+ 'Allowed Users' => 'Pengguna Yang Diizinkan',
'No user have been allowed specifically.' => 'Tidak ada user yang diperbolehkan secara khusus',
'Role' => 'Peran',
'Enter user name...' => 'Masukkan nama pengguna...',
- 'Allowed Groups' => 'Grup Yang Diperbolehkan',
+ 'Allowed Groups' => 'Grup Yang Diizinkan',
'No group have been allowed specifically.' => 'Tidak ada grup yang diperbolehkan secara khusus',
'Group' => 'Grup',
'Group Name' => 'Nama Grup',
'Enter group name...' => 'Masukkan nama grup...',
'Role:' => 'Peran:',
'Project members' => 'Anggota proyek',
- '%s mentioned you in the task #%d' => '%s menyebut anda dalam tugas #%d',
- '%s mentioned you in a comment on the task #%d' => '%s menyebut anda dalam komentar pada tugas #%d',
+ '%s mentioned you in the task #%d' => '%s menyebut Anda dalam tugas #%d',
+ '%s mentioned you in a comment on the task #%d' => '%s menyebut Anda dalam komentar pada tugas #%d',
'You were mentioned in the task #%d' => 'Anda disebutkan dalam tugas #%d',
'You were mentioned in a comment on the task #%d' => 'Anda disebutkan dalam komentar pada tugas #%d',
- 'Estimated hours: ' => 'Estimasi jam:',
- 'Actual hours: ' => 'Aktual jam',
+ 'Estimated hours: ' => 'Estimasi jam: ',
+ 'Actual hours: ' => 'Jam sebenarnya: ',
'Hours Spent' => 'Jam dihabiskan',
'Hours Estimated' => 'Jam diperkirakan',
'Estimated Time' => 'Waktu Estimasi',
- 'Actual Time' => 'Waktu Aktual',
- 'Estimated vs actual time' => 'Estimasi vs waktu aktual',
- 'RUB - Russian Ruble' => 'RUB - Rusia rubel',
- 'Assign the task to the person who does the action when the column is changed' => 'Menetapkan tugas kepada orang yang melakukan tindakan ketika kolom berubah',
+ 'Actual Time' => 'Waktu Sebenarnya',
+ 'Estimated vs actual time' => 'Estimasi vs waktu sebenarnya',
+ 'RUB - Russian Ruble' => 'RUB - Rubel Rusia',
+ 'Assign the task to the person who does the action when the column is changed' => 'Berikan tugas pada orang yang melakukan tindakan saat kolom diganti',
'Close a task in a specific column' => 'Tutup tugas di kolom tertentu',
- 'Time-based One-time Password Algorithm' => 'Waktu berbasis Satu-waktu Algoritma Kata sandi',
- 'Two-Factor Provider: ' => 'Provider Dua-Faktor',
+ 'Time-based One-time Password Algorithm' => 'Algoritma Password Satu-Kali Berbasis-Waktu',
+ 'Two-Factor Provider: ' => 'Penyedia Dua-Faktor',
'Disable two-factor authentication' => 'Nonaktifkan otentikasi dua-faktor',
'Enable two-factor authentication' => 'Aktifkan otentikasi dua-faktor',
- 'There is no integration registered at the moment.' => 'Tidak ada integrasi yang diregristasi untuk saat ini',
- 'Password Reset for Kanboard' => 'Setel ulang Kata sandi untuk Kanboard',
- 'Forgot password?' => 'Lupa kata sandi',
- 'Enable "Forget Password"' => 'Aktifkan "Lupa Kata Sandi"',
- 'Password Reset' => 'Setel ulang Kata sandi',
- 'New password' => 'Kata sandi baru',
- 'Change Password' => 'Rubah kata sandi',
- 'To reset your password click on this link:' => 'Untuk menyetel ulang kata sandi anda klik tautan ini:',
- 'Last Password Reset' => 'Terakhir Setel Ulang Kata Sandi',
- 'The password has never been reinitialized.' => 'Kata sandi tidak pernah di reinisialisasi',
- 'Creation' => 'Kreasi',
- 'Expiration' => 'Waktu berakhir',
- 'Password reset history' => 'Sejarah setel ulang kata sandi',
+ 'There is no integration registered at the moment.' => 'Tidak ada integrasi yang didaftarkan untuk saat ini',
+ 'Password Reset for Kanboard' => 'Reset Password untuk Kanboard',
+ 'Forgot password?' => 'Lupa password?',
+ 'Enable "Forget Password"' => 'Aktifkan "Lupa Password"',
+ 'Password Reset' => 'Reset Password',
+ 'New password' => 'Password baru',
+ 'Change Password' => 'Ganti Password',
+ 'To reset your password click on this link:' => 'Untuk reset password Anda klik tautan ini:',
+ 'Last Password Reset' => 'Reset Password Terakhir',
+ 'The password has never been reinitialized.' => 'Password tidak pernah di inisialisasi ulang',
+ 'Creation' => 'Pembuatan',
+ 'Expiration' => 'Kadaluarsa',
+ 'Password reset history' => 'Sejarah reset password',
'All tasks of the column "%s" and the swimlane "%s" have been closed successfully.' => 'Semua tugas dalam kolom "%s" dan swimlane "%s" telah berhasil ditutup',
- 'Do you really want to close all tasks of this column?' => 'Apakah anda yakin akan menutup semua tugas dalam kolom ini?',
+ 'Do you really want to close all tasks of this column?' => 'Apakah Anda yakin mau menutup semua tugas dalam kolom ini?',
'%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d tugas dalam kolom "%s" dan swimlane "%s" akan ditutup.',
'Close all tasks of this column' => 'Tutup semua tugas dalam kolom ini',
- 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Tidak ada Plugin yang mendaftar metode pemberitahuan proyek. Anda masih dapat mengkonfigurasi pemberitahuan individu dalam profil pengguna Anda.',
+ 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Tidak ada plugin yang mendaftarkan metode pemberitahuan proyek. Anda masih bisa mengatur pemberitahuan individu di dalam profil pengguna Anda.',
'My dashboard' => 'Dasbor saya',
'My profile' => 'Profil saya',
'Project owner: ' => 'Pemilik proyek',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Identifier proyek adalah opsional dan harus alfanumerik, contoh: MYPROJECT.',
'Project owner' => 'Pemilik proyek',
- 'Those dates are useful for the project Gantt chart.' => 'Tanggal tersebut berguna untuk proyek Gantt chart',
'Private projects do not have users and groups management.' => 'Proyek pribadi tidak memiliki manajemen pengguna dan grup',
'There is no project member.' => 'Tidak ada anggota proyek',
'Priority' => 'Prioritas',
- 'Task priority' => 'Tugas prioritas',
+ 'Task priority' => 'Prioritas tugas',
'General' => 'Umum',
'Dates' => 'Tanggal',
'Default priority' => 'Prioritas default',
@@ -995,8 +981,8 @@ return array(
'Duration in days' => 'Durasi dalam hari',
'Send email when there is no activity on a task' => 'Kirim email jika tidak ada aktifitas dalam tugas',
'Unable to fetch link information.' => 'Tidak dapat mengambil informasi tautan',
- 'Daily background job for tasks' => 'Pekerjaan Latar belakang untuk tugas-tugas ',
- 'Auto' => 'Auto',
+ 'Daily background job for tasks' => 'Tugas latar belakang harian untuk tugas',
+ 'Auto' => 'Otomatis',
'Related' => 'Terkait',
'Attachment' => 'Lampiran',
'Title not found' => 'Judul tidak ditemukan',
@@ -1014,7 +1000,7 @@ return array(
'Internal links' => 'Tautan internal',
'Assign to me' => 'Tugaskan ke saya',
'Me' => 'Saya',
- 'Do not duplicate anything' => 'Jangan menduplikasi apa-apa',
+ 'Do not duplicate anything' => 'Jangan menduplikasi apapun',
'Projects management' => 'Manajemen proyek',
'Users management' => 'Manajemen pengguna',
'Groups management' => 'Manajemen grup',
@@ -1023,268 +1009,302 @@ return array(
'closed' => 'tutup',
'Priority:' => 'Prioritas',
'Reference:' => 'Referensi',
- 'Complexity:' => 'Komplesitas',
+ 'Complexity:' => 'Kompleksitas',
'Swimlane:' => 'Swimlane',
- 'Column:' => 'Kolom',
- 'Position:' => 'Posisi',
- 'Creator:' => 'Pembuat',
+ 'Column:' => 'Kolom:',
+ 'Position:' => 'Posisi:',
+ 'Creator:' => 'Pembuat:',
'Time estimated:' => 'Estimasi waktu:',
'%s hours' => '%s jam',
- 'Time spent:' => 'Waktu dihabiskan',
- 'Created:' => 'Dibuat',
- 'Modified:' => 'Dimodifikasi',
- 'Completed:' => 'Selesai',
- 'Started:' => 'Dimulai',
- 'Moved:' => 'Dipindahkan',
+ 'Time spent:' => 'Waktu yang dihabiskan',
+ 'Created:' => 'Dibuat:',
+ 'Modified:' => 'Dimodifikasi:',
+ 'Completed:' => 'Selesai:',
+ 'Started:' => 'Dimulai:',
+ 'Moved:' => 'Dipindahkan:',
'Task #%d' => 'Tugas #%d',
- 'Date and time format' => 'Format tanggal dan waktu',
'Time format' => 'Format waktu',
- 'Start date: ' => 'Tanggal mulai',
- 'End date: ' => 'Tanggal berakhir',
- 'New due date: ' => 'Tanggal jatuh tempo baru',
- 'Start date changed: ' => 'Tanggal mulai berubah',
- 'Disable private projects' => 'Nonaktifkan proyek',
- 'Do you really want to remove this custom filter: "%s"?' => 'Apakah anda yakin akan menghapus kustom filter: "%s"?',
- 'Remove a custom filter' => 'Hapus kustom filter',
- 'User activated successfully.' => 'Pengguna berhasil diaktivasi.',
+ 'Start date: ' => 'Tanggal mulai: ',
+ 'End date: ' => 'Tanggal berakhir: ',
+ 'New due date: ' => 'Tanggal jatuh tempo baru: ',
+ 'Start date changed: ' => 'Tanggal mulai diganti: ',
+ 'Disable private projects' => 'Nonaktifkan proyek pribadi',
+ 'Do you really want to remove this custom filter: "%s"?' => 'Apakah Anda yakin mau menghapus saringan kustom: "%s"?',
+ 'Remove a custom filter' => 'Hapus saringan kustom',
+ 'User activated successfully.' => 'Pengguna berhasil diaktifkan.',
'Unable to enable this user.' => 'Tidak dapat mengaktifkan pengguna ini.',
'User disabled successfully.' => 'Pengguna berhasil dinonaktifkan.',
'Unable to disable this user.' => 'Tidak dapat menonaktifkan pengguna ini.',
- 'All files have been uploaded successfully.' => 'Semua file telah berhasil di unggah.',
- 'View uploaded files' => 'Lihat file yang diunggah',
- 'The maximum allowed file size is %sB.' => 'Maksimum ukuran file yang diiziinkan adalah %sB.',
- 'Choose files again' => 'Pilih file kembali',
- 'Drag and drop your files here' => 'Drag and drop file anda di sini',
- 'choose files' => 'pilih file',
+ 'All files have been uploaded successfully.' => 'Semua berkas berhasil di unggah.',
+ 'The maximum allowed file size is %sB.' => 'Maksimum ukuran berkas yang diiziinkan adalah %sB.',
+ 'Drag and drop your files here' => 'Drag and drop file Anda di sini',
+ 'choose files' => 'pilih berkas',
'View profile' => 'Lihat profil',
'Two Factor' => 'Dua Faktor',
'Disable user' => 'Nonaktifkan pengguna',
- // 'Do you really want to disable this user: "%s"?' => '',
- // 'Enable user' => '',
- // 'Do you really want to enable this user: "%s"?' => '',
- // 'Download' => '',
- // 'Uploaded: %s' => '',
- // 'Size: %s' => '',
- // 'Uploaded by %s' => '',
- // 'Filename' => '',
- // 'Size' => '',
- // 'Column created successfully.' => '',
- // 'Another column with the same name exists in the project' => '',
- // 'Default filters' => '',
- // 'Your board doesn\'t have any columns!' => '',
- // 'Change column position' => '',
- // 'Switch to the project overview' => '',
- // 'User filters' => '',
- // 'Category filters' => '',
- // 'Upload a file' => '',
- // 'View file' => '',
- // 'Last activity' => '',
- // 'Change subtask position' => '',
- // 'This value must be greater than %d' => '',
- // 'Another swimlane with the same name exists in the project' => '',
- // 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => '',
- // 'Actions duplicated successfully.' => '',
- // 'Unable to duplicate actions.' => '',
- // 'Add a new action' => '',
- // 'Import from another project' => '',
- // 'There is no action at the moment.' => '',
- // 'Import actions from another project' => '',
- // 'There is no available project.' => '',
- // 'Local File' => '',
- // 'Configuration' => '',
- // 'PHP version:' => '',
- // 'PHP SAPI:' => '',
- // 'OS version:' => '',
- // 'Database version:' => '',
- // 'Browser:' => '',
- // 'Task view' => '',
- // 'Edit task' => '',
- // 'Edit description' => '',
- // 'New internal link' => '',
- // 'Display list of keyboard shortcuts' => '',
- // 'Menu' => '',
- // 'Set start date' => '',
- // 'Avatar' => '',
- // 'Upload my avatar image' => '',
- // 'Remove my image' => '',
- // 'The OAuth2 state parameter is invalid' => '',
- // 'User not found.' => '',
- // 'Search in activity stream' => '',
- // 'My activities' => '',
- // 'Activity until yesterday' => '',
- // 'Activity until today' => '',
- // 'Search by creator: ' => '',
- // 'Search by creation date: ' => '',
- // 'Search by task status: ' => '',
- // 'Search by task title: ' => '',
- // 'Activity stream search' => '',
- // 'Projects where "%s" is manager' => '',
- // 'Projects where "%s" is member' => '',
- // 'Open tasks assigned to "%s"' => '',
- // 'Closed tasks assigned to "%s"' => '',
- // 'Assign automatically a color based on a priority' => '',
- // 'Overdue tasks for the project(s) "%s"' => '',
- // 'Upload files' => '',
- // 'Installed Plugins' => '',
- // 'Plugin Directory' => '',
- // 'Plugin installed successfully.' => '',
- // 'Plugin updated successfully.' => '',
- // 'Plugin removed successfully.' => '',
- // 'Subtask converted to task successfully.' => '',
- // 'Unable to convert the subtask.' => '',
- // 'Unable to extract plugin archive.' => '',
- // 'Plugin not found.' => '',
- // 'You don\'t have the permission to remove this plugin.' => '',
- // 'Unable to download plugin archive.' => '',
- // 'Unable to write temporary file for plugin.' => '',
- // 'Unable to open plugin archive.' => '',
- // 'There is no file in the plugin archive.' => '',
- // 'Create tasks in bulk' => '',
- // 'Your Kanboard instance is not configured to install plugins from the user interface.' => '',
- // 'There is no plugin available.' => '',
- // 'Install' => '',
- // 'Update' => '',
- // 'Up to date' => '',
- // 'Not available' => '',
- // 'Remove plugin' => '',
- // 'Do you really want to remove this plugin: "%s"?' => '',
- // 'Uninstall' => '',
- // 'Listing' => '',
- // 'Metadata' => '',
- // 'Manage projects' => '',
- // 'Convert to task' => '',
- // 'Convert sub-task to task' => '',
- // 'Do you really want to convert this sub-task to a task?' => '',
- // 'My task title' => '',
- // 'Enter one task by line.' => '',
- // 'Number of failed login:' => '',
- // 'Account locked until:' => '',
- // 'Email settings' => '',
- // 'Email sender address' => '',
- // 'Email transport' => '',
- // 'Webhook token' => '',
- // 'Imports' => '',
- // 'Project tags management' => '',
- // 'Tag created successfully.' => '',
- // 'Unable to create this tag.' => '',
- // 'Tag updated successfully.' => '',
- // 'Unable to update this tag.' => '',
- // 'Tag removed successfully.' => '',
- // 'Unable to remove this tag.' => '',
- // 'Global tags management' => '',
- // 'Tags' => '',
- // 'Tags management' => '',
- // 'Add new tag' => '',
- // 'Edit a tag' => '',
- // 'Project tags' => '',
- // 'There is no specific tag for this project at the moment.' => '',
- // 'Tag' => '',
- // 'Remove a tag' => '',
- // 'Do you really want to remove this tag: "%s"?' => '',
- // 'Global tags' => '',
- // 'There is no global tag at the moment.' => '',
- // 'This field cannot be empty' => '',
- // 'Close a task when there is no activity in an specific column' => '',
- // '%s removed a subtask for the task #%d' => '',
- // '%s removed a comment on the task #%d' => '',
- // 'Comment removed on task #%d' => '',
- // 'Subtask removed on task #%d' => '',
- // 'Hide tasks in this column in the dashboard' => '',
- // '%s removed a comment on the task %s' => '',
- // '%s removed a subtask for the task %s' => '',
- // 'Comment removed' => '',
- // 'Subtask removed' => '',
- // '%s set a new internal link for the task #%d' => '',
- // '%s removed an internal link for the task #%d' => '',
- // 'A new internal link for the task #%d have been defined' => '',
- // 'Internal link removed for the task #%d' => '',
- // '%s set a new internal link for the task %s' => '',
- // '%s removed an internal link for the task %s' => '',
- // 'Automatically set the due date on task creation' => '',
- // 'Move the task to another column when closed' => '',
- // 'Move the task to another column when not moved during a given period' => '',
- // 'Dashboard for %s' => '',
- // 'Tasks overview for %s' => '',
- // 'Subtasks overview for %s' => '',
- // 'Projects overview for %s' => '',
- // 'Activity stream for %s' => '',
- // 'Calendar for %s' => '',
- // 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
- // 'Assign a color when the task is moved to a specific swimlane' => '',
- // 'Assign a priority when the task is moved to a specific swimlane' => '',
- // 'User unlocked successfully.' => '',
- // 'Unable to unlock the user.' => '',
- // 'Move a task to another swimlane' => '',
- // 'Creator Name' => '',
- // 'Time spent and estimated' => '',
- // 'Move position' => '',
- // 'Move task to another position on the board' => '',
- // 'Insert before this task' => '',
- // 'Insert after this task' => '',
- // 'Unlock this user' => '',
- // 'Custom Project Roles' => '',
- // 'Add a new custom role' => '',
- // 'Restrictions for the role "%s"' => '',
- // 'Add a new project restriction' => '',
- // 'Add a new drag and drop restriction' => '',
- // 'Add a new column restriction' => '',
- // 'Edit this role' => '',
- // 'Remove this role' => '',
- // 'There is no restriction for this role.' => '',
- // 'Only moving task between those columns is permitted' => '',
- // 'Close a task in a specific column when not moved during a given period' => '',
- // 'Edit columns' => '',
- // 'The column restriction has been created successfully.' => '',
- // 'Unable to create this column restriction.' => '',
- // 'Column restriction removed successfully.' => '',
- // 'Unable to remove this restriction.' => '',
- // 'Your custom project role has been created successfully.' => '',
- // 'Unable to create custom project role.' => '',
- // 'Your custom project role has been updated successfully.' => '',
- // 'Unable to update custom project role.' => '',
- // 'Custom project role removed successfully.' => '',
- // 'Unable to remove this project role.' => '',
- // 'The project restriction has been created successfully.' => '',
- // 'Unable to create this project restriction.' => '',
- // 'Project restriction removed successfully.' => '',
- // 'You cannot create tasks in this column.' => '',
- // 'Task creation is permitted for this column' => '',
- // 'Closing or opening a task is permitted for this column' => '',
- // 'Task creation is blocked for this column' => '',
- // 'Closing or opening a task is blocked for this column' => '',
- // 'Task creation is not permitted' => '',
- // 'Closing or opening a task is not permitted' => '',
- // 'New drag and drop restriction for the role "%s"' => '',
- // 'People belonging to this role will be able to move tasks only between the source and the destination column.' => '',
- // 'Remove a column restriction' => '',
- // 'Do you really want to remove this column restriction: "%s" to "%s"?' => '',
- // 'New column restriction for the role "%s"' => '',
- // 'Rule' => '',
- // 'Do you really want to remove this column restriction?' => '',
- // 'Custom roles' => '',
- // 'New custom project role' => '',
- // 'Edit custom project role' => '',
- // 'Remove a custom role' => '',
- // 'Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.' => '',
- // 'There is no custom role for this project.' => '',
- // 'New project restriction for the role "%s"' => '',
- // 'Restriction' => '',
- // 'Remove a project restriction' => '',
- // 'Do you really want to remove this project restriction: "%s"?' => '',
- // 'Duplicate to multiple projects' => '',
- // 'This field is required' => '',
- // 'Moving a task is not permitted' => '',
- // 'This value must be in the range %d to %d' => '',
- // 'You are not allowed to move this task.' => '',
- // 'API User Access' => '',
- // 'Preview' => '',
- // 'Write' => '',
- // 'Write your text in Markdown' => '',
- // 'New External Task: %s' => '',
- // 'No personal API access token registered.' => '',
- // 'Your personal API access token is "%s"' => '',
- // 'Remove your token' => '',
- // 'Generate a new token' => '',
+ 'Do you really want to disable this user: "%s"?' => 'Anda yakin mau menonaktifkan pengguna ini: "%s"?',
+ 'Enable user' => 'Aktifkan pengguna',
+ 'Do you really want to enable this user: "%s"?' => 'Anda yakin mau mengaktifkan pengguna ini: "%s"?',
+ 'Download' => 'Unduh',
+ 'Uploaded: %s' => 'Diunggah: %s',
+ 'Size: %s' => 'Ukuran: %s',
+ 'Uploaded by %s' => 'Diunggah oleh %s',
+ 'Filename' => 'Nama berkas',
+ 'Size' => 'Ukuran',
+ 'Column created successfully.' => 'Kolom berhasil dibuat.',
+ 'Another column with the same name exists in the project' => 'Ada kolom lain dengan nama yang sama di proyek ini',
+ 'Default filters' => 'Saringan default',
+ 'Your board doesn\'t have any columns!' => 'Papan Anda tidak memiliki kolom!',
+ 'Change column position' => 'Ganti posisi kolom',
+ 'Switch to the project overview' => 'Pindah ke ringkasan proyek',
+ 'User filters' => 'Saringan pengguna',
+ 'Category filters' => 'Saringan kategori',
+ 'Upload a file' => 'Unggah berkas',
+ 'View file' => 'Lihat berkas',
+ 'Last activity' => 'Aktivitas terakhir',
+ 'Change subtask position' => 'Ganti posisi sub-tugas',
+ 'This value must be greater than %d' => 'Nilai ini harus lebih besar dari %d',
+ 'Another swimlane with the same name exists in the project' => 'Swimlane lain dengan nama yang sama sudah ada di proyek ini',
+ 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Contoh: http://contoh.kanboard.net/ (digunakan untuk menghasilkan URL yang absolut',
+ 'Actions duplicated successfully.' => 'Tindakan berhasil di duplikasi.',
+ 'Unable to duplicate actions.' => 'Tidak bisa menduplikasi tindakan.',
+ 'Add a new action' => 'Tambahkan tindakan baru',
+ 'Import from another project' => 'Impor dari proyek lain',
+ 'There is no action at the moment.' => 'Belum ada tindakan pada saat ini.',
+ 'Import actions from another project' => 'Impor tindakan dari proyek lain',
+ 'There is no available project.' => 'Tidak ada proyek yang tersedia',
+ 'Local File' => 'Berkas Lokal',
+ 'Configuration' => 'Konfigurasi',
+ 'PHP version:' => 'Versi PHP:',
+ 'PHP SAPI:' => 'PHP SAPI:',
+ 'OS version:' => 'Versi sistem operasi:',
+ 'Database version:' => 'Versi database:',
+ 'Browser:' => 'Peramban:',
+ 'Task view' => 'Tampilan Tugas',
+ 'Edit task' => 'Edit tugas',
+ 'Edit description' => 'Edit deskripsi',
+ 'New internal link' => 'Tautan internal baru',
+ 'Display list of keyboard shortcuts' => 'Tampilkan daftar pintasan keyboard',
+ 'Menu' => 'Menu',
+ 'Set start date' => 'Atur tanggal mulai',
+ 'Avatar' => 'Avatar',
+ 'Upload my avatar image' => 'Unggah foto avatar saya',
+ 'Remove my image' => 'Hapus foto saya',
+ 'The OAuth2 state parameter is invalid' => 'Status parameter OAuth2 tidak sesuai',
+ 'User not found.' => 'Pengguna tidak ditemukan.',
+ 'Search in activity stream' => 'Cari di saluran aktivitas',
+ 'My activities' => 'Aktivitas saya',
+ 'Activity until yesterday' => 'Aktivitas sampai kemarin',
+ 'Activity until today' => 'Aktivitas sampai hari ini',
+ 'Search by creator: ' => 'Cari berdasarkan pembuat: ',
+ 'Search by creation date: ' => 'Cari berdasarkan tanggal pembuatan: ',
+ 'Search by task status: ' => 'Cari berdasarkanstatus tugas: ',
+ 'Search by task title: ' => 'Cari berdasarkan judul tugas: ',
+ 'Activity stream search' => 'Pencarian saluran aktivitas',
+ 'Projects where "%s" is manager' => 'Proyek dimana "%s" adalah manajernya',
+ 'Projects where "%s" is member' => 'Proyek dimana "%s" adalah anggotanya',
+ 'Open tasks assigned to "%s"' => 'Tugas terbuka ditugaskan pada "%s"',
+ 'Closed tasks assigned to "%s"' => 'Tugas tertutup ditugaskan pada "%s"',
+ 'Assign automatically a color based on a priority' => 'Berikan warna otomatis berdasarkan prioritas',
+ 'Overdue tasks for the project(s) "%s"' => 'Tugas yang kadaluarsa untuk proyek "%s"',
+ 'Upload files' => 'Unggah berkas',
+ 'Installed Plugins' => 'Plugin terpasang',
+ 'Plugin Directory' => 'Direktori Plugin',
+ 'Plugin installed successfully.' => 'Plugin berhasil dipasang.',
+ 'Plugin updated successfully.' => 'Plugin berhasil diperbarui.',
+ 'Plugin removed successfully.' => 'Plugin berhasil dihapus.',
+ 'Subtask converted to task successfully.' => 'Sub-tugas berhasil diubah menjadi tugas.',
+ 'Unable to convert the subtask.' => 'Tidak dapat mengubah sub-tugas.',
+ 'Unable to extract plugin archive.' => 'Tidak bisa mengekstrak arsip plugin.',
+ 'Plugin not found.' => 'Plugin tidak ditemukan.',
+ 'You don\'t have the permission to remove this plugin.' => 'Anda tidak memiliki izin untuk menghapus plugin ini.',
+ 'Unable to download plugin archive.' => 'Tidak dapat mengunduh arsip plugin.',
+ 'Unable to write temporary file for plugin.' => 'Tidak dapat menulis berkas sementara untuk plugin.',
+ 'Unable to open plugin archive.' => 'Tidak dapat membuka arsip plugin.',
+ 'There is no file in the plugin archive.' => 'Tidak ada berkas di dalam arsip plugin.',
+ 'Create tasks in bulk' => 'Buat tugas sekaligus',
+ 'Your Kanboard instance is not configured to install plugins from the user interface.' => 'Instalasi Kanboard Anda tidak diatur untuk memasang plugin dari antar muka pengguna.',
+ 'There is no plugin available.' => 'Tidak ada plugin yang tersedia.',
+ 'Install' => 'Pasang',
+ 'Update' => 'Perbarui',
+ 'Up to date' => 'Terbaru',
+ 'Not available' => 'Tidak tersedia',
+ 'Remove plugin' => 'Hapus plugin',
+ 'Do you really want to remove this plugin: "%s"?' => 'Anda yakin ingin menghapus plugin ini: "%s"?',
+ 'Uninstall' => 'Lepaskan',
+ 'Listing' => 'Daftar',
+ 'Metadata' => 'Metadata',
+ 'Manage projects' => 'Atur proyek',
+ 'Convert to task' => 'Ubah menjadi tugas',
+ 'Convert sub-task to task' => 'Ubah sub-tugas menjadi tugas',
+ 'Do you really want to convert this sub-task to a task?' => 'Anda yakin ingin mengubah sub-tugas ini menjadi tugas?',
+ 'My task title' => 'Judul tugas saya',
+ 'Enter one task by line.' => 'Masukkan satu tugas berdasarkan baris.',
+ 'Number of failed login:' => 'Jumlah login yang gagal:',
+ 'Account locked until:' => 'Akun terkunci hingga:',
+ 'Email settings' => 'Pengaturan email',
+ 'Email sender address' => 'Alamat pengirim email',
+ 'Email transport' => 'Transportasi email',
+ 'Webhook token' => 'Token Webhook',
+ 'Project tags management' => 'Manajemen tag proyek',
+ 'Tag created successfully.' => 'Tag berhasil dibuat.',
+ 'Unable to create this tag.' => 'Tidak dapat membuat tag ini.',
+ 'Tag updated successfully.' => 'Tag berhasil diperbarui',
+ 'Unable to update this tag.' => 'Tidak dapat memperbarui tag ini.',
+ 'Tag removed successfully.' => 'Tag berhasil dihapus.',
+ 'Unable to remove this tag.' => 'Tidak dapat menghapus tag ini.',
+ 'Global tags management' => 'Manajemen tag global',
+ 'Tags' => 'Tag',
+ 'Tags management' => 'Manajemen tag',
+ 'Add new tag' => 'Tambah tag baru',
+ 'Edit a tag' => 'Edit tag',
+ 'Project tags' => 'Tag proyek',
+ 'There is no specific tag for this project at the moment.' => 'Saat ini tidak ada tag yang spesifik pada proyek ini.',
+ 'Tag' => 'Tag',
+ 'Remove a tag' => 'Hapus tag',
+ 'Do you really want to remove this tag: "%s"?' => 'Anda yakin ingin menghapus tag ini: "%s"?',
+ 'Global tags' => 'Tag global',
+ 'There is no global tag at the moment.' => 'Saat ini tidak ada tag global.',
+ 'This field cannot be empty' => 'Bidang ini tidak boleh kosong',
+ 'Close a task when there is no activity in an specific column' => 'Tutup tugas saat tidak ada aktivitas di kolom tertentu',
+ '%s removed a subtask for the task #%d' => '%s menghapus sub-tugas untuk tugas #%d',
+ '%s removed a comment on the task #%d' => '%s menghapus komentar pada tugas #%d',
+ 'Comment removed on task #%d' => 'Komentar dihapus pada tugas #%d',
+ 'Subtask removed on task #%d' => 'Sub-tugas dihapus pada tugas #%d',
+ 'Hide tasks in this column in the dashboard' => 'Sembunyikan tugas-tugas di kolom ini di dasbor',
+ '%s removed a comment on the task %s' => '%s menghapus komentar pada tugas %s',
+ '%s removed a subtask for the task %s' => '%s menghapus sub-tugas untuk tugas %s',
+ 'Comment removed' => 'Komentar dihapus',
+ 'Subtask removed' => 'Sub-tugas dihapus',
+ '%s set a new internal link for the task #%d' => '%s memasang tautan internal baru untuk tugas #%d',
+ '%s removed an internal link for the task #%d' => '%s menghapus tautan internal untuk tugas #%d',
+ 'A new internal link for the task #%d have been defined' => 'Tautan internal baru untuk tugas #%d telah ditentukan',
+ 'Internal link removed for the task #%d' => 'Tautan internal untuk tugas #%d telah dihapus',
+ '%s set a new internal link for the task %s' => '%s memasang tautan internal baru untuk tugas %s',
+ '%s removed an internal link for the task %s' => '%s menghapus tautan internal untuk tugas %s',
+ 'Automatically set the due date on task creation' => 'Otomatis memasang tanggal kadaluarsa saat pembuatan tugas',
+ 'Move the task to another column when closed' => 'Pindahkan tugas ke kolom lain saat ditutup',
+ 'Move the task to another column when not moved during a given period' => 'Pindahkan tugas ke kolom lain saat tidak dipindahkan selama periode yang diberikan',
+ 'Dashboard for %s' => 'Dasbor untuk %s',
+ 'Tasks overview for %s' => 'Ringkasan tugas-tugas untuk %s',
+ 'Subtasks overview for %s' => 'Ringkasan sub-tugas untuk %s',
+ 'Projects overview for %s' => 'Ringkasan proyek untuk %s',
+ 'Activity stream for %s' => 'Arus aktivitas untuk %s',
+ 'Calendar for %s' => 'Kalender untuk %s',
+ 'Notifications for %s' => 'Notifikasi untuk %s',
+ 'Assign a color when the task is moved to a specific swimlane' => 'Berikan warna saat tugas dipindahkan ke swimlane tertentu',
+ 'Assign a priority when the task is moved to a specific swimlane' => 'Berikan prioritas saat tugas dipindahkan ke swimlane tertentu',
+ 'User unlocked successfully.' => 'Berhasil membuka blokir pengguna.',
+ 'Unable to unlock the user.' => 'Tidak bisa membuka blokir pengguna.',
+ 'Move a task to another swimlane' => 'Pindahkan tugas ke swimlane lain',
+ 'Creator Name' => 'Nama Pembuat',
+ 'Time spent and estimated' => 'Waktu yang dihabiskan dan diperkirakan',
+ 'Move position' => 'Pindahkan posisi',
+ 'Move task to another position on the board' => 'Pindahkan tugas ke posisi lain di dalam papan',
+ 'Insert before this task' => 'Masukkan sebelum tugas ini',
+ 'Insert after this task' => 'Masukkan setelah tugas ini',
+ 'Unlock this user' => 'Buka pengguna ini',
+ 'Custom Project Roles' => 'Peran Proyek Kustom',
+ 'Add a new custom role' => 'Tambahkan peran kustom baru',
+ 'Restrictions for the role "%s"' => 'Batasan untuk peran "%s"',
+ 'Add a new project restriction' => 'Tambahkan batasan proyek baru',
+ 'Add a new drag and drop restriction' => 'Tambahkan batasan drag and drop baru',
+ 'Add a new column restriction' => 'Tambahkan batasan kolom baru',
+ 'Edit this role' => 'Edit peran ini',
+ 'Remove this role' => 'Hapus peran ini',
+ 'There is no restriction for this role.' => 'Tidak ada batasan untuk peran ini.',
+ 'Only moving task between those columns is permitted' => 'Hanya diizinkan untuk memindahkan tugas diantara kolom-kolom tersebut',
+ 'Close a task in a specific column when not moved during a given period' => 'Tutup tugas pada kolom tertentu saat tidak dipindahkan pada periode yang diberikan',
+ 'Edit columns' => 'Edit kolom',
+ 'The column restriction has been created successfully.' => 'Batasan kolom berhasil dibuat.',
+ 'Unable to create this column restriction.' => 'Tidak dapat membuat batasan kolom ini.',
+ 'Column restriction removed successfully.' => 'Batasan kolom berhasil dihapus.',
+ 'Unable to remove this restriction.' => 'Gagal menghapus batasan ini.',
+ 'Your custom project role has been created successfully.' => 'Peran kustom proyek Anda berhasil dibuat.',
+ 'Unable to create custom project role.' => 'Tidak dapat membuat peran proyek kustom.',
+ 'Your custom project role has been updated successfully.' => 'Peran proyek kustom Anda berhasil diperbarui.',
+ 'Unable to update custom project role.' => 'Tidak dapat memperbarui peran kustom proyek',
+ 'Custom project role removed successfully.' => 'Peran kustom proyek berhasil dihapus.',
+ 'Unable to remove this project role.' => 'Tidak dapat menghapus peran proyek ini.',
+ 'The project restriction has been created successfully.' => 'Batasan proyek ini berhasil dibuat.',
+ 'Unable to create this project restriction.' => 'Tidak dapat membuat batasan proyek ini.',
+ 'Project restriction removed successfully.' => 'Batasan proyek berhasil dihapus.',
+ 'You cannot create tasks in this column.' => 'Anda tidak dapat membuat tugas di kolom ini.',
+ 'Task creation is permitted for this column' => 'Pembuatan tugas diizinkan untuk kolom ini',
+ 'Closing or opening a task is permitted for this column' => 'Penutupan atau pembukaan tugas diizinkan untuk kolom ini',
+ 'Task creation is blocked for this column' => 'Pembuatan tugas diblokir dari kolom ini',
+ 'Closing or opening a task is blocked for this column' => 'Penutupan atau pembukaan tugas diblokir di kolom ini',
+ 'Task creation is not permitted' => 'Oembuatan tugas tidak diizinkan',
+ 'Closing or opening a task is not permitted' => 'Penutupan atau pembukaan tugas tidak diizinkan',
+ 'New drag and drop restriction for the role "%s"' => 'Larangan drag and drop baru untuk peran "%s"',
+ 'People belonging to this role will be able to move tasks only between the source and the destination column.' => 'Orang-orang dengan peran ini dapat memindahkan tugas diantara kolom sumber dan destinasi.',
+ 'Remove a column restriction' => 'Hapus pembatasan kolom',
+ 'Do you really want to remove this column restriction: "%s" to "%s"?' => 'Anda yakin ingin menghapus pembatasan kolom ini: "%s" ke "%s"?',
+ 'New column restriction for the role "%s"' => 'Kolom pembatasan baru untuk peran "%s"',
+ 'Rule' => 'Aturan',
+ 'Do you really want to remove this column restriction?' => 'Anda yakin ingin menghapus pembatasan kolom ini?',
+ 'Custom roles' => 'Peran kustom',
+ 'New custom project role' => 'Peran kustom proyek baru',
+ 'Edit custom project role' => 'Edit peran kustom proyek',
+ 'Remove a custom role' => 'Hapus peran kustom',
+ 'Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.' => 'Anda yakin ingin menghapus peran kustom ini: "%s"? Semua orang yang memiliki peran ini akan berubah menjadi anggota proyek.',
+ 'There is no custom role for this project.' => 'Tidak ada peran kustom untuk proyek ini.',
+ 'New project restriction for the role "%s"' => 'Batasan proyek baru untuk peran "%s"',
+ 'Restriction' => 'Pembatasan',
+ 'Remove a project restriction' => 'Hapus batasan proyek',
+ 'Do you really want to remove this project restriction: "%s"?' => 'Anda yakin ingin menghapus pembatasan proyek ini: "%s"?',
+ 'Duplicate to multiple projects' => 'Duplikasikan ke banyak proyek',
+ 'This field is required' => 'Bidang ini dibutuhkan',
+ 'Moving a task is not permitted' => 'Memindahkan tugas tidak diizinkan',
+ 'This value must be in the range %d to %d' => 'Nilai ini harus berkisar antara %d hingga %d',
+ 'You are not allowed to move this task.' => 'Anda tidak diizinkan untuk memindahkan tugas ini.',
+ 'API User Access' => 'API Akses Pengguna',
+ 'Preview' => 'Pratinjau',
+ 'Write' => 'Tulis',
+ 'Write your text in Markdown' => 'Tuliskan teks Anda di Markdown',
+ 'New External Task: %s' => 'Tugas Eksternal Baru: %s',
+ 'No personal API access token registered.' => 'Tidak ada token akses API personal yang terdaftar.',
+ 'Your personal API access token is "%s"' => 'Token akses API personal Anda adalah "%s"',
+ 'Remove your token' => 'Hapus token Anda',
+ 'Generate a new token' => 'Generate token baru',
+ 'Showing %d-%d of %d' => 'Menampilkan %d-%d of %d',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 65defe86..f7c6c5ee 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d task sulla bacheca',
'%d tasks in total' => '%d task in totale',
'Unable to update this board.' => 'Impossibile aggiornare questa bacheca.',
- 'Edit board' => 'Modifica questa bacheca',
'Disable' => 'Disattiva',
'Enable' => 'Attiva',
'New project' => 'Nuovo progetto',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titolo',
'Assigned to %s' => 'Assegnato a %s',
'Remove a column' => 'Cancella questa colonna',
- 'Remove a column from a board' => 'Cancella una colonna da una bacheca',
'Unable to remove this column.' => 'Impossibile cancellare questa colonna.',
'Do you really want to remove this column: "%s"?' => 'Desideri davvero cancellare questa colonna: "%s" ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Questa azione cancellerà TUTTI I TASK legati a questa colonna!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Numero di task',
'User' => 'Utente',
'Comments' => 'Commenti',
- 'Leave a comment' => 'Lascia un commento',
'Comment is required' => 'Si richiede un commento',
- 'Leave a description' => 'Lascia una descrizione',
'Comment added successfully.' => 'Commenti aggiunti con successo.',
'Unable to create your comment.' => 'Impossibile creare questo commento.',
'Due Date' => 'Data di scadenza',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Cerca',
'Nothing found.' => 'Non si è trovato nulla.',
'Due date' => 'Data di scadenza',
- 'Others formats accepted: %s and %s' => 'Altri formati accettati: %s e %s',
'Description' => 'Descrizione',
'%d comments' => '%d commenti',
'%d comment' => '%d commento',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Creato da %s',
'Tasks Export' => 'Export dei task',
'Start Date' => 'Data di inizio',
- 'End Date' => 'Data di fine',
'Execute' => 'Esegui',
'Task Id' => 'Id del task',
'Creator' => 'Creatore',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remoto',
'Enabled' => 'Abilitato',
'Disabled' => 'Disabilitato',
- 'Username:' => 'Nome utente:',
- 'Name:' => 'Nome:',
+ 'Login:' => 'Nome utente:',
+ 'Full Name:' => 'Nome:',
// 'Email:' => '',
'Notifications:' => 'Notifiche:',
'Notifications' => 'Notifiche',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Etichette delle relazioni',
'Link modification' => 'Modifica relazione',
'Links' => 'Relazioni',
- 'Link settings' => 'Impostazioni relazioni',
'Opposite label' => 'Etichetta contraria',
'Remove a link' => 'Rimuovi una relazione',
- 'Task\'s links' => 'Relazioni del task',
'The labels must be different' => 'Le etichette devono essere diverse',
'There is no link.' => 'Nessuna relazione presente.',
'This label must be unique' => 'Questa etichetta deve essere univoca',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Vista compatta',
'Horizontal scrolling' => 'Scrolling orizzontale',
'Compact/wide view' => 'Vista compatta/estesa',
- 'No results match:' => 'Nessun risultato trovato:',
'Currency' => 'Valuta',
'Private project' => 'Progetto privato',
'AUD - Australian Dollar' => 'AUD - Dollari Australiani',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Yen Giapponesi',
'NZD - New Zealand Dollar' => 'NZD - Dollari della Nuova Zelanda',
'RSD - Serbian dinar' => 'RSD - Dinar Serbi',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dollari Americani',
'Destination column' => 'Colonna destinazione',
'Move the task to another column when assigned to a user' => 'Sposta il task in un\'altra colonna quando viene assegnato ad un utente',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Tassi di cambio',
'Rate' => 'Cambio',
'Change reference currency' => 'Cambia la valuta di riferimento',
- 'Add a new currency rate' => 'Aggiungi un nuovo tasso di cambio',
'Reference currency' => 'Valuta di riferimento',
'The currency rate have been added successfully.' => 'Il tasso di cambio è stato aggiunto con successo.',
'Unable to add this currency rate.' => 'Impossibile aggiungere questo tasso di cambio.',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
'Stop timer' => 'Ferma il timer',
'Start timer' => 'Avvia il timer',
- 'Add project member' => 'Aggiungi un membro di progetto',
'My activity stream' => 'Il mio flusso attività',
'My calendar' => 'Il mio calendario',
'Search tasks' => 'Ricerca task',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Utente remoto',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'La password degli utenti remoti (ad esempio: LDAP, account Google e Github) non è salvata nel database di Kanboard',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Se imposti l\'opzione "Disabilita il form di login", le credenzali inserite nella saranno ignorate.',
- 'New remote user' => 'Nuovo utente remoto',
- 'New local user' => 'Nuovo utente locale',
'Default task color' => 'Colore predefinito dei task',
'This feature does not work with all browsers.' => 'Questa feature non funziona con tutti i browser.',
'There is no destination project available.' => 'Non ci sono progetti disponbili come destinazione.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Proprietario',
'Unread notifications' => 'Notifiche non lette',
'Notification methods:' => 'Metodi di notifica',
- 'Import tasks from CSV file' => 'Importa task da file CSV',
'Unable to read your file' => 'Impossibile leggere il file',
'%d task(s) have been imported successfully.' => '%d task sono stati importati con successo.',
'Nothing have been imported!' => 'Non è stato importato nulla!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Proprietario del progetto: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'L\'identificativo del progetto è opzionale e deve essere alfanumerico, ad esempio: MIOPROGETTO.',
'Project owner' => 'Proprietario del progetto',
- 'Those dates are useful for the project Gantt chart.' => 'Le seguenti date sono utilizzate per i grafici Gantt di progetto.',
'Private projects do not have users and groups management.' => 'Per i progetti privati non è prevista la gestione di utenti e gruppi.',
'There is no project member.' => 'Non è impostato un membro del progetto.',
'Priority' => 'Priorità',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Iniziato:',
'Moved:' => 'Spostato:',
// 'Task #%d' => '',
- 'Date and time format' => 'Formato data e ora',
'Time format' => 'Formato ora',
'Start date: ' => 'Data di inizio: ',
'End date: ' => 'Data di fine: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Utente disabilitato con successo.',
'Unable to disable this user.' => 'Impossibile disabilitare questo utente.',
'All files have been uploaded successfully.' => 'Tutti i file sono stati caricati con successo.',
- 'View uploaded files' => 'Visualizza i file caricati',
'The maximum allowed file size is %sB.' => 'La dimensione massima consentita del file è %sB.',
- 'Choose files again' => 'Seleziona nuovamente i file',
'Drag and drop your files here' => 'Trascina i tuoi file qui',
'choose files' => 'seleziona i file',
'View profile' => 'Guarda il profilo',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => 'Indirizzo Email mittente',
'Email transport' => 'Trasporto Email',
'Webhook token' => 'Token Webhook',
- 'Imports' => 'Importa',
'Project tags management' => 'Gestione tag di progetto',
'Tag created successfully.' => 'Tag creato con successo.',
'Unable to create this tag.' => 'Impossibile creare questo tag.',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Flusso attività per %s',
'Calendar for %s' => 'Calendario per %s',
'Notifications for %s' => 'Notifiche per %s',
- 'Subtasks export' => 'Esporta subtasks',
- 'Tasks exportation' => 'Esportazione tasks',
'Assign a color when the task is moved to a specific swimlane' => 'Assegna un colore quando il task viene spostato su una specifica swimlane',
'Assign a priority when the task is moved to a specific swimlane' => 'Assegna una priorità quando il task viene spostato su una specifica swimlane',
'User unlocked successfully.' => 'Utente sbloccato con successo.',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index d0487fb7..e747c320 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d 個のタスク',
'%d tasks in total' => '合計 %d 個のタスク',
'Unable to update this board.' => 'ボードを更新できませんでした',
- 'Edit board' => 'ボードを変更する',
'Disable' => '無効にする',
'Enable' => '有効にする',
'New project' => 'プロジェクトを作る',
@@ -72,7 +71,6 @@ return array(
'Title' => 'タイトル',
'Assigned to %s' => '%sが担当',
'Remove a column' => 'カラムの削除',
- 'Remove a column from a board' => 'ボードからカラムの削除',
'Unable to remove this column.' => 'カラムを削除できませんでした。',
'Do you really want to remove this column: "%s"?' => 'カラム「%s」を削除しますか?',
'This action will REMOVE ALL TASKS associated to this column!' => 'この操作はこのカラムに割当てられた『全てのタスクを削除』します!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'タスク数',
'User' => 'ユーザ',
'Comments' => 'コメント',
- 'Leave a comment' => 'コメントを書く',
'Comment is required' => 'コメントを入力してください',
- 'Leave a description' => '説明を書く',
'Comment added successfully.' => 'コメントを追加しました。',
'Unable to create your comment.' => 'コメントの追加に失敗しました。',
'Due Date' => '期限',
@@ -224,7 +220,6 @@ return array(
'Search' => '検索',
'Nothing found.' => '結果なし。',
'Due date' => '期限',
- 'Others formats accepted: %s and %s' => '他の書式: %s または %s',
'Description' => '説明',
'%d comments' => '%d 個のコメント',
'%d comment' => '%d 個のコメント',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => '%s が作成',
'Tasks Export' => 'タスクの出力',
'Start Date' => '開始日',
- 'End Date' => '終了日',
'Execute' => '実行',
'Task Id' => 'タスク ID',
'Creator' => '作成者',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'リモート',
'Enabled' => '有効',
'Disabled' => '無効',
- 'Username:' => 'ユーザ名:',
- 'Name:' => '名前:',
+ 'Login:' => 'ユーザ名:',
+ 'Full Name:' => '名前:',
'Email:' => 'Email:',
'Notifications:' => '通知:',
'Notifications' => '通知',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'リンクラベル',
'Link modification' => 'リンクの変更',
'Links' => 'リンク',
- 'Link settings' => 'リンク設定',
'Opposite label' => '反対のラベル',
'Remove a link' => 'ラベルの削除',
- 'Task\'s links' => 'タスクのラベル',
'The labels must be different' => '異なるラベルを指定してください',
'There is no link.' => 'リンクがありません',
'This label must be unique' => 'ラベルはユニークである必要があります',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'コンパクトビュー',
'Horizontal scrolling' => '縦スクロール',
'Compact/wide view' => 'コンパクト/ワイドビュー',
- 'No results match:' => '結果が一致しませんでした',
'Currency' => '通貨',
'Private project' => 'プライベートプロジェクト',
'AUD - Australian Dollar' => 'AUD - 豪ドル',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - 日本円',
'NZD - New Zealand Dollar' => 'NZD - NZ ドル',
'RSD - Serbian dinar' => 'RSD - セルビアデナール',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - 米ドル',
'Destination column' => '移動先のカラム',
'Move the task to another column when assigned to a user' => 'ユーザの割り当てをしたらタスクを他のカラムに移動',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => '為替レート',
'Rate' => 'レート',
'Change reference currency' => '現在の基軸通貨',
- 'Add a new currency rate' => '新しい通貨レートを追加',
'Reference currency' => '基軸通貨',
// 'The currency rate have been added successfully.' => '',
'Unable to add this currency rate.' => 'この通貨レートを追加できません。',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
// 'Stop timer' => '',
// 'Start timer' => '',
- // 'Add project member' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
// 'Default task color' => '',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/ko_KR/translations.php b/app/Locale/ko_KR/translations.php
index a613b467..e1825ad7 100644
--- a/app/Locale/ko_KR/translations.php
+++ b/app/Locale/ko_KR/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d개의 할일',
'%d tasks in total' => '총 %d개의 할일',
'Unable to update this board.' => '보드를 갱신할 수 없었습니다',
- 'Edit board' => '보드를 변경하는 ',
'Disable' => '비활성화',
'Enable' => '유효하게 한다',
'New project' => '새 프로젝트',
@@ -72,7 +71,6 @@ return array(
'Title' => '제목',
'Assigned to %s' => '담당자 %s',
'Remove a column' => '컬럼 삭제',
- 'Remove a column from a board' => '보드에서 컬럼 삭제',
'Unable to remove this column.' => '(※)컬럼을 삭제할 수 없었습니다.',
'Do you really want to remove this column: "%s"?' => '컬럼을 삭제하시겠습니까: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => '이 조작은 이 컬럼에 할당된 『 모든 할일을 삭제 』합니다!',
@@ -160,9 +158,7 @@ return array(
'Task count' => '할일 수',
'User' => '사용자',
'Comments' => '댓글',
- 'Leave a comment' => '댓글 남기기',
'Comment is required' => '댓글을 입력하세요',
- 'Leave a description' => '설명을 입력하세요',
'Comment added successfully.' => '의견을 추가했습니다.',
'Unable to create your comment.' => '댓글의 추가에 실패했습니다.',
'Due Date' => '마감일',
@@ -224,7 +220,6 @@ return array(
'Search' => '검색',
'Nothing found.' => '결과가 없습니다',
'Due date' => '마감일',
- 'Others formats accepted: %s and %s' => ' 다른 서식: %s 또는 %s',
'Description' => '설명',
'%d comments' => '%d개의 댓글',
'%d comment' => '%d개의 댓글',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => '작성자 %s',
'Tasks Export' => '할일 내보내기',
'Start Date' => '시작일',
- 'End Date' => '종료일',
'Execute' => '실행',
'Task Id' => '할일 ID',
'Creator' => '작성자',
@@ -342,8 +336,8 @@ return array(
'Remote' => '원격',
'Enabled' => '활성화',
'Disabled' => '비활성화',
- 'Username:' => '사용자명',
- 'Name:' => '이름:',
+ 'Login:' => '사용자명',
+ 'Full Name:' => '이름:',
'Email:' => '이메일:',
'Notifications:' => '알림:',
'Notifications' => '알림',
@@ -516,10 +510,8 @@ return array(
'Link labels' => '링크 라벨',
'Link modification' => '링크의 변경',
'Links' => '링크',
- 'Link settings' => '링크 설정',
'Opposite label' => '반대의 라벨',
'Remove a link' => '라벨의 삭제',
- 'Task\'s links' => '할일의 라벨',
'The labels must be different' => ' 다른 라벨을 지정하세요',
'There is no link.' => '링크가 없습니다',
'This label must be unique' => '라벨은 독특할 필요가 있습니다',
@@ -552,7 +544,6 @@ return array(
'Compact view' => '컴팩트 뷰',
'Horizontal scrolling' => '세로 스크롤',
'Compact/wide view' => '컴팩트/와이드 뷰',
- 'No results match:' => '결과가 일치하지 않았습니다',
'Currency' => '통화',
'Private project' => '개인 프로젝트',
'AUD - Australian Dollar' => 'AUD - 호주 달러',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - 일본 엔',
'NZD - New Zealand Dollar' => 'NZD - 뉴질랜드 달러',
'RSD - Serbian dinar' => 'RSD - 세르비아 디나르',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - 미국 달러',
'Destination column' => '이동 후 컬럼',
'Move the task to another column when assigned to a user' => '사용자의 할당을 하면 할일을 다른 컬럼에 이동',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => '환율',
'Rate' => '레이트',
'Change reference currency' => '현재의 기축 통화',
- 'Add a new currency rate' => ' 새로운 통화 환율을 추가',
'Reference currency' => '기축 통화',
'The currency rate have been added successfully.' => '통화가 성공적으로 추가되었습니다',
'Unable to add this currency rate.' => '이 통화 환율을 추가할 수 없습니다.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30분',
'Stop timer' => '타이머 정지',
'Start timer' => '타이머 시작',
- 'Add project member' => '프로젝트 맴버 추가',
'My activity stream' => '내 활동기록',
'My calendar' => '내 캘린더',
'Search tasks' => '할일 찾기',
@@ -757,8 +747,6 @@ return array(
'Remote user' => '원격 담당자',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '예를 들어 LDAP, Google, Github 계정같은 원격 담당자의 비밀번호는 칸반보드 데이터베이스에 저장하지 않습니다',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '만약 "로그인 폼 거절"에 체크한다면, 로그인 폼에 접근할 자격이 무시됩니다',
- 'New remote user' => '새로운 원격유저',
- 'New local user' => '새로운 유저',
'Default task color' => '기본 할일 색',
'This feature does not work with all browsers.' => '이 기능은 일부 브라우저에서 작동하지 않습니다',
'There is no destination project available.' => '가능한 목적 프로젝트가 없습니다',
@@ -852,7 +840,6 @@ return array(
'Owner' => '소유자',
'Unread notifications' => '읽지않은 알림',
'Notification methods:' => '알림 방법',
- 'Import tasks from CSV file' => 'CSV 파일에서 할일 가져오기',
'Unable to read your file' => '파일을 읽을 수 없습니다',
'%d task(s) have been imported successfully.' => '%d 할일이 성공적으로 추가되었습니다',
'Nothing have been imported!' => '추가가 되지 않았습니다!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => '프로젝트 소유자:',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '프로젝트 구분자는 선택사항이며, 숫자와 문자만 가능합니다. 예: MYPROJECT.',
'Project owner' => '프로젝트 소유자',
- 'Those dates are useful for the project Gantt chart.' => '이 날짜는 프로젝트 간트 차트에 사용됩니다',
'Private projects do not have users and groups management.' => '비밀 프로젝트는 사용자나 관리 그룹이 소유하지 않습니다',
'There is no project member.' => '프로젝트 맴버가 없습니다',
'Priority' => '우선순위',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => '시작:',
'Moved:' => '이동:',
'Task #%d' => '할일 #%d',
- 'Date and time format' => '날짜와 시간 형식',
'Time format' => '시간 형식',
'Start date: ' => '시작일: ',
'End date: ' => '종료일: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => '사용자가 성공적으로 비활성화되었습니다',
'Unable to disable this user.' => '이 사용자를 비활성화할 수 없습니다.',
'All files have been uploaded successfully.' => '모든 파일이 성공적으로 업로드되었습니다',
- 'View uploaded files' => '업로드 파일 보기',
'The maximum allowed file size is %sB.' => '업로드 파일의 최대 크기는 %sB 입니다',
- 'Choose files again' => '파일 다시 선택',
'Drag and drop your files here' => '파일을 이곳으로 끌고오기',
'choose files' => '파일 선택',
'View profile' => '프로파일 보기',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => '이메일 보낸이 주소',
'Email transport' => '이메일 전송',
'Webhook token' => 'Webhook토큰',
- 'Imports' => '가져오기',
'Project tags management' => '프로젝트 태그 관리',
'Tag created successfully.' => '태그가 성공적으로 생성되었습니다.',
'Unable to create this tag.' => '태그를 생성할 수 없습니다.',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => '%s의 활동기록',
'Calendar for %s' => '%s의 달력',
'Notifications for %s' => '%s의 알림',
- 'Subtasks export' => '서브할일 내보내기',
- 'Tasks exportation' => '할일 내보내기',
'Assign a color when the task is moved to a specific swimlane' => '할일이 특정 스웜라인으로 옮겨질 때 색상 지정',
'Assign a priority when the task is moved to a specific swimlane' => '할일이 특정 스웜라인으로 옮겨질 때 우선순위 지정',
'User unlocked successfully.' => '사용자 잠금 성공',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/my_MY/translations.php b/app/Locale/my_MY/translations.php
index be335dec..641dfefa 100644
--- a/app/Locale/my_MY/translations.php
+++ b/app/Locale/my_MY/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tugasan di papan',
'%d tasks in total' => 'Sejumlah %d tugasan',
'Unable to update this board.' => 'Tidak berupaya mengemaskini papan ini',
- 'Edit board' => 'ubah papan',
'Disable' => 'Nyah-Upaya',
'Enable' => 'Aktifkan',
'New project' => 'Projek Baru',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Judul',
'Assigned to %s' => 'Ditugaskan ke %s',
'Remove a column' => 'Hapus kolom',
- 'Remove a column from a board' => 'Hapus kolom dari papan',
'Unable to remove this column.' => 'Tidak dapat menghapus kolom ini.',
'Do you really want to remove this column: "%s"?' => 'Apakah anda yakin akan menghapus kolom ini : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'tindakan ini akan MENGHAPUS SEMUA TUGAS yang terkait dengan kolom ini!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Jumlah tugas',
'User' => 'Pengguna',
'Comments' => 'Komentar',
- 'Leave a comment' => 'Tinggalkan komentar',
'Comment is required' => 'Komentar diperlukan',
- 'Leave a description' => 'Tinggalkan deskripsi',
'Comment added successfully.' => 'Komentar berhasil ditambahkan.',
'Unable to create your comment.' => 'Tidak dapat menambahkan komentar anda.',
'Due Date' => 'Batas Tanggal Terakhir',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Cari',
'Nothing found.' => 'Tidak ditemukan.',
'Due date' => 'Batas tanggal terakhir',
- 'Others formats accepted: %s and %s' => 'Format lain yang didukung : %s et %s',
'Description' => 'Deskripsi',
'%d comments' => '%d komentar',
'%d comment' => '%d komentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Dibuat oleh %s',
'Tasks Export' => 'Ekspor Tugas',
'Start Date' => 'Tanggal Mulai',
- 'End Date' => 'Tanggal Berakhir',
'Execute' => 'Eksekusi',
'Task Id' => 'Id Tugas',
'Creator' => 'Pembuat',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Jauh',
'Enabled' => 'Aktif',
'Disabled' => 'Tidak aktif',
- 'Username:' => 'Nama pengguna :',
- 'Name:' => 'Nama:',
+ 'Login:' => 'Nama pengguna :',
+ 'Full Name:' => 'Nama:',
'Email:' => 'Emel:',
'Notifications:' => 'Makluman:',
'Notifications' => 'Makluman',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Label Pautan',
'Link modification' => 'Modifikasi Pautan',
'Links' => 'Pautan',
- 'Link settings' => 'Pengaturan Pautan',
'Opposite label' => 'Label berlawanan',
'Remove a link' => 'Hapus Pautan',
- 'Task\'s links' => 'Pautan tugas',
'The labels must be different' => 'Label harus berbeda',
'There is no link.' => 'Tidak ada Pautan.',
'This label must be unique' => 'Label ini harus unik',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Tampilan kompak',
'Horizontal scrolling' => 'Horisontal bergulir',
'Compact/wide view' => 'Beralih antara tampilan kompak dan diperluas',
- 'No results match:' => 'Tidak ada hasil :',
'Currency' => 'Mata uang',
'Private project' => 'projek pribadi',
'AUD - Australian Dollar' => 'AUD - Dollar Australia',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Yen Jepang',
'NZD - New Zealand Dollar' => 'NZD - Dollar Selandia baru',
'RSD - Serbian dinar' => 'RSD - Dinar Serbia',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dollar Amerika',
'Destination column' => 'Kolom tujuan',
'Move the task to another column when assigned to a user' => 'Pindahkan tugas ke kolom lain ketika ditugaskan ke pengguna',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Nilai tukar mata uang',
'Rate' => 'Tarif',
'Change reference currency' => 'Mengubah referensi mata uang',
- 'Add a new currency rate' => 'Tambahkan nilai tukar mata uang baru',
'Reference currency' => 'Referensi mata uang',
'The currency rate have been added successfully.' => 'Nilai tukar mata uang berhasil ditambahkan.',
'Unable to add this currency rate.' => 'Tidak dapat menambahkan nilai tukar mata uang',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Hentikan timer',
'Start timer' => 'Mulai timer',
- 'Add project member' => 'Tambahkan anggota projek',
'My activity stream' => 'Aliran kegiatan saya',
'My calendar' => 'Kalender saya',
'Search tasks' => 'Cari tugas',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Pengguna jauh',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Pengguna jauh tidak menyimpan kata laluan mereka dalam basis data Kanboard, contoh: Akaun LDAP, Google dan Github.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Jika anda mencentang kotak "Larang formulir login", kredensial masuk ke formulis login akan diabaikan.',
- 'New remote user' => 'Pengguna baru jauh',
- 'New local user' => 'Pengguna baru lokal',
'Default task color' => 'Standar warna tugas',
'This feature does not work with all browsers.' => 'Ciri ini tidak dapat digunakan pada semua browsers',
'There is no destination project available.' => 'Tiada destinasi projek yang tersedia.',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/nb_NO/translations.php b/app/Locale/nb_NO/translations.php
index 6b49545c..da7e6508 100644
--- a/app/Locale/nb_NO/translations.php
+++ b/app/Locale/nb_NO/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d Oppgaver på hovedsiden',
'%d tasks in total' => '%d Oppgaver i alt',
'Unable to update this board.' => 'Ikke mulig at oppdatere hovedsiden',
- 'Edit board' => 'Endre prosjektsiden',
'Disable' => 'Deaktiver',
'Enable' => 'Aktiver',
'New project' => 'Nytt prosjekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Tittel',
'Assigned to %s' => 'Tildelt: %s',
'Remove a column' => 'Fjern en kolonne',
- 'Remove a column from a board' => 'Fjern en kolonne fra et board',
'Unable to remove this column.' => 'Ikke mulig ø fjerne denne kolonnen',
'Do you really want to remove this column: "%s"?' => 'Vil du fjerne denne kolonnen: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Denne handlingen vil SLETTE ALLE OPPGAVER tilknyttet denne kolonnen',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Antall oppgaver',
'User' => 'Bruker',
'Comments' => 'Kommentarer',
- 'Leave a comment' => 'Legg inn en kommentar',
'Comment is required' => 'Kommentar må legges inn',
- 'Leave a description' => 'Legg inn en beskrivelse...',
'Comment added successfully.' => 'Kommentaren er lagt til.',
'Unable to create your comment.' => 'Din kommentar kunne ikke opprettes.',
'Due Date' => 'Forfallsdato',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Søk',
'Nothing found.' => 'Intet funnet.',
'Due date' => 'Forfallsdato',
- 'Others formats accepted: %s and %s' => 'Andre formater: %s og %s',
'Description' => 'Beskrivelse',
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Opprettet av %s',
'Tasks Export' => 'Oppgave eksport',
'Start Date' => 'Start-dato',
- 'End Date' => 'Slutt-dato',
'Execute' => 'KKjør',
'Task Id' => 'Oppgave ID',
'Creator' => 'Laget av',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Fjernstyrt',
'Enabled' => 'Aktiv',
'Disabled' => 'Deaktivert',
- 'Username:' => 'Brukernavn',
- 'Name:' => 'Navn:',
+ 'Login:' => 'Brukernavn',
+ 'Full Name:' => 'Navn:',
'Email:' => 'Epost:',
'Notifications:' => 'Varslinger:',
'Notifications' => 'Varslinger',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Relasjonsetiketter',
'Link modification' => 'Relasjonsmodifisering',
'Links' => 'Relasjoner',
- 'Link settings' => 'Relasjonsinnstillinger',
'Opposite label' => 'Etikett for relatert motsatt oppgave',
'Remove a link' => 'Fjern relasjon',
- // 'Task\'s links' => '',
// 'The labels must be different' => '',
// 'There is no link.' => '',
// 'This label must be unique' => '',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompakt visning',
'Horizontal scrolling' => 'Bla horisontalt',
'Compact/wide view' => 'Kompakt/bred visning',
- 'No results match:' => 'Ingen resultater',
'Currency' => 'Valuta',
'Private project' => 'Privat prosjekt',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
// 'JPY - Japanese Yen' => '',
// 'NZD - New Zealand Dollar' => '',
// 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
// 'USD - US Dollar' => '',
'Destination column' => 'Ny kolonne',
'Move the task to another column when assigned to a user' => 'Flytt oppgaven til en annen kolonne når den er tildelt en bruker',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Valutakurser',
// 'Rate' => '',
// 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
'Stop timer' => 'Stopp timer',
'Start timer' => 'Start timer',
- 'Add project member' => 'Legg til prosjektmedlem',
'My activity stream' => 'Aktivitetslogg',
'My calendar' => 'Min kalender',
'Search tasks' => 'Søk oppgave',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- 'New remote user' => 'Ny eksternbruker',
- 'New local user' => 'Ny internbruker',
'Default task color' => 'Standard oppgavefarge',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 44434a4e..140c0406 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d taken op het bord',
'%d tasks in total' => '%d taken in totaal',
'Unable to update this board.' => 'Update van dit bord niet mogelijk.',
- 'Edit board' => 'Bord bewerken',
'Disable' => 'Deactiveren',
'Enable' => 'Activeren',
'New project' => 'Nieuw project',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titel',
'Assigned to %s' => 'Toegewezen aan %s',
'Remove a column' => 'Kolom verwijderen',
- 'Remove a column from a board' => 'Kolom verwijderen van het bord',
'Unable to remove this column.' => 'Verwijderen van deze kolom niet mogelijk.',
'Do you really want to remove this column: "%s"?' => 'Weet u zeker dat u deze kolom wil verwijderen : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Deze actie zal ALLE TAKEN VERWIJDEREN die zijn geassocieerd met deze kolom!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Aantal taken',
'User' => 'Gebruiker',
'Comments' => 'Commentaar',
- 'Leave a comment' => 'Schrijf een commentaar',
'Comment is required' => 'Commentaar is verplicht',
- 'Leave a description' => 'Schrijf een omschrijving',
'Comment added successfully.' => 'Commentaar succesvol toegevoegd.',
'Unable to create your comment.' => 'Commentaar toevoegen niet gelukt.',
'Due Date' => 'Vervaldag',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Zoek',
'Nothing found.' => 'Niets gevonden.',
'Due date' => 'Vervaldatum',
- 'Others formats accepted: %s and %s' => 'Andere toegestane formaten : %s en %s',
'Description' => 'Omschrijving',
'%d comments' => '%d commentaren',
'%d comment' => '%d commentaar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Aangemaakt door %s',
'Tasks Export' => 'Taken exporteren',
'Start Date' => 'Startdatum',
- 'End Date' => 'Einddatum',
'Execute' => 'Uitvoeren',
'Task Id' => 'Taak Id',
'Creator' => 'Aangemaakt door',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remote',
'Enabled' => 'Actief',
'Disabled' => 'Inactief',
- 'Username:' => 'Gebruikersnaam :',
- 'Name:' => 'Naam :',
+ 'Login:' => 'Gebruikersnaam :',
+ 'Full Name:' => 'Naam :',
'Email:' => 'Email :',
'Notifications:' => 'Notificaties :',
'Notifications' => 'Notificaties',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Link labels',
'Link modification' => 'Link aanpassing',
'Links' => 'Links',
- 'Link settings' => 'Link instellingen',
'Opposite label' => 'Tegenovergesteld label',
'Remove a link' => 'Link verwijderen',
- 'Task\'s links' => 'Links van taak',
'The labels must be different' => 'De labels moeten verschillend zijn',
'There is no link.' => 'Er is geen link.',
'This label must be unique' => 'Dit label moet uniek zijn',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Compacte weergave',
// 'Horizontal scrolling' => '',
'Compact/wide view' => 'Compacte/breedbeeld-weergave',
- 'No results match:' => 'Geen resultaten voor',
'Currency' => 'Valuta',
'Private project' => 'Privé project',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
// 'JPY - Japanese Yen' => '',
// 'NZD - New Zealand Dollar' => '',
// 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
// 'USD - US Dollar' => '',
'Destination column' => 'Doel kolom',
// 'Move the task to another column when assigned to a user' => '',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Wisselkoersen',
'Rate' => 'Koers',
// 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Stop timer',
'Start timer' => 'Start timer',
- 'Add project member' => 'Voeg projectlid toe',
'My activity stream' => 'Mijn activiteiten',
'My calendar' => 'Mijn kalender',
'Search tasks' => 'Zoek taken',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
// 'Default task color' => '',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 51c0fef8..16988195 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d zadań na tablicy',
'%d tasks in total' => '%d wszystkich zadań',
'Unable to update this board.' => 'Nie można zaktualizować tablicy.',
- 'Edit board' => 'Edytuj tablicę',
'Disable' => 'Wyłącz',
'Enable' => 'Włącz',
'New project' => 'Nowy projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Nazwa',
'Assigned to %s' => 'Przypisane do %s',
'Remove a column' => 'Usuń kolumnę',
- 'Remove a column from a board' => 'Usuń kolumnę z tablicy',
'Unable to remove this column.' => 'Nie udało się usunąć kolumny.',
'Do you really want to remove this column: "%s"?' => 'Na pewno chcesz usunąć kolumnę: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Wszystkie zadania w kolumnie zostaną usunięte!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Liczba zadań',
'User' => 'Użytkownik',
'Comments' => 'Komentarze',
- 'Leave a comment' => 'Wstaw komentarz',
'Comment is required' => 'Komentarz jest wymagany',
- 'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentarz dodany',
'Unable to create your comment.' => 'Nie udało się dodać komentarza',
'Due Date' => 'Termin',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Szukaj',
'Nothing found.' => 'Nic nie znaleziono',
'Due date' => 'Termin',
- 'Others formats accepted: %s and %s' => 'Inne akceptowane formaty: %s and %s',
'Description' => 'Opis',
'%d comments' => '%d Komentarzy',
'%d comment' => '%d Komentarz',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Utworzone przez %s',
'Tasks Export' => 'Eksport zadań',
'Start Date' => 'Data początkowa',
- 'End Date' => 'Data Końcowa',
'Execute' => 'Wykonaj',
'Task Id' => 'Identyfikator Zadania',
'Creator' => 'Autor',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Zdalne',
'Enabled' => 'Odblokowane',
'Disabled' => 'Zablokowane',
- 'Username:' => 'Nazwa Użytkownika (login):',
- 'Name:' => 'Imię i Nazwisko',
+ 'Login:' => 'Nazwa Użytkownika (login):',
+ 'Full Name:' => 'Imię i Nazwisko',
'Email:' => 'Email: ',
'Notifications:' => 'Powiadomienia: ',
'Notifications' => 'Powiadomienia',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Etykiety linku',
'Link modification' => 'Modyfikuj link',
'Links' => 'Linki',
- 'Link settings' => 'Ustawienia linku',
'Opposite label' => 'Etykieta odwrotna',
'Remove a link' => 'Usuń link',
- 'Task\'s links' => 'Linki zadania',
'The labels must be different' => 'Etykiety muszą być różne',
'There is no link.' => 'Brak linku',
'This label must be unique' => 'Etykieta musi być unikatowa',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Widok kompaktowy',
'Horizontal scrolling' => 'Przewijanie poziome',
'Compact/wide view' => 'Pełny/Kompaktowy widok',
- 'No results match:' => 'Brak wyników:',
'Currency' => 'Waluta',
'Private project' => 'Projekt prywatny',
'AUD - Australian Dollar' => 'AUD - Dolar australijski',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Jen japoński',
'NZD - New Zealand Dollar' => 'NZD - Dolar nowozelandzki',
'RSD - Serbian dinar' => 'RSD - Dinar serbski',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dolar amerykański',
'Destination column' => 'Kolumna docelowa',
'Move the task to another column when assigned to a user' => 'Przenieś zadanie do innej kolumny gdy zostanie przypisane do osoby',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Kursy walut',
'Rate' => 'Kurs',
'Change reference currency' => 'Zmień walutę referencyjną',
- 'Add a new currency rate' => 'Dodaj nowy kurs waluty',
'Reference currency' => 'Waluta referencyjna',
'The currency rate have been added successfully.' => 'Dodano kurs waluty',
'Unable to add this currency rate.' => 'Nie można dodać kursu waluty',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
'Stop timer' => 'Zatrzymaj pomiar czasu',
'Start timer' => 'Uruchom pomiar czasu',
- 'Add project member' => 'Dodaj uczestnika projektu',
'My activity stream' => 'Moja aktywność',
'My calendar' => 'Mój kalendarz',
'Search tasks' => 'Szukaj zadań',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Zdalny użytkownik',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Zdalni użykownicy nie przechowują swojego hasła w bazie danych Kanboard, przykłady: konta LDAP, Google and Github.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Jeśli zaznaczysz "Zablokuj możliwość logowania", dane podane przy logowaniu zostaną zignorowane.',
- 'New remote user' => 'Nowy użytkownik zdalny',
- 'New local user' => 'Nowy użytkownik lokalny',
'Default task color' => 'Domyślny kolor zadań',
'This feature does not work with all browsers.' => 'Ta funkcja może nie działać z każdą przeglądarką.',
'There is no destination project available.' => 'Żaden docelowy projekt nie jest aktualnie dostępny.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Właściciel',
'Unread notifications' => 'Nieprzeczytane powiadomienia',
'Notification methods:' => 'Metody powiadomień:',
- 'Import tasks from CSV file' => 'Importuj zadania z pliku CSV',
'Unable to read your file' => 'Nie można odczytać pliku',
'%d task(s) have been imported successfully.' => '%d zadań zostało zaimportowanych.',
'Nothing have been imported!' => 'Nic nie zostało zaimportowane!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Właściciel projektu: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Identyfikator projektu jest opcjonalny i musi być alfanumeryczny, przykład: MYPROJECT.',
'Project owner' => 'Właściciel projektu',
- 'Those dates are useful for the project Gantt chart.' => 'Daty te są przydatne dla wykresu Gantta.',
'Private projects do not have users and groups management.' => 'Projekty prywatne nie wspierają obsługi użytkowników i grup.',
'There is no project member.' => 'Projekt nie ma uczestników.',
'Priority' => 'Priorytet',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Rozpoczęte:',
'Moved:' => 'Przeniesione:',
'Task #%d' => 'Zadanie #%d',
- 'Date and time format' => 'Format daty oraz czasu',
'Time format' => 'Format czasu',
'Start date: ' => 'Data rozpoczęcia: ',
'End date: ' => 'Data zakończenia: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Użytkownik został wyłączony.',
'Unable to disable this user.' => 'Nie można wyłączyć użytkownika.',
'All files have been uploaded successfully.' => 'Wszystkie pliki zostały pomyślnie przesłane.',
- 'View uploaded files' => 'Zobacz przesłane pliki',
'The maximum allowed file size is %sB.' => 'Maksymalny rozmiar pliku to %sB.',
- 'Choose files again' => 'Wybierz jeszcze raz pliki',
'Drag and drop your files here' => 'Przeciągnij i upuść pliki tutaj',
'choose files' => 'wybierz pliki',
'View profile' => 'Zobacz profil',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index c0fa2387..ef8fc4c9 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tarefas no board',
'%d tasks in total' => '%d tarefas no total',
'Unable to update this board.' => 'Não foi possível atualizar este board.',
- 'Edit board' => 'Editar board',
'Disable' => 'Desativar',
'Enable' => 'Ativar',
'New project' => 'Novo projeto',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Título',
'Assigned to %s' => 'Designado para %s',
'Remove a column' => 'Remover uma coluna',
- 'Remove a column from a board' => 'Remover uma coluna do board',
'Unable to remove this column.' => 'Não foi possível remover esta coluna.',
'Do you really want to remove this column: "%s"?' => 'Você realmente deseja remover esta coluna: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Esta ação irá REMOVER TODAS AS TAREFAS associadas a esta coluna!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Número de tarefas',
'User' => 'Usuário',
'Comments' => 'Comentários',
- 'Leave a comment' => 'Deixe um comentário',
'Comment is required' => 'Comentário é obrigatório',
- 'Leave a description' => 'Deixe uma descrição',
'Comment added successfully.' => 'Comentário adicionado com sucesso.',
'Unable to create your comment.' => 'Não é possível criar o seu comentário.',
'Due Date' => 'Data fim estimada',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Pesquisar',
'Nothing found.' => 'Nada foi encontrado.',
'Due date' => 'Data fim estimada',
- 'Others formats accepted: %s and %s' => 'Outros formatos permitidos: %s e %s',
'Description' => 'Descrição',
'%d comments' => '%d comentários',
'%d comment' => '%d comentário',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Criado por %s',
'Tasks Export' => 'Exportar Tarefas',
'Start Date' => 'Data inicial',
- 'End Date' => 'Data final',
'Execute' => 'Executar',
'Task Id' => 'ID da Tarefa',
'Creator' => 'Criado por',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remoto',
'Enabled' => 'Habilitado',
'Disabled' => 'Desabilitado',
- 'Username:' => 'Usuário:',
- 'Name:' => 'Nome:',
+ 'Login:' => 'Usuário:',
+ 'Full Name:' => 'Nome:',
'Email:' => 'E-mail:',
'Notifications:' => 'Notificações:',
'Notifications' => 'Notificações',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Etiquetas das associações',
'Link modification' => 'Modificação de uma associação',
'Links' => 'Associações',
- 'Link settings' => 'Configuração das associações',
'Opposite label' => 'Nome da etiqueta oposta',
'Remove a link' => 'Remover uma associação',
- 'Task\'s links' => 'Associações das tarefas',
'The labels must be different' => 'As etiquetas devem ser diferentes',
'There is no link.' => 'Não há nenhuma associação.',
'This label must be unique' => 'Esta etiqueta deve ser unica',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Vista reduzida',
'Horizontal scrolling' => 'Rolagem horizontal',
'Compact/wide view' => 'Alternar entre a vista compacta e ampliada',
- 'No results match:' => 'Nenhum resultado:',
'Currency' => 'Moeda',
'Private project' => 'Projeto privado',
'AUD - Australian Dollar' => 'AUD - Dólar australiano',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Iene japonês',
'NZD - New Zealand Dollar' => 'NZD - Dólar Neozelandês',
'RSD - Serbian dinar' => 'RSD - Dinar sérvio',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dólar norte-americano',
'Destination column' => 'Coluna de destino',
'Move the task to another column when assigned to a user' => 'Mover a tarefa para uma outra coluna quando esta está atribuída a um usuário',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Taxas de câmbio das moedas estrangeiras',
'Rate' => 'Taxa',
'Change reference currency' => 'Mudar a moeda de referência',
- 'Add a new currency rate' => 'Adicionar uma nova taxa para uma moeda',
'Reference currency' => 'Moeda de Referência',
'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.',
'Unable to add this currency rate.' => 'Impossível de adicionar essa taxa de câmbio.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Stop timer',
'Start timer' => 'Start timer',
- 'Add project member' => 'Adicionar membro ao projeto',
'My activity stream' => 'Meu feed de atividades',
'My calendar' => 'Minha agenda',
'Search tasks' => 'Pesquisar tarefas',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Usuário remoto',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Os usuários remotos não conservam as suas senhas no banco de dados Kanboard, exemplos: contas LDAP, Github ou Google.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Se você marcar "Interdir o formulário de autenticação", os identificadores entrados no formulário de login serão ignorado.',
- 'New remote user' => 'Criar um usuário remoto',
- 'New local user' => 'Criar um usuário local',
'Default task color' => 'Cor padrão para as tarefas',
'This feature does not work with all browsers.' => 'Esta funcionalidade não é compatível com todos os navegadores.',
'There is no destination project available.' => 'Não há nenhum projeto de destino disponível.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Líder',
'Unread notifications' => 'Notificações não lidas',
'Notification methods:' => 'Métodos de notificação:',
- 'Import tasks from CSV file' => 'Importar tarefas a partir de arquivo CSV',
'Unable to read your file' => 'Não foi possível ler seu arquivo',
'%d task(s) have been imported successfully.' => '%d tarefa(s) importada(s) com sucesso.',
'Nothing have been imported!' => 'Nada foi importado!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Líder do projeto: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'O identificador do projeto é opcional e deve ser alfanumérico, por exemplo MEUPROJETO.',
'Project owner' => 'Líder do projeto',
- 'Those dates are useful for the project Gantt chart.' => 'Estas datas são úteis para o gráfico de Gantt dos projetos.',
'Private projects do not have users and groups management.' => 'Projetos privados não têm gestão de usuários e grupos.',
'There is no project member.' => 'Não há nenhum membro do projeto.',
'Priority' => 'Prioridade',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Começado:',
'Moved:' => 'Movido:',
'Task #%d' => 'Tarefa #%d',
- 'Date and time format' => 'Formato da hora e da data',
'Time format' => 'Formato da hora',
'Start date: ' => 'Data de início: ',
'End date: ' => 'Data final: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Usuário desactivado com sucesso.',
'Unable to disable this user.' => 'Impossível de desativar esse usuário.',
'All files have been uploaded successfully.' => 'Todos os arquivos foram enviados com sucesso.',
- 'View uploaded files' => 'Ver os arquivos enviados',
'The maximum allowed file size is %sB.' => 'O tamanho máximo dos arquivos é %sB.',
- 'Choose files again' => 'Selecionar novamente arquivos',
'Drag and drop your files here' => 'Arraste e solte os arquivos aqui',
'choose files' => 'selecione os arquivos',
'View profile' => 'Ver o perfil',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => 'Endereço de envio de Email',
'Email transport' => 'Transportador de Email',
'Webhook token' => 'Token do Webhook',
- 'Imports' => 'Importados',
'Project tags management' => 'Gestão de etiquetas do Projeto',
'Tag created successfully.' => 'Etiqueta criada com sucesso.',
'Unable to create this tag.' => 'Não foi possivel criar esta etiqueta.',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Fluxo de atividade de %s',
'Calendar for %s' => 'Calendário de %s',
'Notifications for %s' => 'Notificações de %s',
- 'Subtasks export' => 'Exportar sub-tarefas',
- 'Tasks exportation' => 'Exportação de tarefas',
'Assign a color when the task is moved to a specific swimlane' => 'Atribuir uma cor quando a tarefa é movida para uma swimlane especifica',
'Assign a priority when the task is moved to a specific swimlane' => 'Atribuir uma prioridade quando a tarefa é movida para uma swimlane especifica',
'User unlocked successfully.' => 'Usuário desbloqueado com sucesso.',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/pt_PT/translations.php b/app/Locale/pt_PT/translations.php
index 3a229570..c4e14ed3 100644
--- a/app/Locale/pt_PT/translations.php
+++ b/app/Locale/pt_PT/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d tarefas no quadro',
'%d tasks in total' => '%d tarefas no total',
'Unable to update this board.' => 'Não foi possível actualizar este quadro.',
- 'Edit board' => 'Editar quadro',
'Disable' => 'Desactivar',
'Enable' => 'Activar',
'New project' => 'Novo projeto',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Título',
'Assigned to %s' => 'Designado para %s',
'Remove a column' => 'Remover uma coluna',
- 'Remove a column from a board' => 'Remover uma coluna do quadro',
'Unable to remove this column.' => 'Não foi possível remover esta coluna.',
'Do you really want to remove this column: "%s"?' => 'Tem a certeza que quer remover esta coluna: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Esta acção irá REMOVER TODAS AS TAREFAS associadas a esta coluna!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Número de tarefas',
'User' => 'Utilizador',
'Comments' => 'Comentários',
- 'Leave a comment' => 'Deixe um comentário',
'Comment is required' => 'Comentário é obrigatório',
- 'Leave a description' => 'Deixe uma descrição',
'Comment added successfully.' => 'Comentário adicionado com sucesso.',
'Unable to create your comment.' => 'Não é possível criar o seu comentário.',
'Due Date' => 'Data de vencimento',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Pesquisar',
'Nothing found.' => 'Nada encontrado.',
'Due date' => 'Data de vencimento',
- 'Others formats accepted: %s and %s' => 'Outros formatos permitidos: %s e %s',
'Description' => 'Descrição',
'%d comments' => '%d comentários',
'%d comment' => '%d comentário',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Criado por %s',
'Tasks Export' => 'Exportar Tarefas',
'Start Date' => 'Data inicial',
- 'End Date' => 'Data final',
'Execute' => 'Executar',
'Task Id' => 'ID da Tarefa',
'Creator' => 'Criado por',
@@ -307,7 +301,7 @@ return array(
'Clone' => 'Clonar',
'Project cloned successfully.' => 'Projeto clonado com sucesso.',
'Unable to clone this project.' => 'Não foi possível clonar este projeto.',
- 'Enable email notifications' => 'Activar notificações por email',
+ 'Enable email notifications' => 'Activar notificações por e-mail',
'Task position:' => 'Posição da tarefa:',
'The task #%d have been opened.' => 'A tarefa #%d foi aberta.',
'The task #%d have been closed.' => 'A tarefa #%d foi finalizada.',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Remoto',
'Enabled' => 'Activado',
'Disabled' => 'Desactivado',
- 'Username:' => 'Utilizador:',
- 'Name:' => 'Nome:',
+ 'Login:' => 'Utilizador:',
+ 'Full Name:' => 'Nome:',
'Email:' => 'E-mail:',
'Notifications:' => 'Notificações:',
'Notifications' => 'Notificações',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Etiquetas das associações',
'Link modification' => 'Modificação de uma associação',
'Links' => 'Associações',
- 'Link settings' => 'Configuração das associações',
'Opposite label' => 'Nome da etiqueta oposta',
'Remove a link' => 'Remover uma associação',
- 'Task\'s links' => 'Associações das tarefas',
'The labels must be different' => 'As etiquetas devem ser diferentes',
'There is no link.' => 'Não há nenhuma associação.',
'This label must be unique' => 'Esta etiqueta deve ser unica',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Vista reduzida',
'Horizontal scrolling' => 'Deslocamento horizontal',
'Compact/wide view' => 'Alternar entre a vista compacta e ampliada',
- 'No results match:' => 'Nenhum resultado:',
'Currency' => 'Moeda',
'Private project' => 'Projeto privado',
'AUD - Australian Dollar' => 'AUD - Dólar australiano',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Iene japonês',
'NZD - New Zealand Dollar' => 'NZD - Dólar Neozelandês',
'RSD - Serbian dinar' => 'RSD - Dinar sérvio',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Dólar norte-americano',
'Destination column' => 'Coluna de destino',
'Move the task to another column when assigned to a user' => 'Mover a tarefa para uma outra coluna quando esta está atribuída a um utilizador',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Taxas de câmbio das moedas estrangeiras',
'Rate' => 'Taxa',
'Change reference currency' => 'Mudar a moeda de referência',
- 'Add a new currency rate' => 'Adicionar uma nova taxa para uma moeda',
'Reference currency' => 'Moeda de Referência',
'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.',
'Unable to add this currency rate.' => 'Impossível adicionar essa taxa de câmbio.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Parar temporizador',
'Start timer' => 'Iniciar temporizador',
- 'Add project member' => 'Adicionar um membro ao projeto',
'My activity stream' => 'O meu feed de actividade',
'My calendar' => 'A minha agenda',
'Search tasks' => 'Pesquisar tarefas',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Utilizador remoto',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Utilizadores remotos não guardam a password na base de dados do Kanboard, por exemplo: LDAP, contas do Google e Github.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Se activar a opção "Desactivar login", as credenciais digitadas no login serão ignoradas.',
- 'New remote user' => 'Novo utilizador remoto',
- 'New local user' => 'Novo utilizador local',
'Default task color' => 'Cor de tarefa por defeito',
'This feature does not work with all browsers.' => 'Esta funcionalidade não funciona em todos os browsers',
'There is no destination project available.' => 'Não há projeto de destino disponivel',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Dono',
'Unread notifications' => 'Notificações por ler',
'Notification methods:' => 'Métodos de notificação:',
- 'Import tasks from CSV file' => 'Importar tarefas de um ficheiro CSV',
'Unable to read your file' => 'Não foi possivel ler o ficheiro',
'%d task(s) have been imported successfully.' => '%d tarefa(s) importada(s) com successo.',
'Nothing have been imported!' => 'Nada foi importado',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Dono do projeto: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'O identificador do projeto é opcional e tem de ser alfa-numerico, exemplo: MEUPROJETO.',
'Project owner' => 'Dono do projeto',
- 'Those dates are useful for the project Gantt chart.' => 'Estas datas são uteis para o gráfico de Grantt do projeto.',
'Private projects do not have users and groups management.' => 'Projetos privados não têm gestão de utilizadores nem de grupos.',
'There is no project member.' => 'Não existe membro do projeto.',
'Priority' => 'Prioridade',
@@ -993,7 +979,7 @@ return array(
'If you put zero to the low and high priority, this feature will be disabled.' => 'Se colocar zero na prioridade baixa ou alta, essa funcionalidade será desactivada.',
'Close a task when there is no activity' => 'Fechar tarefa quando não há actividade',
'Duration in days' => 'Duração em dias',
- 'Send email when there is no activity on a task' => 'Enviar email quando não há actividade numa tarefa',
+ 'Send email when there is no activity on a task' => 'Enviar e-mail quando não há actividade numa tarefa',
'Unable to fetch link information.' => 'Impossivel obter informação da ligação.',
'Daily background job for tasks' => 'Trabalho diário em segundo plano para tarefas',
'Auto' => 'Auto',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Iniciado:',
'Moved:' => 'Movido:',
'Task #%d' => 'Tarefa #%d',
- 'Date and time format' => 'Formato tempo e data',
'Time format' => 'Formato tempo',
'Start date: ' => 'Data inicio: ',
'End date: ' => 'Data final: ',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Utilizador desactivado com sucesso.',
'Unable to disable this user.' => 'Não foi possivel desactivar este utilizador.',
'All files have been uploaded successfully.' => 'Todos os ficheiros foram enviados com sucesso.',
- 'View uploaded files' => 'Ver ficheiros enviados',
'The maximum allowed file size is %sB.' => 'O tamanho máximo permitido é %sB.',
- 'Choose files again' => 'Escolher ficheiros novamente',
'Drag and drop your files here' => 'Arraste e deixe os ficheiros para aqui',
'choose files' => 'escolher ficheiros',
'View profile' => 'Ver perfil',
@@ -1159,11 +1142,10 @@ return array(
'Enter one task by line.' => 'Escreva uma tarefa por linha.',
'Number of failed login:' => 'Número de logins falhados:',
'Account locked until:' => 'Conta bloqueada até:',
- 'Email settings' => 'Definições de Email',
- 'Email sender address' => 'Endereço de envido de Email',
- 'Email transport' => 'Transportador de Email',
+ 'Email settings' => 'Definições de E-mail',
+ 'Email sender address' => 'Endereço de envido de E-mail',
+ 'Email transport' => 'Transportador de E-mail',
'Webhook token' => 'Token do Webhook',
- 'Imports' => 'Importados',
'Project tags management' => 'Gestão de etiquetas do Projeto',
'Tag created successfully.' => 'Etiqueta criada com sucesso.',
'Unable to create this tag.' => 'Não foi possivel criar esta etiqueta.',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Fluxo de actividade de %s',
'Calendar for %s' => 'Calendário de %s',
'Notifications for %s' => 'Notificações de %s',
- 'Subtasks export' => 'Exportar sub-tarefas',
- 'Tasks exportation' => 'Exportação de tarefas',
'Assign a color when the task is moved to a specific swimlane' => 'Atribuir uma cor quando a tarefa é movida para uma swimlane especifica',
'Assign a priority when the task is moved to a specific swimlane' => 'Atribuir uma prioridade quando a tarefa é movida para uma swimlane especifica',
'User unlocked successfully.' => 'Utilizador desbloqueado com sucesso.',
@@ -1287,4 +1267,44 @@ return array(
'Your personal API access token is "%s"' => 'O seu token de acesso pessoal ao API é "%s"',
'Remove your token' => 'Remover o seu token',
'Generate a new token' => 'Gerar um novo token',
+ 'Showing %d-%d of %d' => 'A mostrar %d-%d de %d',
+ 'Outgoing Emails' => 'E-mails de saída',
+ 'Add or change currency rate' => 'Adicionar ou alterar taxa da moeda',
+ 'Reference currency: %s' => 'Moeda de referência: %s',
+ 'Add custom filters' => 'Adicionar filtros personalizados',
+ 'Export' => 'Exportar',
+ 'Add link label' => 'Adicionar etiqueta de associação',
+ 'Incompatible Plugins' => 'Plugins incompatíveis',
+ 'Compatibility' => 'Compatibilidade',
+ 'Permissions and ownership' => 'Permissões e propriedade',
+ 'Priorities' => 'Prioridades',
+ 'Close this window' => 'Feche esta janela',
+ 'Unable to upload this file.' => 'Não foi possível enviar este ficheiro.',
+ 'Import tasks' => 'Importar tarefas',
+ 'Choose a project' => 'Escolha um projeto',
+ 'Profile' => 'Perfil',
+ 'Application role' => 'Função na Aplicação',
+ '%d invitations were sent.' => '%d convites foram enviados.',
+ '%d invitation was sent.' => '%d convite foi enviado.',
+ 'Unable to create this user.' => 'Não foi possível criar este utilizador.',
+ 'Kanboard Invitation' => 'Convite de Kanboard',
+ 'Visible on dashboard' => 'Visível no painel',
+ 'Created at:' => 'Criado a:',
+ 'Updated at:' => 'Atualizado a:',
+ 'There is no custom filter.' => 'Não existe nenhum filtro personalizado.',
+ 'New User' => 'Novo Utilizador',
+ 'Authentication' => 'Autenticação',
+ 'If checked, this user will use a third-party system for authentication.' => 'Se selecionado, este utilizador irá utilizar um serviços de terceiros para autenticação.',
+ 'The password is necessary only for local users.' => 'A password só é necessária para utilizadores locais.',
+ 'You have been invited to register on Kanboard.' => 'Foi convidado para se registrar no Kanboard.',
+ 'Click here to join your team' => 'Clique aqui para se juntar à sua equipa',
+ 'Invite people' => 'Convidar pessoas',
+ 'Emails' => 'E-mails',
+ 'Enter one email address by line.' => 'Insira um endereço de e-mail por linha.',
+ 'Add these people to this project' => 'Adicione estas pessoas a este projeto',
+ 'Add this person to this project' => 'Adicione esta pessoa a este projeto',
+ 'Sign-up' => 'Registe-se',
+ 'Credentials' => 'Credenciais',
+ 'New user' => 'Novo utilizador',
+ 'This username is already taken' => 'Este nome de usuário já foi utilizado',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 4d821f6a..7bf57fb2 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -36,7 +36,7 @@ return array(
'Remove user' => 'Удалить пользователя',
'Do you really want to remove this user: "%s"?' => 'Вы точно хотите удалить пользователя: « %s » ?',
'All users' => 'Все пользователи',
- 'Username' => 'Имя пользователя',
+ 'Username' => 'Логин',
'Password' => 'Пароль',
'Administrator' => 'Администратор',
'Sign in' => 'Войти',
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d задач на доске',
'%d tasks in total' => 'всего %d задач',
'Unable to update this board.' => 'Не удалось обновить эту доску.',
- 'Edit board' => 'Изменить доску',
'Disable' => 'Выключить проект',
'Enable' => 'Включить проект',
'New project' => 'Новый проект',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Название',
'Assigned to %s' => 'Назначено %s',
'Remove a column' => 'Удалить колонку',
- 'Remove a column from a board' => 'Удалить колонку с доски',
'Unable to remove this column.' => 'Не удалось удалить эту колонку.',
'Do you really want to remove this column: "%s"?' => 'Вы точно хотите удалить эту колонку: "%s" ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Вы УДАЛИТЕ ВСЕ ЗАДАЧИ находящиеся в этой колонке!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Количество задач',
'User' => 'Пользователь',
'Comments' => 'Комментарии',
- 'Leave a comment' => 'Оставить комментарий',
'Comment is required' => 'Нужен комментарий',
- 'Leave a description' => 'Напишите описание',
'Comment added successfully.' => 'Комментарий успешно добавлен.',
'Unable to create your comment.' => 'Невозможно создать комментарий.',
'Due Date' => 'Сделать до',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Поиск',
'Nothing found.' => 'Ничего не найдено.',
'Due date' => 'Срок',
- 'Others formats accepted: %s and %s' => 'Другой формат приемлем: %s и %s',
'Description' => 'Описание',
'%d comments' => '%d комментариев',
'%d comment' => '%d комментарий',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Создано %s',
'Tasks Export' => 'Экспорт задач',
'Start Date' => 'Дата начала',
- 'End Date' => 'Дата завершения',
'Execute' => 'Выполнить',
'Task Id' => 'ID задачи',
'Creator' => 'Автор',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Удалённый',
'Enabled' => 'Включён',
'Disabled' => 'Выключены',
- 'Username:' => 'Имя пользователя:',
- 'Name:' => 'Имя:',
+ 'Login:' => 'Логин:',
+ 'Full Name:' => 'Имя:',
'Email:' => 'E-mail:',
'Notifications:' => 'Уведомления:',
'Notifications' => 'Уведомления',
@@ -491,7 +485,7 @@ return array(
'All swimlanes' => 'Все дорожки',
'All colors' => 'Все цвета',
'Moved to column %s' => 'Перемещена в колонку %s',
- 'User dashboard' => 'Пользователь панели мониторинга',
+ 'User dashboard' => 'Панель управления',
'Allow only one subtask in progress at the same time for a user' => 'Разрешена только одна подзадача в разработке одновременно для одного пользователя',
'Edit column "%s"' => 'Редактировать колонку "%s"',
'Select the new status of the subtask: "%s"' => 'Выбрать новый статус для подзадачи: "%s"',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Метки для ссылки',
'Link modification' => 'Обновление ссылки',
'Links' => 'Ссылки',
- 'Link settings' => 'Настройки ссылки',
'Opposite label' => 'Ярлык напротив',
'Remove a link' => 'Удалить ссылку',
- 'Task\'s links' => 'Ссылки задачи',
'The labels must be different' => 'Ярлыки должны быть разными',
'There is no link.' => 'Это не ссылка',
'This label must be unique' => 'Этот ярлык должен быть уникальным ',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Компактный вид',
'Horizontal scrolling' => 'Широкий вид',
'Compact/wide view' => 'Компактный/широкий вид',
- 'No results match:' => 'Отсутствуют результаты:',
'Currency' => 'Валюта',
'Private project' => 'Приватный проект',
'AUD - Australian Dollar' => 'AUD - Австралийский доллар',
@@ -563,9 +554,10 @@ return array(
'EUR - Euro' => 'EUR - Евро',
'GBP - British Pound' => 'GBP - Британский фунт',
'INR - Indian Rupee' => 'INR - Индийский рупий',
- 'JPY - Japanese Yen' => 'JPY - Японскай йена',
+ 'JPY - Japanese Yen' => 'JPY - Японская йена',
'NZD - New Zealand Dollar' => 'NZD - Новозеландский доллар',
'RSD - Serbian dinar' => 'RSD - Сербский динар',
+ 'CNY - Chinese Yuan' => 'CNY - Китайский юань',
'USD - US Dollar' => 'USD - доллар США',
'Destination column' => 'Колонка назначения',
'Move the task to another column when assigned to a user' => 'Переместить задачу в другую колонку, когда она назначена пользователю',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Курсы валют',
'Rate' => 'Курс',
'Change reference currency' => 'Изменить справочник валют',
- 'Add a new currency rate' => 'Добавить новый валютный курс',
'Reference currency' => 'Справочник валют',
'The currency rate have been added successfully.' => 'Курс валюты был успешно добавлен.',
'Unable to add this currency rate.' => 'Невозможно добавить этот курс валюты.',
@@ -600,7 +591,7 @@ return array(
'Assign a color when the task is moved to a specific column' => 'Назначить цвет, когда задача перемещается в определенную колонку',
'%s via Kanboard' => '%s через Канборд',
'Burndown chart' => 'Диаграмма сгорания',
- 'This chart show the task complexity over the time (Work Remaining).' => 'Эта диаграмма показывают сложность задачи по времени (оставшейся работы).',
+ 'This chart show the task complexity over the time (Work Remaining).' => 'Эта диаграмма показывает сложность задачи по времени (оставшейся работы).',
'Screenshot taken %s' => 'Скриншот сделан %s',
'Add a screenshot' => 'Прикрепить картинку',
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Сделайте скриншот и нажмите CTRL+V или ⌘+V для вложения',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30м',
'Stop timer' => 'Остановить таймер',
'Start timer' => 'Запустить таймер',
- 'Add project member' => 'Добавить номер проекта',
'My activity stream' => 'Лента моей активности',
'My calendar' => 'Мой календарь',
'Search tasks' => 'Поиск задачи',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Удаленный пользователь',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Учётные данные для входа через LDAP, Google и Github не будут сохранены в Kanboard.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Если вы установите флажок "Запретить форму входа", учётные данные, введенные в форму входа будет игнорироваться.',
- 'New remote user' => 'Новый удалённый пользователь',
- 'New local user' => 'Новый локальный пользователь',
'Default task color' => 'Стандартные цвета задач',
'This feature does not work with all browsers.' => 'Эта функция доступна не во всех браузерах.',
'There is no destination project available.' => 'Нет доступного для назначения проекта.',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'Владелец',
'Unread notifications' => 'Непрочитанные уведомления',
'Notification methods:' => 'Способы уведомления:',
- 'Import tasks from CSV file' => 'Импорт задач из CSV-файла',
'Unable to read your file' => 'Невозможно прочитать файл',
'%d task(s) have been imported successfully.' => '%d задач было успешно импортировано.',
'Nothing have been imported!' => 'Ничего не было импортировано!',
@@ -931,7 +918,7 @@ return array(
'Allowed Users' => 'Разрешенные пользователи',
'No user have been allowed specifically.' => 'Нет заданных разрешений для пользователей.',
'Role' => 'Роль',
- 'Enter user name...' => 'Введите имя пользователя...',
+ 'Enter user name...' => 'Введите логин пользователя...',
'Allowed Groups' => 'Разрешенные группы',
'No group have been allowed specifically.' => 'Нет заданных разрешений для групп.',
'Group' => 'Группа',
@@ -950,13 +937,13 @@ return array(
'Estimated Time' => 'Запланировано времени',
'Actual Time' => 'Затрачено времени',
'Estimated vs actual time' => 'Запланировано и реально затрачено времени',
- 'RUB - Russian Ruble' => 'Руб - Российский рубль',
+ 'RUB - Russian Ruble' => 'РУБ - Российский рубль',
'Assign the task to the person who does the action when the column is changed' => 'Назначить задачу пользователю, который произвёл изменение в колонке',
'Close a task in a specific column' => 'Закрыть задачу в выбранной колонке',
'Time-based One-time Password Algorithm' => 'Зависимый от времени, одноразовый алгоритм пароля',
- 'Two-Factor Provider: ' => 'Провайдер двух-факторной авторизации: ',
- 'Disable two-factor authentication' => 'Отключить двух-факторную авторизацию',
- 'Enable two-factor authentication' => 'Включить двух-факторную авторизацию',
+ 'Two-Factor Provider: ' => 'Провайдер двухфакторной авторизации: ',
+ 'Disable two-factor authentication' => 'Отключить двухфакторную авторизацию',
+ 'Enable two-factor authentication' => 'Включить двухфакторную авторизацию',
'There is no integration registered at the moment.' => 'Интеграции в данный момент не зарегистрированы.',
'Password Reset for Kanboard' => 'Сброс пароля для Kanboard',
'Forgot password?' => 'Забыли пароль?',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'Владелец проекта:',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Идентификатор проекта не обязателен и должен содержать буквенно-цифровые символы, пример: MYPROJECT',
'Project owner' => 'Владелец проекта',
- 'Those dates are useful for the project Gantt chart.' => 'Эти даты используются для диаграммы Ганта проекта.',
'Private projects do not have users and groups management.' => 'Приватные проекты не имеют управления пользователями и группами.',
'There is no project member.' => 'Нет участников проекта.',
'Priority' => 'Приоритет',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'Начата:',
'Moved:' => 'Перемещена:',
'Task #%d' => 'Задача #%d',
- 'Date and time format' => 'Формат даты и времени',
'Time format' => 'Формат времени',
'Start date: ' => 'Дата начала:',
'End date: ' => 'Дата окончания:',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Пользователь был успешно выключен.',
'Unable to disable this user.' => 'Не удалось выключить пользователя.',
'All files have been uploaded successfully.' => 'Все файлы были успешно загружены.',
- 'View uploaded files' => 'Просмотр загруженных файлов',
'The maximum allowed file size is %sB.' => 'Максимально допустимый размер файла: %sB.',
- 'Choose files again' => 'Выбрать файлы повторно',
'Drag and drop your files here' => 'Переместите ваши файлы сюда',
'choose files' => 'выбор файлов',
'View profile' => 'Просмотр профиля',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => 'Адрес отправителя',
'Email transport' => 'Почтовый транспорт',
'Webhook token' => 'Webhook токены',
- 'Imports' => 'Импорт',
'Project tags management' => 'Управление метками проекта',
'Tag created successfully.' => 'Метка успешно создана.',
'Unable to create this tag.' => 'Невозможно создать эту метку.',
@@ -1189,7 +1171,7 @@ return array(
'%s removed a comment on the task #%d' => '%s удалил комментарий к задаче #%d',
'Comment removed on task #%d' => 'Комментарий удален в задаче #%d',
'Subtask removed on task #%d' => 'Подзадача удалена в задаче #%d',
- 'Hide tasks in this column in the dashboard' => 'Не показывать задачи из этой колонки в кабинете',
+ 'Hide tasks in this column in the dashboard' => 'Не показывать задачи из этой колонки в панели управления',
'%s removed a comment on the task %s' => '%s удалил комментарии к задаче %s',
'%s removed a subtask for the task %s' => '%s удалил подзадачу для %s',
'Comment removed' => 'Комментарий удален',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => 'Лента активности для %s',
'Calendar for %s' => 'Календарь для %s',
'Notifications for %s' => 'Уведомления для %s',
- 'Subtasks export' => 'Экспорт подзадач',
- 'Tasks exportation' => 'Экспортирование задач',
'Assign a color when the task is moved to a specific swimlane' => 'Назначить цвет, когда задача будет перемещена в указанную дорожку',
'Assign a priority when the task is moved to a specific swimlane' => 'Назначить приоритет, когда задача будет перемещена в указанную дорожку',
'User unlocked successfully.' => 'Пользователь успешно разблокирован.',
@@ -1277,14 +1257,54 @@ return array(
'This field is required' => 'Заполните это поле',
'Moving a task is not permitted' => 'Перемещение задачи не разрешено',
'This value must be in the range %d to %d' => 'Значение должно находиться в диапазоне от %d до %d',
- // 'You are not allowed to move this task.' => '',
- // 'API User Access' => '',
- // 'Preview' => '',
- // 'Write' => '',
- // 'Write your text in Markdown' => '',
- // 'New External Task: %s' => '',
- // 'No personal API access token registered.' => '',
- // 'Your personal API access token is "%s"' => '',
- // 'Remove your token' => '',
- // 'Generate a new token' => '',
+ 'You are not allowed to move this task.' => 'Вам не разрешено перемещать эту задачу.',
+ 'API User Access' => 'Доступ к API',
+ 'Preview' => 'Предпросмотр',
+ 'Write' => 'Редактирование',
+ 'Write your text in Markdown' => 'Добавьте Ваше описание в формате Markdown',
+ 'New External Task: %s' => 'Новая внешняя задача: %s',
+ 'No personal API access token registered.' => 'Персональные токены доступа к API не созданы.',
+ 'Your personal API access token is "%s"' => 'Ваш персональный токен доступа к API: "%s"',
+ 'Remove your token' => 'Удалить токен',
+ 'Generate a new token' => 'Сгенерировать новый токен',
+ 'Showing %d-%d of %d' => 'Показывается %d-%d из %d',
+ 'Outgoing Emails' => 'Исходящие e-mail',
+ 'Add or change currency rate' => 'Добавить или изменить курс валют',
+ 'Reference currency: %s' => 'Базовая валюта: %s',
+ 'Add custom filters' => 'Добавить пользовательские фильтры',
+ 'Export' => 'Экспорт',
+ 'Add link label' => 'Добавить связь в задаче',
+ 'Incompatible Plugins' => 'Несовместимые плагины',
+ 'Compatibility' => 'Совместимость',
+ 'Permissions and ownership' => 'Разрешения и владение проектом',
+ 'Priorities' => 'Приоритеты',
+ 'Close this window' => 'Закрыть окно',
+ 'Unable to upload this file.' => 'Не удаётся загрузить файл.',
+ 'Import tasks' => 'Импорт задач',
+ 'Choose a project' => 'Выберите проект',
+ 'Profile' => 'Профиль',
+ 'Application role' => 'Роль в приложении',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ 'There is no custom filter.' => 'Пользовательские фильтры отсутствуют.',
+ 'New User' => 'Добавление пользователя',
+ 'Authentication' => 'Данные входа',
+ 'If checked, this user will use a third-party system for authentication.' => 'Если включено, то пользователь будет использовать стороннюю систему для авторизации.',
+ 'The password is necessary only for local users.' => 'Пароль необходим только для локальных пользователей',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ 'Invite people' => 'Приглашение пользователей',
+ 'Emails' => 'Адреса e-mail',
+ 'Enter one email address by line.' => 'Вводите по одному e-mail на строку.',
+ 'Add these people to this project' => 'Добавить приглашенных в проект',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ 'New user' => 'Добавить пользователя',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index 470e3390..bee83a94 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d zadataka na tabli',
'%d tasks in total' => '%d zadataka ukupno',
'Unable to update this board.' => 'Nemogu da ažuriram ovu tablu.',
- 'Edit board' => 'Izmeni tablu',
'Disable' => 'Onemogući',
'Enable' => 'Omogući',
'New project' => 'Novi projekat',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Naslov',
'Assigned to %s' => 'Dodeljen korisniku %s',
'Remove a column' => 'Ukloni kolonu',
- 'Remove a column from a board' => 'Ukloni kolonu sa table',
'Unable to remove this column.' => 'Nemoguće uklanjanje kolone.',
'Do you really want to remove this column: "%s"?' => 'Da li zaista želiš da ukoniš ovu kolonu: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Ova akcija BRIŠE SVE ZADATKE vezane za ovu kolonu!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Broj zadataka',
'User' => 'Korisnik',
'Comments' => 'Komentari',
- 'Leave a comment' => 'Ostavi komentar',
'Comment is required' => 'Komentar je obavezan',
- 'Leave a description' => 'Dodaj opis',
'Comment added successfully.' => 'Komentar uspešno ostavljen',
'Unable to create your comment.' => 'Nemoguće kreiranje komentara',
'Due Date' => 'Termin',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Traži',
'Nothing found.' => 'Ništa nije pronađeno',
'Due date' => 'Termin',
- 'Others formats accepted: %s and %s' => 'Ostali formati: %s i %s',
'Description' => 'Opis',
'%d comments' => '%d Komentara',
'%d comment' => '%d Komentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Kreirao %s',
'Tasks Export' => 'Izvoz zadataka',
'Start Date' => 'Početni datum',
- 'End Date' => 'Krajni datum',
'Execute' => 'Izvrši',
'Task Id' => 'Identifikator Zadatka',
'Creator' => 'Autor',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Udaljno',
'Enabled' => 'Omogući',
'Disabled' => 'Onemogući',
- 'Username:' => 'Korisničko ime:',
- 'Name:' => 'Ime i Prezime',
+ 'Login:' => 'Korisničko ime:',
+ 'Full Name:' => 'Ime i Prezime',
'Email:' => 'Email: ',
'Notifications:' => 'Obaveštenja: ',
'Notifications' => 'Obaveštenja',
@@ -516,10 +510,8 @@ return array(
// 'Link labels' => '',
// 'Link modification' => '',
// 'Links' => '',
- // 'Link settings' => '',
// 'Opposite label' => '',
// 'Remove a link' => '',
- // 'Task\'s links' => '',
// 'The labels must be different' => '',
// 'There is no link.' => '',
// 'This label must be unique' => '',
@@ -552,7 +544,6 @@ return array(
// 'Compact view' => '',
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
- // 'No results match:' => '',
// 'Currency' => '',
// 'Private project' => '',
// 'AUD - Australian Dollar' => '',
@@ -566,6 +557,7 @@ return array(
// 'JPY - Japanese Yen' => '',
// 'NZD - New Zealand Dollar' => '',
// 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
// 'USD - US Dollar' => '',
// 'Destination column' => '',
// 'Move the task to another column when assigned to a user' => '',
@@ -580,7 +572,6 @@ return array(
// 'Currency rates' => '',
// 'Rate' => '',
// 'Change reference currency' => '',
- // 'Add a new currency rate' => '',
// 'Reference currency' => '',
// 'The currency rate have been added successfully.' => '',
// 'Unable to add this currency rate.' => '',
@@ -702,7 +693,6 @@ return array(
// '<30m' => '',
// 'Stop timer' => '',
// 'Start timer' => '',
- // 'Add project member' => '',
// 'My activity stream' => '',
// 'My calendar' => '',
// 'Search tasks' => '',
@@ -757,8 +747,6 @@ return array(
// 'Remote user' => '',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- // 'New remote user' => '',
- // 'New local user' => '',
// 'Default task color' => '',
// 'This feature does not work with all browsers.' => '',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 2ec4fa82..ec6f75e1 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d uppgifter på tavlan',
'%d tasks in total' => '%d uppgifter totalt',
'Unable to update this board.' => 'Kunde inte uppdatera tavlan',
- 'Edit board' => 'Ändra tavlan',
'Disable' => 'Inaktivera',
'Enable' => 'Aktivera',
'New project' => 'Nytt projekt',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Titel',
'Assigned to %s' => 'Tilldelad %s',
'Remove a column' => 'Ta bort en kolumn',
- 'Remove a column from a board' => 'Ta bort en kolumn från tavlan',
'Unable to remove this column.' => 'Kunde inte ta bort kolumnen.',
'Do you really want to remove this column: "%s"?' => 'Vill du verkligen ta bort kolumnen: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Denna åtgärd kommer att TA BORT ALLA uppgifter kopplade till kolumnen!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Antal uppgifter',
'User' => 'Användare',
'Comments' => 'Kommentarer',
- 'Leave a comment' => 'Lämna en kommentar',
'Comment is required' => 'En kommentar måste lämnas',
- 'Leave a description' => 'Lämna en beskrivning',
'Comment added successfully.' => 'Kommentaren har lagts till.',
'Unable to create your comment.' => 'Kommentaren kunde inte laddas upp.',
'Due Date' => 'Måldatum',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Sök',
'Nothing found.' => 'Inget kunde hittas.',
'Due date' => 'Måldatum',
- 'Others formats accepted: %s and %s' => 'Andra format som accepteras: %s and %s',
'Description' => 'Beskrivning',
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'Skapad av %s',
'Tasks Export' => 'Exportera uppgifter',
'Start Date' => 'Startdatum',
- 'End Date' => 'Slutdatum',
'Execute' => 'Utför',
'Task Id' => 'Uppgift ID',
'Creator' => 'Skapare',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Fjärr',
'Enabled' => 'Aktiverad',
'Disabled' => 'Inaktiverad',
- 'Username:' => 'Användarnam:',
- 'Name:' => 'Namn:',
+ 'Login:' => 'Användarnam:',
+ 'Full Name:' => 'Namn:',
'Email:' => 'E-post:',
'Notifications:' => 'Notiser:',
'Notifications' => 'Notiser',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Länketiketter',
'Link modification' => 'Länkändring',
'Links' => 'Länkar',
- 'Link settings' => 'Länkinställningar',
'Opposite label' => 'Motpartslänk',
'Remove a link' => 'Ta bort en länk',
- 'Task\'s links' => 'Uppgiftslänkar',
'The labels must be different' => 'Etiketterna måste vara olika',
'There is no link.' => 'Det finns ingen länk',
'This label must be unique' => 'Länken måste vara unik',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'Kompakt vy',
'Horizontal scrolling' => 'Horisontell scroll',
'Compact/wide view' => 'Kompakt/bred vy',
- 'No results match:' => 'Inga matchande resultat',
'Currency' => 'Valuta',
'Private project' => 'Privat projekt',
'AUD - Australian Dollar' => 'AUD - Australiska dollar',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - Japanska Yen',
'NZD - New Zealand Dollar' => 'NZD - Nya Zeeländska Dollar',
'RSD - Serbian dinar' => 'RSD - Serbiska Dinarer',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - Amerikanska Dollar',
'Destination column' => 'Målkolumn',
'Move the task to another column when assigned to a user' => 'Flytta uppgiften till en annan kolumn när den tilldelats en användare',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'Valutakurser',
'Rate' => 'Kurs',
'Change reference currency' => 'Ändra referenskurs',
- 'Add a new currency rate' => 'Lägg till ny valutakurs',
'Reference currency' => 'Referensvaluta',
'The currency rate have been added successfully.' => 'Valutakursen har lagts till.',
'Unable to add this currency rate.' => 'Kunde inte lägga till valutakursen.',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30m',
'Stop timer' => 'Stoppa timer',
'Start timer' => 'Starta timer',
- 'Add project member' => 'Lägg till projektmedlem',
'My activity stream' => 'Min aktivitetsström',
'My calendar' => 'Min kalender',
'Search tasks' => 'Sök uppgifter',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'Extern användare',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Externa användares lösenord lagras inte i Kanboard-databasen, exempel: LDAP, Google och Github-konton.',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Om du aktiverar boxen "Tillåt inte loginformulär" kommer inloggningsuppgifter i formuläret att ignoreras.',
- 'New remote user' => 'Ny extern användare',
- 'New local user' => 'Ny lokal användare',
'Default task color' => 'Standardfärg för uppgifter',
'This feature does not work with all browsers.' => 'Denna funktion fungerar inte i alla webbläsare.',
'There is no destination project available.' => 'Det finns inget destinationsprojekt tillgängligt.',
@@ -852,7 +840,6 @@ return array(
// 'Owner' => '',
// 'Unread notifications' => '',
// 'Notification methods:' => '',
- // 'Import tasks from CSV file' => '',
// 'Unable to read your file' => '',
// '%d task(s) have been imported successfully.' => '',
// 'Nothing have been imported!' => '',
@@ -980,7 +967,6 @@ return array(
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
- // 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
// 'Priority' => '',
@@ -1037,7 +1023,6 @@ return array(
// 'Started:' => '',
// 'Moved:' => '',
// 'Task #%d' => '',
- // 'Date and time format' => '',
// 'Time format' => '',
// 'Start date: ' => '',
// 'End date: ' => '',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index 5e0912fc..dcd858d0 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d งานบนบอร์ด',
'%d tasks in total' => '%d งานทั้งหมด',
'Unable to update this board.' => 'ไม่สามารถปรับปรุงบอร์ดได้.',
- 'Edit board' => 'แก้ไขบอร์ด',
'Disable' => 'ปิดการทำงาน',
'Enable' => 'เปิดการทำงาน',
'New project' => 'โปรเจคใหม่',
@@ -72,7 +71,6 @@ return array(
'Title' => 'หัวเรื่อง',
'Assigned to %s' => 'กำหนดให้ %s',
'Remove a column' => 'ลบคอลัมน์',
- 'Remove a column from a board' => 'ลบคอลัมน์ออกจากบอร์ด',
'Unable to remove this column.' => 'ไม่สามารถลบคอลัมน์นี้',
'Do you really want to remove this column: "%s"?' => 'คุณต้องการลบคอลัมน์ « %s » ออกใช่หรือไม่?',
'This action will REMOVE ALL TASKS associated to this column!' => 'การกระทำนี้จะลบงานที่เกี่ยวข้องกับคอลัมน์นี้',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'นับงาน',
'User' => 'ผู้ใช้',
'Comments' => 'ความคิดเห็น',
- 'Leave a comment' => 'ออกความคิดเห็น',
'Comment is required' => 'ต้องการความคิดเห็น',
- 'Leave a description' => 'แสดงคำอธิบาย',
'Comment added successfully.' => 'เพิ่มความคิดเห็นเรียบร้อยแล้ว',
'Unable to create your comment.' => 'ไม่สามารถสร้างความคิดเห็น',
'Due Date' => 'วันที่ครบกำหนด',
@@ -224,7 +220,6 @@ return array(
'Search' => 'ค้นหา',
'Nothing found.' => 'ค้นหาไม่พบ.',
'Due date' => 'วันที่ครบกำหนด',
- 'Others formats accepted: %s and %s' => 'รูปแบบอื่นที่ได้รับการยอมรับ: %s และ %s',
'Description' => 'คำอธิบาย',
'%d comments' => '%d ความคิดเห็น',
'%d comment' => '%d ความคิดเห็น',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => 'สร้างโดย %s',
'Tasks Export' => 'ส่งออกงาน',
'Start Date' => 'เริ่มวันที่',
- 'End Date' => 'สิ้นสุดวันที่',
'Execute' => 'ประมวลผล',
'Task Id' => 'งาน ไอดี',
'Creator' => 'ผู้สร้าง',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'รีโมท',
'Enabled' => 'เปิดการใช้',
'Disabled' => 'ปิดการใช้',
- 'Username:' => 'ชื่อผู้ใช้:',
- 'Name:' => 'ชื่อ:',
+ 'Login:' => 'ชื่อผู้ใช้:',
+ 'Full Name:' => 'ชื่อ:',
'Email:' => 'อีเมล:',
'Notifications:' => 'แจ้งเตือน:',
'Notifications' => 'การแจ้งเตือน',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'ป้ายลิงค์',
'Link modification' => 'แก้ไขลิงค์',
'Links' => 'ลิงค์',
- 'Link settings' => 'ตั้งค่าลิงค์',
'Opposite label' => 'ป้ายชื่อตรงข้าม',
'Remove a link' => 'ลบลิงค์',
- 'Task\'s links' => 'ลิงค์',
'The labels must be different' => 'ป้ายชื่อต้องต่างกัน',
'There is no link.' => 'ไม่มีลิงค์',
'This label must be unique' => 'ป้ายชื่อต้องไม่ซ้ำกัน',
@@ -552,7 +544,6 @@ return array(
'Compact view' => 'มุมมองพอดี',
'Horizontal scrolling' => 'เลื่อนตามแนวนอน',
'Compact/wide view' => 'พอดี/กว้าง มุมมอง',
- 'No results match:' => 'ไม่มีผลลัพท์ที่ตรง',
'Currency' => 'สกุลเงิน',
'Private project' => 'โปรเจคส่วนตัว',
'AUD - Australian Dollar' => 'AUD - ดอลลาร์ออสเตรเลีย',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => 'JPY - เยน',
'NZD - New Zealand Dollar' => 'NZD - ดอลลาร์นิวซีแลนด์',
'RSD - Serbian dinar' => 'RSD - ดีนาร์เซอร์เบีย',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD - ดอลลาร์สหรัฐ',
'Destination column' => 'คอลัมน์เป้าหมาย',
'Move the task to another column when assigned to a user' => 'ย้ายงานไปคอลัมน์อื่นเมื่อกำหนดบุคคลรับผิดชอบ',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => 'อัตราค่าเงิน',
'Rate' => 'อัตรา',
'Change reference currency' => 'เปลี่ยนการอ้างถึงค่าเงิน',
- 'Add a new currency rate' => 'เพิ่มอัตราค่าเงินใหม่',
'Reference currency' => 'อ้างถึงค่าเงิน',
'The currency rate have been added successfully.' => 'เพิ่มอัตราค่าเงินเรียบร้อย',
'Unable to add this currency rate.' => 'ไม่สามารถเพิ่มค่าเงินนี้',
@@ -702,7 +693,6 @@ return array(
'<30m' => '<30นาที',
'Stop timer' => 'หยุดจับเวลา',
'Start timer' => 'เริ่มจับเวลา',
- 'Add project member' => 'เพิ่มสมาชิกโปรเจค',
'My activity stream' => 'กิจกรรมที่เกิดขึ้นของฉัน',
'My calendar' => 'ปฎิทินของฉัน',
'Search tasks' => 'ค้นหางาน',
@@ -757,8 +747,6 @@ return array(
'Remote user' => 'ผู้ใช้รีโมท',
// 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
// 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
- 'New remote user' => 'เพิ่มผู้ใช้รีโมทใหม่',
- 'New local user' => 'เพิ่มผู้ใช้ท้องถิ่นใหม่',
'Default task color' => 'สีเริ่มต้นของงาน',
'This feature does not work with all browsers.' => 'คุณลักษณะนี้ไม่สามารถทำงานได้ทุกเบราเซอร์',
// 'There is no destination project available.' => '',
@@ -852,7 +840,6 @@ return array(
'Owner' => 'เจ้าของ',
'Unread notifications' => 'การแจ้งเตือนยังไม่ได้อ่าน',
'Notification methods:' => 'ลักษณะการแจ้งเตือน:',
- 'Import tasks from CSV file' => 'นำเข้างานจากไฟล์ CSV',
'Unable to read your file' => 'ไม่สามารถอ่านไฟล์ของคุณ',
'%d task(s) have been imported successfully.' => '%d งานนำเข้าเรียบร้อย',
'Nothing have been imported!' => 'ไม่มีอะไรถูกนำเข้า',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => 'เจ้าของโปรเจค: ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'ตัวบ่งชี้โปรโจคเป็นตัวเลือกเสริมและต้องเป็นตัวอักษรหรือตัวเลข ตัวอย่าง: MYPROJECT',
'Project owner' => 'เจ้าของโปรเจค',
- 'Those dates are useful for the project Gantt chart.' => 'วันที่ใช้สำหรับแผนภูมิแกรนท์ของโปรเจค',
'Private projects do not have users and groups management.' => 'โปรเจคส่วนตัวไม่มีการจัดการผู้ใช้และกลุ่ม',
'There is no project member.' => 'ไม่มีสมาชิกโปรเจค',
'Priority' => 'ความสำคัญ',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => 'เริ่ม:',
'Moved:' => 'ย้าย:',
'Task #%d' => 'งานที่ #%d',
- 'Date and time format' => 'รูปแบบของวันเวลา',
'Time format' => 'รูปแบบของเวลา',
'Start date: ' => 'เริ่มวันที่:',
'End date: ' => 'จบวันที่:',
@@ -1051,9 +1036,7 @@ return array(
// 'User disabled successfully.' => '',
// 'Unable to disable this user.' => '',
// 'All files have been uploaded successfully.' => '',
- // 'View uploaded files' => '',
// 'The maximum allowed file size is %sB.' => '',
- // 'Choose files again' => '',
// 'Drag and drop your files here' => '',
// 'choose files' => '',
// 'View profile' => '',
@@ -1163,7 +1146,6 @@ return array(
// 'Email sender address' => '',
// 'Email transport' => '',
// 'Webhook token' => '',
- // 'Imports' => '',
// 'Project tags management' => '',
// 'Tag created successfully.' => '',
// 'Unable to create this tag.' => '',
@@ -1210,8 +1192,6 @@ return array(
// 'Activity stream for %s' => '',
// 'Calendar for %s' => '',
// 'Notifications for %s' => '',
- // 'Subtasks export' => '',
- // 'Tasks exportation' => '',
// 'Assign a color when the task is moved to a specific swimlane' => '',
// 'Assign a priority when the task is moved to a specific swimlane' => '',
// 'User unlocked successfully.' => '',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 6858f4e7..85a667a6 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '%d görev bu panoda',
'%d tasks in total' => '%d görev toplam',
'Unable to update this board.' => 'Bu pano güncellenemiyor.',
- 'Edit board' => 'Panoyu düzenle',
'Disable' => 'Devre dışı bırak',
'Enable' => 'Etkinleştir',
'New project' => 'Yeni proje',
@@ -72,7 +71,6 @@ return array(
'Title' => 'Başlık',
'Assigned to %s' => '%s kullanıcısına atanmış',
'Remove a column' => 'Bir sütunu sil',
- 'Remove a column from a board' => 'Panodan bir sütunu sil',
'Unable to remove this column.' => 'Bu sütun silinemiyor.',
'Do you really want to remove this column: "%s"?' => 'Bu sütunu gerçekten silmek istiyor musunuz: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Bu komut sütun içindeki TÜM GÖREVLERİ silecek!',
@@ -160,9 +158,7 @@ return array(
'Task count' => 'Görev sayısı',
'User' => 'Kullanıcı',
'Comments' => 'Yorumlar',
- 'Leave a comment' => 'Bir yorum ekle',
'Comment is required' => 'Yorum gerekli',
- 'Leave a description' => 'Açıklama ekleyin',
'Comment added successfully.' => 'Yorum eklendi',
'Unable to create your comment.' => 'Yorumunuz oluşturulamadı',
'Due Date' => 'Bitiş Tarihi',
@@ -224,7 +220,6 @@ return array(
'Search' => 'Ara',
'Nothing found.' => 'Hiçbir şey bulunamadı.',
'Due date' => 'Bitiş tarihi',
- 'Others formats accepted: %s and %s' => 'Diğer kabul edilen formatlar: %s ve %s',
'Description' => 'Açıklama',
'%d comments' => '%d yorum',
'%d comment' => '%d yorum',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => '%s tarafından oluşturuldu',
'Tasks Export' => 'Görevleri dışa aktar',
'Start Date' => 'Başlangıç tarihi',
- 'End Date' => 'Bitiş tarihi',
'Execute' => 'Gerçekleştir',
'Task Id' => 'Görev Kimliği',
'Creator' => 'Oluşturan',
@@ -342,8 +336,8 @@ return array(
'Remote' => 'Uzak',
'Enabled' => 'Etkinleştirildi',
'Disabled' => 'Devre dışı bırakıldı',
- 'Username:' => 'Kullanıcı adı',
- 'Name:' => 'Ad',
+ 'Login:' => 'Kullanıcı adı',
+ 'Full Name:' => 'Ad',
'Email:' => 'E-posta',
'Notifications:' => 'Bildirimler:',
'Notifications' => 'Bildirimler',
@@ -516,10 +510,8 @@ return array(
'Link labels' => 'Link etiketleri',
'Link modification' => 'Link değiştirme',
'Links' => 'Links',
- 'Link settings' => 'Link ayarları',
'Opposite label' => 'Zıt etiket',
'Remove a link' => 'Bir link silmek',
- 'Task\'s links' => 'Görevin linkleri',
'The labels must be different' => 'Etiketler farklı olmalı',
'There is no link.' => 'Hiç bir bağ yok',
'This label must be unique' => 'Bu etiket tek olmalı',
@@ -552,30 +544,21 @@ return array(
'Compact view' => 'Ekrana sığdır',
'Horizontal scrolling' => 'Geniş görünüm',
'Compact/wide view' => 'Ekrana sığdır / Geniş görünüm',
- 'No results match:' => 'Uygun sonuç bulunamadı',
'Currency' => 'Para birimi',
'Private project' => 'Özel proje',
- // 'AUD - Australian Dollar' => '',
- // 'CAD - Canadian Dollar' => '',
- // 'CHF - Swiss Francs' => '',
'AUD - Australian Dollar' => 'AUD - Avustralya Doları',
'CAD - Canadian Dollar' => 'CAD - Kanada Doları',
'CHF - Swiss Francs' => 'CHF - İsviçre Frangı',
'Custom Stylesheet' => 'Özel Sitil Css',
'download' => 'indir',
// 'EUR - Euro' => '',
- // 'GBP - British Pound' => '',
'GBP - British Pound' => 'GBP - İngiliz Paund',
- // 'INR - Indian Rupee' => '',
- // 'JPY - Japanese Yen' => '',
- // 'NZD - New Zealand Dollar' => '',
- // 'RSD - Serbian dinar' => '',
- // 'USD - US Dollar' => '',
'INR - Indian Rupee' => 'INR - Hint Rupesi',
'JPY - Japanese Yen' => 'JPY - Japon Yeni',
'NZD - New Zealand Dollar' => 'NZD - Yeni Zelanda Doları',
+ // 'RSD - Serbian dinar' => '',
+ // 'CNY - Chinese Yuan' => '',
'USD - US Dollar' => 'USD$ Amerikan Doları',
- 'TRL - Turkish Lira' => 'TRL - Türk Lirası',
'Destination column' => 'Hedef Sütun',
'Move the task to another column when assigned to a user' => 'Bir kullanıcıya atandığında görevi başka bir sütuna taşı',
'Move the task to another column when assignee is cleared' => 'Atanmış kullanıcı kaldırıldığında görevi başka bir sütuna taşı',
@@ -589,7 +572,6 @@ return array(
'Currency rates' => 'Döviz kurları',
'Rate' => 'Kurlar',
'Change reference currency' => 'Referans kur değiştir',
- 'Add a new currency rate' => 'Yeni bir kur ekle',
'Reference currency' => 'Referans kur',
'The currency rate have been added successfully.' => 'Kur başarıyla eklendi',
'Unable to add this currency rate.' => 'Bu kur eklenemedi',
@@ -614,7 +596,6 @@ return array(
'Add a screenshot' => 'Bir ekran görüntüsü ekle',
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Bir ekran görüntüsü alın ve buraya yapıştırmak için CTRL+V veya ⌘+V tuşlarına basın.',
'Screenshot uploaded successfully.' => 'Ekran görüntüsü başarıyla yüklendi',
- // 'SEK - Swedish Krona' => '',
'SEK - Swedish Krona' => ' SEK - İsveç Kronu',
'Identifier' => 'Kimlik',
'Disable two factor authentication' => 'Çift-Kademeli doğrulamayı iptal et',
@@ -712,7 +693,6 @@ return array(
'<30m' => '<30dk',
'Stop timer' => 'Zamanlayıcıyı durdur',
'Start timer' => 'Zamanlayıcıyı başlat',
- 'Add project member' => 'Proje üyesi ekle',
'My activity stream' => 'Olay akışım',
'My calendar' => 'Takvimim',
'Search tasks' => 'Görevleri ara',
@@ -767,8 +747,6 @@ return array(
'Remote user' => 'Uzak kullanıcı',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Uzak kullanıcıların şifreleri Kanboard veritabanında saklanmaz, örnek: LDAP, Google ve Github hesapları',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Eğer giriş formuna erişimi engelleyi seçerseniz, giriş formuna girilen bilgiler gözardı edilir.',
- 'New remote user' => 'Yeni uzak kullanıcı',
- 'New local user' => 'Yeni yerel kullanıcı',
'Default task color' => 'Varsayılan görev rengi',
'This feature does not work with all browsers.' => 'Bu özellik tüm tarayıcılarla çalışmaz',
'There is no destination project available.' => 'Seçilebilecek hedef proje yok.',
@@ -796,7 +774,6 @@ return array(
'Gantt chart' => 'Gantt diyagramı',
'People who are project managers' => 'Proje müdürü olan kişiler',
'People who are project members' => 'Proje üyesi olan kişiler',
- // 'NOK - Norwegian Krone' => '',
'NOK - Norwegian Krone' => ' NOK - Norveç Kronu',
'Show this column' => 'Bu sütunu göster',
'Hide this column' => 'Bu sütunu gizle',
@@ -863,7 +840,6 @@ return array(
'Owner' => 'Sahibi',
'Unread notifications' => 'Okunmamış bildirimler',
'Notification methods:' => 'Bildirim yöntemleri:',
- 'Import tasks from CSV file' => 'CSV dosyasından görevleri içeri aktar',
'Unable to read your file' => 'Dosya okunamıyor',
'%d task(s) have been imported successfully.' => '%d görev başarıyla içeri aktarıldı.',
'Nothing have been imported!' => 'Hiçbir şey içeri aktarılamadı!',
@@ -961,7 +937,6 @@ return array(
'Estimated Time' => 'Tahmini süre',
'Actual Time' => 'Gerçekleşen süre',
'Estimated vs actual time' => 'Tahmini vs gerçekleşen süre',
- // 'RUB - Russian Ruble' => '',
'RUB - Russian Ruble' => ' RUB - Rus Rublesi',
'Assign the task to the person who does the action when the column is changed' => 'Sütun değiştirildiği zaman görevi eylemi gerçekleştiren kişiye ata',
'Close a task in a specific column' => 'Belirli bir sütundaki görevi kapat',
@@ -992,7 +967,6 @@ return array(
'Project owner: ' => 'Proje sahibi',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'Proje kodu opsiyoneldir ve alfanümerik olmalıdır, örneğin: PROJE1',
'Project owner' => 'Proje sahibi',
- 'Those dates are useful for the project Gantt chart.' => 'Bu tarihler proje Gantt görünümü için gereklidir.',
'Private projects do not have users and groups management.' => '(Kişiye) Özel projelerde kullanıcı ve grup yönetimi yoktur.',
'There is no project member.' => 'Proje ekibi yok.',
'Priority' => 'Öncelik',
@@ -1049,7 +1023,6 @@ return array(
'Started:' => 'Başlatıldı',
'Moved:' => 'Taşındı',
'Task #%d' => 'Görev #%d',
- 'Date and time format' => 'Tarih ve saat formatı',
'Time format' => 'Saat formatı',
'Start date: ' => 'Başlangıç tarihi',
'End date: ' => 'Bitiş tarihi',
@@ -1063,9 +1036,7 @@ return array(
'User disabled successfully.' => 'Kullanıcı başarıyla engellendi.',
'Unable to disable this user.' => 'Bu kullanıcı engellenemez.',
'All files have been uploaded successfully.' => 'Tüm dosyalar başarıyla yüklendi.',
- 'View uploaded files' => 'Yüklenen dosyaları göster',
'The maximum allowed file size is %sB.' => 'Maksimum dosya büyüklüğü %s B.',
- 'Choose files again' => 'Dosyaları tekrar seç',
'Drag and drop your files here' => 'Dosyalarınızı buraya sürükleyip bırakın',
'choose files' => 'dosyaları seç',
'View profile' => 'Profili göster',
@@ -1094,7 +1065,7 @@ return array(
'Change subtask position' => 'Alt görev sırasını değiştir',
'This value must be greater than %d' => 'Bu değer %d den büyük olmalı',
'Another swimlane with the same name exists in the project' => 'Projede aynı isimli başka bir kulvar var',
- 'Example: http://example.dediteknoloji.com/ (used to generate absolute URLs)' => 'Örneğin: http://ornek.dediteknoloji.com/ (sabit URLler oluşturmak için)',
+ 'Example: http://example.kanboard.net/ (used to generate absolute URLs)' => 'Örneğin: http://ornek.dediteknoloji.com/ (sabit URLler oluşturmak için)',
'Actions duplicated successfully.' => 'İşlemler başarıyla çoklandı.',
'Unable to duplicate actions.' => 'İşlemler çoklanamıyor.',
'Add a new action' => 'Yeni bir işlem ekle',
@@ -1175,7 +1146,6 @@ return array(
'Email sender address' => 'E-posta gönderen adresi',
'Email transport' => 'E-posta taşıma',
'Webhook token' => 'Webhook token',
- 'Imports' => 'İçe Aktarımlar',
'Project tags management' => 'Proje etiket yönetimi',
'Tag created successfully.' => 'Etiket başarıyla oluturuldu.',
'Unable to create this tag.' => 'Etiket oluşturulamıyor.',
@@ -1222,8 +1192,6 @@ return array(
'Activity stream for %s' => '%s için akış',
'Calendar for %s' => '%s için takvim',
'Notifications for %s' => '%s için bildirimler',
- 'Subtasks export' => 'Alt görev dışa aktar',
- 'Tasks exportation' => 'Görev dışa aktar',
'Assign a color when the task is moved to a specific swimlane' => 'Görev bir kulvara taşındığında rengini değiştir',
'Assign a priority when the task is moved to a specific swimlane' => 'Görev bir kulvara taşındığında önceliğini değiştir',
'User unlocked successfully.' => 'Kullanıcı kilidi başarıyla kaldırıldı.',
@@ -1290,15 +1258,6 @@ return array(
'Moving a task is not permitted' => 'Görev taşımaya izin verilmemiş',
'This value must be in the range %d to %d' => 'Bu değer şu aralıkta olmalı: "%d" "%d"',
'You are not allowed to move this task.' => 'Bu görevi taşımaya izniniz yok.',
- // 'API User Access' => '',
- // 'Preview' => '',
- // 'Write' => '',
- // 'Write your text in Markdown' => '',
- // 'New External Task: %s' => '',
- // 'No personal API access token registered.' => '',
- // 'Your personal API access token is "%s"' => '',
- // 'Remove your token' => '',
- // 'Generate a new token' => '',
'API User Access' => 'API Kullanıcı Erişimi',
'Preview' => 'Öngörünüm',
'Write' => 'Yaz',
@@ -1308,45 +1267,44 @@ return array(
'Your personal API access token is "%s"' => 'Kişisel API erişim belirteç-token ınız"%s"',
'Remove your token' => 'Belirteç-token ınızı kaldır',
'Generate a new token' => 'Yeni bir belirteç-token oluştur',
- 'My future tasks' => 'Gelecekteki görevlerim',
- 'There is no future task.' => 'Gelecekte bir görev yok.',
- 'Future tasks for %s' => '%s için gelecekteki görevler',
- 'Manage timetable' => 'Zaman çizelgesini yönet',
- 'Timetable' => 'Zaman çizelgesi',
- 'Day timetable' => 'Günlük zaman çizelgesi',
- 'Week timetable' => 'Haftalık zaman çizelgesi',
- 'Time off timetable' => 'Öğle tatili zaman çizelgesi',
- 'Overtime timetable' => 'Mesai zaman çizelgesi',
- 'From' => 'Başlangıç',
- 'To' => 'den',
- 'Start time' => 'Başlangıç zamanı',
- 'End time' => 'Bitiş zamanı',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Bu zaman çizelgesi, "bütün gün" onay kutusu zamanlanmış kapalı ve fazla mesai için işaretlendiğinde kullanılır.',
- 'Day' => 'Gün',
- 'Monday' => 'Pazartesi',
- 'Tuesday' => 'Salı',
- 'Wednesday' => 'Çarşamba',
- 'Thursday' => 'Perşembe',
- 'Friday' => 'Cuma',
- 'Saturday' => 'Cumartesi',
- 'Sunday' => 'Pazar',
- 'All day' => 'Tüm Gün',
- 'Comment' => 'Açıklama',
- 'Hourly rate' => 'Saatlik ücret',
- 'Effective date' => 'Yürürlük tarihi',
- 'Add new rate' => 'Yeni ücret ekle',
- 'Show Google Avatar' => 'Google Avatarını Göster',
- 'User (Optional)' => 'Kullanıcı (İsteğe Bağlı)',
- 'Help on RocketChat integration' => 'RocketChat entegrasyonu hakkında yardım',
- 'SMS Two-Factor Authentication' => 'Çift-Kademeli SMS Kimlik Doğrulama',
- 'Phone Number' => 'Telefon Numarası',
- 'Channel/Group/User (Optional)' => 'Kanal / Grup / Kullanıcı (İsteğe Bağlı)',
- 'Help on Slack integration' => 'Slack entegrasyonu hakkında yardım',
- 'OAuth2 Account' => 'OAuth2 Hesabı',
- 'Link OAuth2 account' => 'OAuth2 hesabını bağla',
- 'Unlink OAuth2 account' => 'OAuth2 hesabmla bağı kaldır',
- 'Key' => 'Anahtar',
- 'Value' => 'Değer',
- 'Add Metadata' => 'Yeni Metadata Ekle',
+ // 'Showing %d-%d of %d' => '',
+ // 'Outgoing Emails' => '',
'Add or change currency rate' => 'Kur Oranını ekle veya değiştir',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index c87adbec..0f91e29f 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -61,7 +61,6 @@ return array(
'%d tasks on the board' => '看板目前有%d个任务',
'%d tasks in total' => '总共有%d个任务',
'Unable to update this board.' => '无法更新该看板。',
- 'Edit board' => '修改看板',
'Disable' => '停用',
'Enable' => '启用',
'New project' => '新建项目',
@@ -72,7 +71,6 @@ return array(
'Title' => '标题',
'Assigned to %s' => '指派给 %s',
'Remove a column' => '移除一个栏目',
- 'Remove a column from a board' => '从看板移除一个栏目',
'Unable to remove this column.' => '无法移除该栏目。',
'Do you really want to remove this column: "%s"?' => '确定要移除栏目"%s"吗?',
'This action will REMOVE ALL TASKS associated to this column!' => '该动作将移除与该栏目相关的所有项目!',
@@ -160,9 +158,7 @@ return array(
'Task count' => '任务数',
'User' => '用户',
'Comments' => '评论',
- 'Leave a comment' => '留言',
'Comment is required' => '必须得有评论',
- 'Leave a description' => '给一个描述',
'Comment added successfully.' => '评论成功添加。',
'Unable to create your comment.' => '无法创建评论。',
'Due Date' => '到期时间',
@@ -224,7 +220,6 @@ return array(
'Search' => '查找',
'Nothing found.' => '没找到。',
'Due date' => '到期时间',
- 'Others formats accepted: %s and %s' => '可以使用的其它格式:%s 和 %s',
'Description' => '描述',
'%d comments' => '%d个评论',
'%d comment' => '%d个评论',
@@ -298,7 +293,6 @@ return array(
'Created by %s' => '创建者:%s',
'Tasks Export' => '任务导出',
'Start Date' => '开始时间',
- 'End Date' => '结束时间',
'Execute' => '执行',
'Task Id' => '任务ID',
'Creator' => '创建者',
@@ -342,8 +336,8 @@ return array(
'Remote' => '远程',
'Enabled' => '启用',
'Disabled' => '停用',
- 'Username:' => '用户名:',
- 'Name:' => '姓名:',
+ 'Login:' => '用户名:',
+ 'Full Name:' => '姓名:',
'Email:' => '电子邮件:',
'Notifications:' => '通知:',
'Notifications' => '通知',
@@ -516,10 +510,8 @@ return array(
'Link labels' => '关联标签',
'Link modification' => '关联修改',
'Links' => '关联',
- 'Link settings' => '关联设置',
'Opposite label' => '反向标签',
'Remove a link' => '删除关联',
- 'Task\'s links' => '任务的关联',
'The labels must be different' => '标签不能一样',
'There is no link.' => '当前没有关联',
'This label must be unique' => '关联必须唯一',
@@ -552,7 +544,6 @@ return array(
'Compact view' => '紧凑视图',
'Horizontal scrolling' => '水平滚动',
'Compact/wide view' => '紧凑/宽视图',
- 'No results match:' => '无匹配结果:',
'Currency' => '货币',
'Private project' => '私人项目',
'AUD - Australian Dollar' => '澳元',
@@ -566,6 +557,7 @@ return array(
'JPY - Japanese Yen' => '日元',
'NZD - New Zealand Dollar' => '新西兰元',
'RSD - Serbian dinar' => '第纳尔',
+ 'CNY - Chinese Yuan' => '人民币',
'USD - US Dollar' => '美元',
'Destination column' => '目标栏目',
'Move the task to another column when assigned to a user' => '指定负责人时移动到其它栏目',
@@ -580,7 +572,6 @@ return array(
'Currency rates' => '汇率',
'Rate' => '汇率',
'Change reference currency' => '修改参考货币',
- 'Add a new currency rate' => '添加新汇率',
'Reference currency' => '参考货币',
'The currency rate have been added successfully.' => '成功添加汇率。',
'Unable to add this currency rate.' => '无法添加此汇率',
@@ -702,7 +693,6 @@ return array(
'<30m' => '小于30分钟',
'Stop timer' => '停止计时器',
'Start timer' => '开启计时器',
- 'Add project member' => '添加项目成员',
'My activity stream' => '我的活动流',
'My calendar' => '我的日程表',
'Search tasks' => '搜索任务',
@@ -757,8 +747,6 @@ return array(
'Remote user' => '远程用户',
'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '远程用户不会在看板数据库保存密码,例如:LDAP,GOOGLE,GitHub。',
'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '如果选中“禁止登陆来自”,登陆表单内的验证信息将被忽略。',
- 'New remote user' => '新加远程用户',
- 'New local user' => '新加本地用户',
'Default task color' => '默认任务颜色',
'This feature does not work with all browsers.' => '本功能只在部分浏览器下工作正常。',
'There is no destination project available.' => '当前没有目标项目可用',
@@ -852,7 +840,6 @@ return array(
'Owner' => '所有人',
'Unread notifications' => '未读通知',
'Notification methods:' => '通知提醒方式:',
- 'Import tasks from CSV file' => '从CSV文件导入任务',
'Unable to read your file' => '无法读取文件',
'%d task(s) have been imported successfully.' => '成功导入%d条任务。',
'Nothing have been imported!' => '没有信息被导入!',
@@ -980,7 +967,6 @@ return array(
'Project owner: ' => '项目负责人',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '项目标识符是可选的,且只能是数字或字母组成,例如:MYPROJECT。',
'Project owner' => '项目负责人',
- 'Those dates are useful for the project Gantt chart.' => '那些时间对于项目甘特图非常有用',
'Private projects do not have users and groups management.' => '私有项目下没有成员或组可管理',
'There is no project member.' => '当前没有项目成员',
'Priority' => '优先级',
@@ -1037,7 +1023,6 @@ return array(
'Started:' => '已开始:',
'Moved:' => '已移走',
'Task #%d' => '任务#%d',
- 'Date and time format' => '时间和日期格式',
'Time format' => '时间格式',
'Start date: ' => '开始时间:',
'End date: ' => '结束时间:',
@@ -1051,9 +1036,7 @@ return array(
'User disabled successfully.' => '用户已禁用。',
'Unable to disable this user.' => '无法禁用该用户。',
'All files have been uploaded successfully.' => '所有文件已成功上传。',
- 'View uploaded files' => '查看已上传文件',
'The maximum allowed file size is %sB.' => '最大上传尺寸 %sB',
- 'Choose files again' => '重新选择文件',
'Drag and drop your files here' => '拖放文件到这里',
'choose files' => '选择文件',
'View profile' => '查看个人信息',
@@ -1163,7 +1146,6 @@ return array(
'Email sender address' => '邮件发送地址',
'Email transport' => '邮件转发',
'Webhook token' => 'Web钩子Token',
- 'Imports' => '导入',
'Project tags management' => '项目标签管理',
'Tag created successfully.' => '成功创建标签。',
'Unable to create this tag.' => '无法创建此标签。',
@@ -1210,8 +1192,6 @@ return array(
'Activity stream for %s' => '%s的活动足迹',
'Calendar for %s' => '%s的日历',
'Notifications for %s' => '%s的通知',
- 'Subtasks export' => '子任务导出',
- 'Tasks exportation' => '任务导出',
'Assign a color when the task is moved to a specific swimlane' => '当任务移动到指定里程碑时标记颜色',
'Assign a priority when the task is moved to a specific swimlane' => '当任务移动到指定里程碑时标记优先级',
'User unlocked successfully.' => '用户解锁成功。',
@@ -1287,4 +1267,44 @@ return array(
// 'Your personal API access token is "%s"' => '',
// 'Remove your token' => '',
// 'Generate a new token' => '',
+ 'Showing %d-%d of %d' => '本页显示 %d-%d 条,共有: %d 条',
+ // 'Outgoing Emails' => '',
+ // 'Add or change currency rate' => '',
+ // 'Reference currency: %s' => '',
+ // 'Add custom filters' => '',
+ // 'Export' => '',
+ // 'Add link label' => '',
+ // 'Incompatible Plugins' => '',
+ // 'Compatibility' => '',
+ // 'Permissions and ownership' => '',
+ // 'Priorities' => '',
+ // 'Close this window' => '',
+ // 'Unable to upload this file.' => '',
+ // 'Import tasks' => '',
+ // 'Choose a project' => '',
+ // 'Profile' => '',
+ // 'Application role' => '',
+ // '%d invitations were sent.' => '',
+ // '%d invitation was sent.' => '',
+ // 'Unable to create this user.' => '',
+ // 'Kanboard Invitation' => '',
+ // 'Visible on dashboard' => '',
+ // 'Created at:' => '',
+ // 'Updated at:' => '',
+ // 'There is no custom filter.' => '',
+ // 'New User' => '',
+ // 'Authentication' => '',
+ // 'If checked, this user will use a third-party system for authentication.' => '',
+ // 'The password is necessary only for local users.' => '',
+ // 'You have been invited to register on Kanboard.' => '',
+ // 'Click here to join your team' => '',
+ // 'Invite people' => '',
+ // 'Emails' => '',
+ // 'Enter one email address by line.' => '',
+ // 'Add these people to this project' => '',
+ // 'Add this person to this project' => '',
+ // 'Sign-up' => '',
+ // 'Credentials' => '',
+ // 'New user' => '',
+ // 'This username is already taken' => '',
);
diff --git a/app/Model/CommentModel.php b/app/Model/CommentModel.php
index a9e48bd3..e44a5ecd 100644
--- a/app/Model/CommentModel.php
+++ b/app/Model/CommentModel.php
@@ -60,6 +60,7 @@ class CommentModel extends Base
->columns(
self::TABLE.'.id',
self::TABLE.'.date_creation',
+ self::TABLE.'.date_modification',
self::TABLE.'.task_id',
self::TABLE.'.user_id',
self::TABLE.'.comment',
@@ -69,7 +70,7 @@ class CommentModel extends Base
UserModel::TABLE.'.avatar_path'
)
->join(UserModel::TABLE, 'id', 'user_id')
- ->orderBy(self::TABLE.'.date_creation', $sorting)
+ ->orderBy(self::TABLE.'.date_modification', $sorting)
->eq(self::TABLE.'.task_id', $task_id)
->findAll();
}
@@ -90,6 +91,7 @@ class CommentModel extends Base
self::TABLE.'.task_id',
self::TABLE.'.user_id',
self::TABLE.'.date_creation',
+ self::TABLE.'.date_modification',
self::TABLE.'.comment',
self::TABLE.'.reference',
UserModel::TABLE.'.username',
@@ -127,6 +129,7 @@ class CommentModel extends Base
public function create(array $values)
{
$values['date_creation'] = time();
+ $values['date_modification'] = time();
$comment_id = $this->db->table(self::TABLE)->persist($values);
if ($comment_id !== false) {
@@ -148,7 +151,7 @@ class CommentModel extends Base
$result = $this->db
->table(self::TABLE)
->eq('id', $values['id'])
- ->update(array('comment' => $values['comment']));
+ ->update(array('comment' => $values['comment'], 'date_modification' => time()));
if ($result) {
$this->queueManager->push($this->commentEventJob->withParams($values['id'], self::EVENT_UPDATE));
diff --git a/app/Model/CurrencyModel.php b/app/Model/CurrencyModel.php
index a097cb34..55a5b2fe 100644
--- a/app/Model/CurrencyModel.php
+++ b/app/Model/CurrencyModel.php
@@ -42,6 +42,7 @@ class CurrencyModel extends Base
'NOK' => t('NOK - Norwegian Krone'),
'BAM' => t('BAM - Konvertible Mark'),
'RUB' => t('RUB - Russian Ruble'),
+ 'CNY' => t('CNY - Chinese Yuan'),
'TRL' => t('TRL - Turkish Lira'),
);
}
diff --git a/app/Model/FileModel.php b/app/Model/FileModel.php
index 98032f9d..b5852b08 100644
--- a/app/Model/FileModel.php
+++ b/app/Model/FileModel.php
@@ -210,9 +210,7 @@ abstract class FileModel extends Base
*/
public function isImage($filename)
{
- $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-
- switch ($extension) {
+ switch (get_file_extension($filename)) {
case 'jpeg':
case 'jpg':
case 'png':
diff --git a/app/Model/InviteModel.php b/app/Model/InviteModel.php
new file mode 100644
index 00000000..13d75f69
--- /dev/null
+++ b/app/Model/InviteModel.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Kanboard\Model;
+
+use Kanboard\Core\Base;
+use Kanboard\Core\Security\Token;
+
+/**
+ * Class InviteModel
+ *
+ * @package Kanboard\Model
+ * @author Frederic Guillot
+ */
+class InviteModel extends Base
+{
+ const TABLE = 'invites';
+
+ public function createInvites(array $emails, $projectId)
+ {
+ $emails = array_unique($emails);
+ $nb = 0;
+
+ foreach ($emails as $email) {
+ $email = trim($email);
+
+ if (! empty($email) && $this->createInvite($email, $projectId)) {
+ $nb++;
+ }
+ }
+
+ return $nb;
+ }
+
+ protected function createInvite($email, $projectId)
+ {
+ $values = array(
+ 'email' => $email,
+ 'project_id' => $projectId,
+ 'token' => Token::getToken(),
+ );
+
+ if ($this->db->table(self::TABLE)->insert($values)) {
+ $this->sendInvite($values);
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function sendInvite(array $values)
+ {
+ $this->emailClient->send(
+ $values['email'],
+ $values['email'],
+ e('Kanboard Invitation'),
+ $this->template->render('user_invite/email', array('token' => $values['token']))
+ );
+ }
+
+ public function getByToken($token)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('token', $token)
+ ->findOne();
+ }
+
+ public function remove($email)
+ {
+ return $this->db->table(self::TABLE)
+ ->eq('email', $email)
+ ->remove();
+ }
+}
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index fac8688a..7771440e 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -6,7 +6,27 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 118;
+const VERSION = 120;
+
+function version_120(PDO $pdo)
+{
+ $pdo->exec("
+ CREATE TABLE invites (
+ email VARCHAR(255) NOT NULL,
+ project_id INTEGER NOT NULL,
+ token VARCHAR(255) NOT NULL,
+ PRIMARY KEY(email, token)
+ ) ENGINE=InnoDB CHARSET=utf8
+ ");
+
+ $pdo->exec("DELETE FROM settings WHERE `option`='application_datetime_format'");
+}
+
+function version_119(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE `comments` ADD COLUMN `date_modification` BIGINT(20)');
+ $pdo->exec('UPDATE `comments` SET `date_modification` = `date_creation` WHERE `date_modification` IS NULL');
+}
function version_118(PDO $pdo)
{
@@ -63,9 +83,9 @@ function version_113(PDO $pdo)
$pdo->exec("
CREATE TABLE project_has_roles (
role_id INT NOT NULL AUTO_INCREMENT,
- role VARCHAR(255) NOT NULL,
+ `role` VARCHAR(255) NOT NULL,
project_id INT NOT NULL,
- UNIQUE(project_id, role),
+ UNIQUE(project_id, `role`),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
PRIMARY KEY(role_id)
) ENGINE=InnoDB CHARSET=utf8
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index 32a7a744..8054340c 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -6,7 +6,27 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
-const VERSION = 97;
+const VERSION = 99;
+
+function version_99(PDO $pdo)
+{
+ $pdo->exec("
+ CREATE TABLE invites (
+ email VARCHAR(255) NOT NULL,
+ project_id INTEGER NOT NULL,
+ token VARCHAR(255) NOT NULL,
+ PRIMARY KEY(email, token)
+ )
+ ");
+
+ $pdo->exec("DELETE FROM settings WHERE \"option\"='application_datetime_format'");
+}
+
+function version_98(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE "comments" ADD COLUMN date_modification BIGINT');
+ $pdo->exec('UPDATE "comments" SET date_modification = date_creation WHERE date_modification IS NULL');
+}
function version_97(PDO $pdo)
{
diff --git a/app/Schema/Sql/mysql.sql b/app/Schema/Sql/mysql.sql
index 0ee88d88..487560f3 100644
--- a/app/Schema/Sql/mysql.sql
+++ b/app/Schema/Sql/mysql.sql
@@ -100,6 +100,7 @@ CREATE TABLE `comments` (
`date_creation` bigint(20) DEFAULT NULL,
`comment` text,
`reference` varchar(50) DEFAULT '',
+ `date_modification` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `comments_reference_idx` (`reference`),
@@ -157,6 +158,16 @@ CREATE TABLE `groups` (
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+DROP TABLE IF EXISTS `invites`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `invites` (
+ `email` varchar(255) NOT NULL,
+ `project_id` int(11) NOT NULL,
+ `token` varchar(255) NOT NULL,
+ PRIMARY KEY (`email`,`token`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `last_logins`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
@@ -739,7 +750,7 @@ CREATE TABLE `users` (
LOCK TABLES `settings` WRITE;
/*!40000 ALTER TABLE `settings` DISABLE KEYS */;
-INSERT INTO `settings` VALUES ('api_token','f149956cb60c88d01123a28964fc035b1ce4513be454f2a85fe6b4ca3758',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','47d1d896b6612234c7543eb3f3a09a0a669f77a079d13ad3d810ccb79896',0,0),('webhook_url','',0,0);
+INSERT INTO `settings` VALUES ('api_token','b428b1088a5ee28730a8405774084f7a35f27f2a218cdb63582f99c008ee',0,0),('application_currency','USD',0,0),('application_date_format','m/d/Y',0,0),('application_language','en_US',0,0),('application_stylesheet','',0,0),('application_timezone','UTC',0,0),('application_url','',0,0),('board_columns','',0,0),('board_highlight_period','172800',0,0),('board_private_refresh_interval','10',0,0),('board_public_refresh_interval','60',0,0),('calendar_project_tasks','date_started',0,0),('calendar_user_subtasks_time_tracking','0',0,0),('calendar_user_tasks','date_started',0,0),('cfd_include_closed_tasks','1',0,0),('default_color','yellow',0,0),('integration_gravatar','0',0,0),('password_reset','1',0,0),('project_categories','',0,0),('subtask_restriction','0',0,0),('subtask_time_tracking','1',0,0),('webhook_token','e0d3e2613a79f1d751135f4a4d6c3e5b869348db229e57f706b5b54fc3c7',0,0),('webhook_url','',0,0);
/*!40000 ALTER TABLE `settings` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
@@ -768,4 +779,4 @@ UNLOCK TABLES;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$R1zYk04d96KcHRpd9.r5I.5I6mgKIgUdsaISZYmaDLPIJCUO0FFJG', 'app-admin');INSERT INTO schema_version VALUES ('118');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$R3.YibAi6H0ZzzrSHFa7qeaiEqep1X2TF/bKQX5jMQ7fZ9KIfzUte', 'app-admin');INSERT INTO schema_version VALUES ('120');
diff --git a/app/Schema/Sql/postgres.sql b/app/Schema/Sql/postgres.sql
index 578b0c75..8c6b0dd8 100644
--- a/app/Schema/Sql/postgres.sql
+++ b/app/Schema/Sql/postgres.sql
@@ -196,7 +196,8 @@ CREATE TABLE "comments" (
"user_id" integer DEFAULT 0,
"date_creation" bigint NOT NULL,
"comment" "text",
- "reference" character varying(50) DEFAULT ''::character varying
+ "reference" character varying(50) DEFAULT ''::character varying,
+ "date_modification" bigint
);
@@ -304,6 +305,17 @@ ALTER SEQUENCE "groups_id_seq" OWNED BY "groups"."id";
--
+-- Name: invites; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE "invites" (
+ "email" character varying(255) NOT NULL,
+ "project_id" integer NOT NULL,
+ "token" character varying(255) NOT NULL
+);
+
+
+--
-- Name: last_logins; Type: TABLE; Schema: public; Owner: -
--
@@ -1605,6 +1617,14 @@ ALTER TABLE ONLY "groups"
--
+-- Name: invites invites_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY "invites"
+ ADD CONSTRAINT "invites_pkey" PRIMARY KEY ("email", "token");
+
+
+--
-- Name: last_logins last_logins_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2543,8 +2563,8 @@ INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_high
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_public_refresh_interval', '60', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_private_refresh_interval', '10', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('board_columns', '', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', 'b64911d9b61ea71adada348105281e16470e268fce7cb9bf1895958d4bbc', 0, 0);
-INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', 'f63bd25c2e952d78b70f178fd96b4207ef29315ca73d308af37c02d8d51f', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('webhook_token', 'a41accd9dabc3d45a3d26de5edd5c43b3b0082cabebfbc7a175b8d6b2e5a', 0, 0);
+INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('api_token', 'dbbf966938e4400746ebcb2337bb4a3cdce0bab2dd053d57dbbc243ccc9d', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_language', 'en_US', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_timezone', 'UTC', 0, 0);
INSERT INTO settings (option, value, changed_by, changed_on) VALUES ('application_url', '', 0, 0);
@@ -2613,4 +2633,4 @@ SELECT pg_catalog.setval('links_id_seq', 11, true);
-- PostgreSQL database dump complete
--
-INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$0.8BJyhOEBHGqfwD3nIJHuxObqTlZGJ/KRNDVHfSu7RGd42rEbSa.', 'app-admin');INSERT INTO schema_version VALUES ('97');
+INSERT INTO users (username, password, role) VALUES ('admin', '$2y$10$R3.YibAi6H0ZzzrSHFa7qeaiEqep1X2TF/bKQX5jMQ7fZ9KIfzUte', 'app-admin');INSERT INTO schema_version VALUES ('99');
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index 11dcd537..87630b1a 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -6,7 +6,27 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
-const VERSION = 108;
+const VERSION = 110;
+
+function version_110(PDO $pdo)
+{
+ $pdo->exec("
+ CREATE TABLE invites (
+ email TEXT NOT NULL,
+ project_id INTEGER NOT NULL,
+ token TEXT NOT NULL,
+ PRIMARY KEY(email, token)
+ )
+ ");
+
+ $pdo->exec("DELETE FROM settings WHERE \"option\"='application_datetime_format'");
+}
+
+function version_109(PDO $pdo)
+{
+ $pdo->exec('ALTER TABLE comments ADD COLUMN date_modification INTEGER');
+ $pdo->exec('UPDATE comments SET date_modification = date_creation WHERE date_modification IS NULL;');
+}
function version_108(PDO $pdo)
{
diff --git a/app/ServiceProvider/AuthenticationProvider.php b/app/ServiceProvider/AuthenticationProvider.php
index 80882456..6a9a820e 100644
--- a/app/ServiceProvider/AuthenticationProvider.php
+++ b/app/ServiceProvider/AuthenticationProvider.php
@@ -88,7 +88,6 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('ExportController', '*', Role::PROJECT_MANAGER);
$acl->add('TaskFileController', array('screenshot', 'create', 'save', 'remove', 'confirm'), Role::PROJECT_MEMBER);
$acl->add('TaskGanttController', '*', Role::PROJECT_MANAGER);
- $acl->add('TaskGanttCreationController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectViewController', array('share', 'updateSharing', 'integrations', 'updateIntegrations', 'notifications', 'updateNotifications', 'duplicate', 'doDuplication'), Role::PROJECT_MANAGER);
$acl->add('ProjectPermissionController', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectEditController', '*', Role::PROJECT_MANAGER);
@@ -137,6 +136,7 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->add('ICalendarController', '*', Role::APP_PUBLIC);
$acl->add('FeedController', '*', Role::APP_PUBLIC);
$acl->add('AvatarFileController', array('show', 'image'), Role::APP_PUBLIC);
+ $acl->add('UserInviteController', array('signup', 'register'), Role::APP_PUBLIC);
$acl->add('ConfigController', '*', Role::APP_ADMIN);
$acl->add('TagController', '*', Role::APP_ADMIN);
@@ -197,19 +197,19 @@ class AuthenticationProvider implements ServiceProviderInterface
$acl->setRoleHierarchy(Role::PROJECT_MEMBER, array(Role::PROJECT_VIEWER));
$acl->add('ActionProcedure', array('removeAction', 'getActions', 'createAction'), Role::PROJECT_MANAGER);
- $acl->add('CategoryProcedure', '*', Role::PROJECT_MANAGER);
- $acl->add('ColumnProcedure', '*', Role::PROJECT_MANAGER);
+ $acl->add('CategoryProcedure', array('removeCategory', 'createCategory', 'updateCategory'), Role::PROJECT_MANAGER);
+ $acl->add('ColumnProcedure', array('updateColumn', 'addColumn', 'removeColumn', 'changeColumnPosition'), Role::PROJECT_MANAGER);
$acl->add('CommentProcedure', array('removeComment', 'createComment', 'updateComment'), Role::PROJECT_MEMBER);
- $acl->add('ProjectPermissionProcedure', '*', Role::PROJECT_MANAGER);
+ $acl->add('ProjectPermissionProcedure', array('addProjectUser', 'addProjectGroup', 'removeProjectUser', 'removeProjectGroup', 'changeProjectUserRole', 'changeProjectGroupRole'), Role::PROJECT_MANAGER);
$acl->add('ProjectProcedure', array('updateProject', 'removeProject', 'enableProject', 'disableProject', 'enableProjectPublicAccess', 'disableProjectPublicAccess'), Role::PROJECT_MANAGER);
- $acl->add('SubtaskProcedure', '*', Role::PROJECT_MEMBER);
- $acl->add('SubtaskTimeTrackingProcedure', '*', Role::PROJECT_MEMBER);
- $acl->add('SwimlaneProcedure', '*', Role::PROJECT_MANAGER);
- $acl->add('ProjectFileProcedure', '*', Role::PROJECT_MEMBER);
- $acl->add('TaskFileProcedure', '*', Role::PROJECT_MEMBER);
- $acl->add('TaskLinkProcedure', '*', Role::PROJECT_MEMBER);
+ $acl->add('SubtaskProcedure', array('removeSubtask', 'createSubtask', 'updateSubtask'), Role::PROJECT_MEMBER);
+ $acl->add('SubtaskTimeTrackingProcedure', array('setSubtaskStartTime', 'setSubtaskEndTime'), Role::PROJECT_MEMBER);
+ $acl->add('SwimlaneProcedure', array('addSwimlane', 'updateSwimlane', 'removeSwimlane', 'disableSwimlane', 'enableSwimlane', 'changeSwimlanePosition'), Role::PROJECT_MANAGER);
+ $acl->add('ProjectFileProcedure', array('createProjectFile', 'removeProjectFile', 'removeAllProjectFiles'), Role::PROJECT_MEMBER);
+ $acl->add('TaskFileProcedure', array('createTaskFile', 'removeTaskFile', 'removeAllTaskFiles'), Role::PROJECT_MEMBER);
+ $acl->add('TaskLinkProcedure', array('createTaskLink', 'updateTaskLink', 'removeTaskLink'), Role::PROJECT_MEMBER);
$acl->add('TaskExternalLinkProcedure', array('createExternalTaskLink', 'updateExternalTaskLink', 'removeExternalTaskLink'), Role::PROJECT_MEMBER);
- $acl->add('TaskProcedure', '*', Role::PROJECT_MEMBER);
+ $acl->add('TaskProcedure', array('openTask', 'closeTask', 'removeTask', 'moveTaskPosition', 'moveTaskToProject', 'duplicateTaskToProject', 'createTask', 'updateTask'), Role::PROJECT_MEMBER);
$acl->add('TaskTagProcedure', array('setTaskTags'), Role::PROJECT_MEMBER);
$acl->add('TagProcedure', array('createTag', 'updateTag', 'removeTag'), Role::PROJECT_MEMBER);
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 8d471b79..50ce531f 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -42,6 +42,7 @@ class ClassProvider implements ServiceProviderInterface
'CustomFilterModel',
'GroupModel',
'GroupMemberModel',
+ 'InviteModel',
'LanguageModel',
'LastLoginModel',
'LinkModel',
diff --git a/app/ServiceProvider/CommandProvider.php b/app/ServiceProvider/CommandProvider.php
index c9abb294..f17ba352 100644
--- a/app/ServiceProvider/CommandProvider.php
+++ b/app/ServiceProvider/CommandProvider.php
@@ -5,6 +5,7 @@ namespace Kanboard\ServiceProvider;
use Kanboard\Console\CronjobCommand;
use Kanboard\Console\DatabaseMigrationCommand;
use Kanboard\Console\DatabaseVersionCommand;
+use Kanboard\Console\JobCommand;
use Kanboard\Console\LocaleComparatorCommand;
use Kanboard\Console\LocaleSyncCommand;
use Kanboard\Console\PluginInstallCommand;
@@ -52,6 +53,7 @@ class CommandProvider implements ServiceProviderInterface
$application->add(new TaskTriggerCommand($container));
$application->add(new CronjobCommand($container));
$application->add(new WorkerCommand($container));
+ $application->add(new JobCommand($container));
$application->add(new ResetPasswordCommand($container));
$application->add(new ResetTwoFactorCommand($container));
$application->add(new PluginUpgradeCommand($container));
diff --git a/app/ServiceProvider/FilterProvider.php b/app/ServiceProvider/FilterProvider.php
index 1684592b..1cc4da8a 100644
--- a/app/ServiceProvider/FilterProvider.php
+++ b/app/ServiceProvider/FilterProvider.php
@@ -14,6 +14,7 @@ use Kanboard\Filter\TaskCategoryFilter;
use Kanboard\Filter\TaskColorFilter;
use Kanboard\Filter\TaskColumnFilter;
use Kanboard\Filter\TaskCommentFilter;
+use Kanboard\Filter\TaskCompletionDateFilter;
use Kanboard\Filter\TaskCreationDateFilter;
use Kanboard\Filter\TaskCreatorFilter;
use Kanboard\Filter\TaskDescriptionFilter;
@@ -156,6 +157,9 @@ class FilterProvider implements ServiceProviderInterface
->withFilter(TaskStartDateFilter::getInstance()
->setDateParser($c['dateParser'])
)
+ ->withFilter(TaskCompletionDateFilter::getInstance()
+ ->setDateparser($c['dateParser'])
+ )
->withFilter(new TaskIdFilter())
->withFilter(TaskLinkFilter::getInstance()
->setDatabase($c['db'])
diff --git a/app/ServiceProvider/FormatterProvider.php b/app/ServiceProvider/FormatterProvider.php
new file mode 100644
index 00000000..dbba3f3c
--- /dev/null
+++ b/app/ServiceProvider/FormatterProvider.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Kanboard\ServiceProvider;
+
+use Kanboard\Core\Tool;
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+
+/**
+ * Class FormatterProvider
+ *
+ * @package Kanboard\ServiceProvider
+ * @author Frederic Guillot
+ */
+class FormatterProvider implements ServiceProviderInterface
+{
+ protected $formatters = array(
+ 'Formatter' => array(
+ 'BoardColumnFormatter',
+ 'BoardFormatter',
+ 'BoardSwimlaneFormatter',
+ 'BoardTaskFormatter',
+ 'GroupAutoCompleteFormatter',
+ 'ProjectActivityEventFormatter',
+ 'ProjectGanttFormatter',
+ 'SubtaskTimeTrackingCalendarFormatter',
+ 'TaskAutoCompleteFormatter',
+ 'TaskCalendarFormatter',
+ 'TaskGanttFormatter',
+ 'TaskICalFormatter',
+ 'TaskSuggestMenuFormatter',
+ 'UserAutoCompleteFormatter',
+ 'UserMentionFormatter',
+ )
+ );
+
+ /**
+ * Registers services on the given container.
+ *
+ * @param Container $container
+ * @return Container
+ */
+ public function register(Container $container)
+ {
+ Tool::buildFactories($container, $this->formatters);
+ return $container;
+ }
+}
diff --git a/app/ServiceProvider/HelperProvider.php b/app/ServiceProvider/HelperProvider.php
index f4c0db22..dcaf81c6 100644
--- a/app/ServiceProvider/HelperProvider.php
+++ b/app/ServiceProvider/HelperProvider.php
@@ -39,6 +39,7 @@ class HelperProvider implements ServiceProviderInterface
$container['helper']->register('projectHeader', '\Kanboard\Helper\ProjectHeaderHelper');
$container['helper']->register('projectActivity', '\Kanboard\Helper\ProjectActivityHelper');
$container['helper']->register('mail', '\Kanboard\Helper\MailHelper');
+ $container['helper']->register('modal', '\Kanboard\Helper\ModalHelper');
$container['template'] = new Template($container['helper']);
diff --git a/app/ServiceProvider/RouteProvider.php b/app/ServiceProvider/RouteProvider.php
index 52687647..08759b22 100644
--- a/app/ServiceProvider/RouteProvider.php
+++ b/app/ServiceProvider/RouteProvider.php
@@ -65,10 +65,7 @@ class RouteProvider implements ServiceProviderInterface
$container['route']->addRoute('project/:project_id/overview', 'ProjectOverviewController', 'show');
// ProjectEdit routes
- $container['route']->addRoute('project/:project_id/edit', 'ProjectEditController', 'edit');
- $container['route']->addRoute('project/:project_id/edit/dates', 'ProjectEditController', 'dates');
- $container['route']->addRoute('project/:project_id/edit/description', 'ProjectEditController', 'description');
- $container['route']->addRoute('project/:project_id/edit/priority', 'ProjectEditController', 'priority');
+ $container['route']->addRoute('project/:project_id/edit', 'ProjectEditController', 'show');
// ProjectUser routes
$container['route']->addRoute('projects/managers/:user_id', 'ProjectUserOverviewController', 'managers');
diff --git a/app/Template/action/index.php b/app/Template/action/index.php
index 7768a0b6..90db0450 100644
--- a/app/Template/action/index.php
+++ b/app/Template/action/index.php
@@ -2,12 +2,10 @@
<h2><?= t('Automatic actions for the project "%s"', $project['name']) ?></h2>
<ul>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new action'), 'ActionCreationController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new action'), 'ActionCreationController', 'create', array('project_id' => $project['id'])) ?>
</li>
<li>
- <i class="fa fa-copy fa-fw"></i>
- <?= $this->url->link(t('Import from another project'), 'ProjectActionDuplicationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('copy', t('Import from another project'), 'ProjectActionDuplicationController', 'show', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
@@ -17,8 +15,8 @@
<?php else: ?>
<table class="table-scrolling">
<tr>
- <th><?= t('Automatic actions') ?></th>
- <th><?= t('Action parameters') ?></th>
+ <th class="column-60"><?= t('Automatic actions') ?></th>
+ <th class="column-25"><?= t('Action parameters') ?></th>
<th><?= t('Action') ?></th>
</tr>
@@ -65,7 +63,7 @@
</ul>
</td>
<td>
- <?= $this->url->link(t('Remove'), 'ActionController', 'confirm', array('project_id' => $project['id'], 'action_id' => $action['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ActionController', 'confirm', array('project_id' => $project['id'], 'action_id' => $action['id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/action/remove.php b/app/Template/action/remove.php
index 384bec7a..e3cdb206 100644
--- a/app/Template/action/remove.php
+++ b/app/Template/action/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this action: "%s"?', $this->text->in($action['event_name'], $available_events).'/'.$this->text->in($action['action_name'], $available_actions)) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ActionController', 'remove', array('project_id' => $project['id'], 'action_id' => $action['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ActionController',
+ 'remove',
+ array('project_id' => $project['id'], 'action_id' => $action['id'])
+ ) ?>
</div>
diff --git a/app/Template/action_creation/create.php b/app/Template/action_creation/create.php
index c0d2880e..862ee474 100644
--- a/app/Template/action_creation/create.php
+++ b/app/Template/action_creation/create.php
@@ -1,16 +1,14 @@
<div class="page-header">
<h2><?= t('Add an action') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'event', array('project_id' => $project['id'])) ?>">
+<form method="post" action="<?= $this->url->href('ActionCreationController', 'event', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Action'), 'action_name') ?>
<?= $this->form->select('action_name', $available_actions, $values) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Next step') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ActionController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons(array(
+ 'submitLabel' => t('Next step')
+ )) ?>
</form>
diff --git a/app/Template/action_creation/event.php b/app/Template/action_creation/event.php
index cdf00310..e4166548 100644
--- a/app/Template/action_creation/event.php
+++ b/app/Template/action_creation/event.php
@@ -2,8 +2,7 @@
<h2><?= t('Choose an event') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'params', array('project_id' => $project['id'])) ?>">
-
+<form method="post" action="<?= $this->url->href('ActionCreationController', 'params', array('project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -19,9 +18,7 @@
<?= t('When the selected event occurs execute the corresponding action.') ?>
</div>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Next step') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons(array(
+ 'submitLabel' => t('Next step')
+ )) ?>
</form>
diff --git a/app/Template/action_creation/params.php b/app/Template/action_creation/params.php
index c9608f21..0cc98f50 100644
--- a/app/Template/action_creation/params.php
+++ b/app/Template/action_creation/params.php
@@ -2,8 +2,7 @@
<h2><?= t('Define action parameters') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ActionCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('ActionCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -50,9 +49,5 @@
<?php endif ?>
<?php endforeach ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ActionController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/activity/project.php b/app/Template/activity/project.php
index e8e62777..ce1f8bba 100644
--- a/app/Template/activity/project.php
+++ b/app/Template/activity/project.php
@@ -1,14 +1,12 @@
-<section id="main">
- <?= $this->projectHeader->render($project, 'ActivityController', $this->app->getRouterAction()) ?>
+<div class="page-header">
+ <h2><?= t('%s\'s activity', $project['name']) ?></h2>
<?php if ($project['is_public']): ?>
- <div class="menu-inline pull-right">
<ul>
- <li><i class="fa fa-rss-square fa-fw"></i><?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar fa-fw"></i><?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
+ <li><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
</ul>
- </div>
<?php endif ?>
+</div>
- <?= $this->render('event/events', array('events' => $events)) ?>
-</section>
+<?= $this->render('event/events', array('events' => $events)) ?>
diff --git a/app/Template/analytic/avg_time_columns.php b/app/Template/analytic/avg_time_columns.php
index 929331a9..1af69c8b 100644
--- a/app/Template/analytic/avg_time_columns.php
+++ b/app/Template/analytic/avg_time_columns.php
@@ -1,6 +1,8 @@
-<div class="page-header">
- <h2><?= t('Average time spent into each column') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Average time spent into each column') ?></h2>
+ </div>
+<?php endif ?>
<?php if (empty($metrics)): ?>
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
@@ -11,16 +13,16 @@
)) ?>
<table class="table-striped">
- <tr>
- <th><?= t('Column') ?></th>
- <th><?= t('Average time spent') ?></th>
- </tr>
- <?php foreach ($metrics as $column): ?>
- <tr>
- <td><?= $this->text->e($column['title']) ?></td>
- <td><?= $this->dt->duration($column['average']) ?></td>
- </tr>
- <?php endforeach ?>
+ <tr>
+ <th><?= t('Column') ?></th>
+ <th><?= t('Average time spent') ?></th>
+ </tr>
+ <?php foreach ($metrics as $column): ?>
+ <tr>
+ <td><?= $this->text->e($column['title']) ?></td>
+ <td><?= $this->dt->duration($column['average']) ?></td>
+ </tr>
+ <?php endforeach ?>
</table>
<p class="alert alert-info">
diff --git a/app/Template/analytic/burndown.php b/app/Template/analytic/burndown.php
index 674c76dd..d62c9ba0 100644
--- a/app/Template/analytic/burndown.php
+++ b/app/Template/analytic/burndown.php
@@ -1,6 +1,8 @@
-<div class="page-header">
- <h2><?= t('Burndown chart') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Burndown chart') ?></h2>
+ </div>
+<?php endif ?>
<?php if (! $display_graph): ?>
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
@@ -15,20 +17,10 @@
<hr/>
<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'burndown', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('Start date'), 'from', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('End date'), 'to', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
- </div>
+ <?= $this->form->date(t('Start date'), 'from', $values) ?>
+ <?= $this->form->date(t('End date'), 'to', $values) ?>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Execute'))) ?>
</form>
<p class="alert alert-info"><?= t('This chart show the task complexity over the time (Work Remaining).') ?></p>
diff --git a/app/Template/analytic/cfd.php b/app/Template/analytic/cfd.php
index 5eb42e82..dcd7b58f 100644
--- a/app/Template/analytic/cfd.php
+++ b/app/Template/analytic/cfd.php
@@ -1,6 +1,8 @@
-<div class="page-header">
- <h2><?= t('Cumulative flow diagram') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Cumulative flow diagram') ?></h2>
+ </div>
+<?php endif ?>
<?php if (! $display_graph): ?>
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
@@ -14,18 +16,8 @@
<hr/>
<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'cfd', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('Start date'), 'from', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('End date'), 'to', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
- </div>
+ <?= $this->form->date(t('Start date'), 'from', $values) ?>
+ <?= $this->form->date(t('End date'), 'to', $values) ?>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Execute'))) ?>
</form>
diff --git a/app/Template/analytic/layout.php b/app/Template/analytic/layout.php
index e3c6099f..7159094c 100644
--- a/app/Template/analytic/layout.php
+++ b/app/Template/analytic/layout.php
@@ -1,10 +1,14 @@
-<section id="main">
+<?php if ($is_ajax): ?>
+ <div class="page-header">
+ <h2><?= $title ?></h2>
+ </div>
+<?php else: ?>
<?= $this->projectHeader->render($project, 'TaskListController', 'show') ?>
- <section class="sidebar-container">
- <?= $this->render($sidebar_template, array('project' => $project)) ?>
+<?php endif ?>
+<section class="sidebar-container">
+ <?= $this->render($sidebar_template, array('project' => $project)) ?>
- <div class="sidebar-content">
- <?= $content_for_sublayout ?>
- </div>
- </section>
+ <div class="sidebar-content">
+ <?= $content_for_sublayout ?>
+ </div>
</section>
diff --git a/app/Template/analytic/lead_cycle_time.php b/app/Template/analytic/lead_cycle_time.php
index d5908096..780b47b6 100644
--- a/app/Template/analytic/lead_cycle_time.php
+++ b/app/Template/analytic/lead_cycle_time.php
@@ -1,8 +1,10 @@
-<div class="page-header">
- <h2><?= t('Average Lead and Cycle time') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Average Lead and Cycle time') ?></h2>
+ </div>
+<?php endif ?>
-<div class="listing">
+<div class="panel">
<ul>
<li><?= t('Average lead time: ').'<strong>'.$this->dt->duration($average['avg_lead_time']) ?></strong></li>
<li><?= t('Average cycle time: ').'<strong>'.$this->dt->duration($average['avg_cycle_time']) ?></strong></li>
@@ -19,20 +21,10 @@
)) ?>
<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('Start date'), 'from', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <?= $this->form->date(t('End date'), 'to', $values) ?>
- </div>
-
- <div class="form-inline-group">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
- </div>
+ <?= $this->form->date(t('Start date'), 'from', $values) ?>
+ <?= $this->form->date(t('End date'), 'to', $values) ?>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Execute'))) ?>
</form>
<p class="alert alert-info">
diff --git a/app/Template/analytic/sidebar.php b/app/Template/analytic/sidebar.php
index f768a11d..d5ce88cb 100644
--- a/app/Template/analytic/sidebar.php
+++ b/app/Template/analytic/sidebar.php
@@ -1,28 +1,27 @@
<div class="sidebar">
<ul>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'taskDistribution') ?>>
- <?= $this->url->link(t('Task distribution'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Task distribution'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'userDistribution') ?>>
- <?= $this->url->link(t('User repartition'), 'AnalyticController', 'userDistribution', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('User repartition'), 'AnalyticController', 'userDistribution', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'cfd') ?>>
- <?= $this->url->link(t('Cumulative flow diagram'), 'AnalyticController', 'cfd', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Cumulative flow diagram'), 'AnalyticController', 'cfd', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'burndown') ?>>
- <?= $this->url->link(t('Burndown chart'), 'AnalyticController', 'burndown', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Burndown chart'), 'AnalyticController', 'burndown', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'averageTimeByColumn') ?>>
- <?= $this->url->link(t('Average time into each column'), 'AnalyticController', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Average time into each column'), 'AnalyticController', 'averageTimeByColumn', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'leadAndCycleTime') ?>>
- <?= $this->url->link(t('Lead and cycle time'), 'AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Lead and cycle time'), 'AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('AnalyticController', 'timeComparison') ?>>
- <?= $this->url->link(t('Estimated vs actual time'), 'AnalyticController', 'timeComparison', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->replaceLink(t('Estimated vs actual time'), 'AnalyticController', 'timeComparison', array('project_id' => $project['id'])) ?>
</li>
<?= $this->hook->render('template:analytic:sidebar', array('project' => $project)) ?>
-
</ul>
</div>
diff --git a/app/Template/analytic/task_distribution.php b/app/Template/analytic/task_distribution.php
index 1231856e..671d462f 100644
--- a/app/Template/analytic/task_distribution.php
+++ b/app/Template/analytic/task_distribution.php
@@ -1,6 +1,8 @@
-<div class="page-header">
- <h2><?= t('Task distribution') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Task distribution') ?></h2>
+ </div>
+<?php endif ?>
<?php if (empty($metrics)): ?>
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
diff --git a/app/Template/analytic/time_comparison.php b/app/Template/analytic/time_comparison.php
index 31d0f53b..754c68f2 100644
--- a/app/Template/analytic/time_comparison.php
+++ b/app/Template/analytic/time_comparison.php
@@ -1,8 +1,10 @@
-<div class="page-header">
- <h2><?= t('Estimated vs actual time') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('Estimated vs actual time') ?></h2>
+ </div>
+<?php endif ?>
-<div class="listing">
+<div class="panel">
<ul>
<li><?= t('Estimated hours: ').'<strong>'.$this->text->e($metrics['open']['time_estimated'] + $metrics['closed']['time_estimated']) ?></strong></li>
<li><?= t('Actual hours: ').'<strong>'.$this->text->e($metrics['open']['time_spent'] + $metrics['closed']['time_spent']) ?></strong></li>
@@ -27,9 +29,9 @@
<tr>
<th class="column-5"><?= $paginator->order(t('Id'), 'tasks.id') ?></th>
<th><?= $paginator->order(t('Title'), 'tasks.title') ?></th>
- <th class="column-5"><?= $paginator->order(t('Status'), 'tasks.is_active') ?></th>
- <th class="column-10"><?= $paginator->order(t('Estimated Time'), 'tasks.time_estimated') ?></th>
- <th class="column-10"><?= $paginator->order(t('Actual Time'), 'tasks.time_spent') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Status'), 'tasks.is_active') ?></th>
+ <th class="column-12"><?= $paginator->order(t('Estimated Time'), 'tasks.time_estimated') ?></th>
+ <th class="column-12"><?= $paginator->order(t('Actual Time'), 'tasks.time_spent') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $task): ?>
<tr>
diff --git a/app/Template/analytic/user_distribution.php b/app/Template/analytic/user_distribution.php
index 76ac945c..cae6fa57 100644
--- a/app/Template/analytic/user_distribution.php
+++ b/app/Template/analytic/user_distribution.php
@@ -1,6 +1,8 @@
-<div class="page-header">
- <h2><?= t('User repartition') ?></h2>
-</div>
+<?php if (! $is_ajax): ?>
+ <div class="page-header">
+ <h2><?= t('User repartition') ?></h2>
+ </div>
+<?php endif ?>
<?php if (empty($metrics)): ?>
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
diff --git a/app/Template/board/table_column.php b/app/Template/board/table_column.php
index e2976f27..df16715f 100644
--- a/app/Template/board/table_column.php
+++ b/app/Template/board/table_column.php
@@ -14,7 +14,7 @@
<div class="board-column-expanded">
<?php if (! $not_editable && $this->projectRole->canCreateTaskInColumn($column['project_id'], $column['id'])): ?>
<div class="board-add-icon">
- <?= $this->url->link('+', 'TaskCreationController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover', t('Add a new task')) ?>
+ <?= $this->modal->largeIcon('plus', t('Add a new task'), 'TaskCreationController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id'])) ?>
</div>
<?php endif ?>
@@ -37,15 +37,13 @@
</li>
<?php if ($this->projectRole->canCreateTaskInColumn($column['project_id'], $column['id'])): ?>
<li>
- <i class="fa fa-align-justify fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Create tasks in bulk'), 'TaskBulkController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->modal->medium('align-justify', t('Create tasks in bulk'), 'TaskBulkController', 'show', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<?php endif ?>
<?php if ($column['nb_tasks'] > 0 && $this->projectRole->canChangeTaskStatusInColumn($column['project_id'], $column['id'])): ?>
<li>
- <i class="fa fa-close fa-fw"></i>
- <?= $this->url->link(t('Close all tasks of this column'), 'BoardPopoverController', 'confirmCloseColumnTasks', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('close', t('Close all tasks of this column'), 'BoardPopoverController', 'confirmCloseColumnTasks', array('project_id' => $column['project_id'], 'column_id' => $column['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<?php endif ?>
@@ -76,6 +74,7 @@
(<span id="task-number-column-<?= $column['id'] ?>"><?= $column['nb_tasks'] ?></span>)
</span>
<?php endif ?>
+ <?= $this->hook->render('template:board:column:header', array('swimlane' => $swimlane, 'column' => $column)) ?>
</div>
</th>
diff --git a/app/Template/board/task_footer.php b/app/Template/board/task_footer.php
index 83a582c6..15f1f713 100644
--- a/app/Template/board/task_footer.php
+++ b/app/Template/board/task_footer.php
@@ -10,7 +10,7 @@
'edit',
array('task_id' => $task['id'], 'project_id' => $task['project_id']),
false,
- 'popover' . (! empty($task['category_description']) ? ' tooltip' : ''),
+ 'js-modal-medium' . (! empty($task['category_description']) ? ' tooltip' : ''),
! empty($task['category_description']) ? $this->text->markdownAttribute($task['category_description']) : t('Change category')
) ?>
<?php endif ?>
diff --git a/app/Template/board/tooltip_files.php b/app/Template/board/tooltip_files.php
index 4e704dac..5cb72741 100644
--- a/app/Template/board/tooltip_files.php
+++ b/app/Template/board/tooltip_files.php
@@ -9,9 +9,9 @@
</tr>
<tr>
<td>
- <i class="fa fa-download fa-fw"></i><?= $this->url->link(t('download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->icon('download', t('download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
<?php if ($file['is_image'] == 1): ?>
- &nbsp;<i class="fa fa-eye"></i> <?= $this->url->link(t('open file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ &nbsp;<?= $this->modal->large('eye', t('open file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
<?php endif ?>
</td>
</tr>
diff --git a/app/Template/board_popover/close_all_tasks_column.php b/app/Template/board_popover/close_all_tasks_column.php
index 57f703e3..ab7c2d47 100644
--- a/app/Template/board_popover/close_all_tasks_column.php
+++ b/app/Template/board_popover/close_all_tasks_column.php
@@ -1,18 +1,15 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('Do you really want to close all tasks of this column?') ?></h2>
- </div>
- <form method="post" action="<?= $this->url->href('BoardPopoverController', 'closeColumnTasks', array('project_id' => $project['id'])) ?>">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('column_id', $values) ?>
- <?= $this->form->hidden('swimlane_id', $values) ?>
+<div class="page-header">
+ <h2><?= t('Do you really want to close all tasks of this column?') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('BoardPopoverController', 'closeColumnTasks', array('project_id' => $project['id'])) ?>">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('column_id', $values) ?>
+ <?= $this->form->hidden('swimlane_id', $values) ?>
- <p class="alert"><?= t('%d task(s) in the column "%s" and the swimlane "%s" will be closed.', $nb_tasks, $column, $swimlane) ?></p>
+ <p class="alert"><?= t('%d task(s) in the column "%s" and the swimlane "%s" will be closed.', $nb_tasks, $column, $swimlane) ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-red"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
- </form>
-</section>
+ <?= $this->modal->submitButtons(array(
+ 'submitLabel' => t('Yes'),
+ 'color' => 'red',
+ )) ?>
+</form>
diff --git a/app/Template/category/edit.php b/app/Template/category/edit.php
index d8ca313d..108826f3 100644
--- a/app/Template/category/edit.php
+++ b/app/Template/category/edit.php
@@ -2,8 +2,7 @@
<h2><?= t('Category modification for the project "%s"', $project['name']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('CategoryController', 'update', array('project_id' => $project['id'], 'category_id' => $values['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('CategoryController', 'update', array('project_id' => $project['id'], 'category_id' => $values['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -15,9 +14,5 @@
<?= $this->form->label(t('Description'), 'description') ?>
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'CategoryController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/category/index.php b/app/Template/category/index.php
index 336b79a2..e93138fd 100644
--- a/app/Template/category/index.php
+++ b/app/Template/category/index.php
@@ -15,12 +15,10 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'CategoryController', 'edit', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'CategoryController', 'edit', array('project_id' => $project['id'], 'category_id' => $category_id)) ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'CategoryController', 'confirm', array('project_id' => $project['id'], 'category_id' => $category_id), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'CategoryController', 'confirm', array('project_id' => $project['id'], 'category_id' => $category_id)) ?>
</li>
</ul>
</div>
diff --git a/app/Template/category/remove.php b/app/Template/category/remove.php
index e7b9c9b4..79e8a560 100644
--- a/app/Template/category/remove.php
+++ b/app/Template/category/remove.php
@@ -1,17 +1,15 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('Remove a category') ?></h2>
- </div>
+<div class="page-header">
+ <h2><?= t('Remove a category') ?></h2>
+</div>
- <div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to remove this category: "%s"?', $category['name']) ?>
- </p>
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this category: "%s"?', $category['name']) ?>
+ </p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'CategoryController', 'remove', array('project_id' => $project['id'], 'category_id' => $category['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'CategoryController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
- </div>
-</section>
+ <?= $this->modal->confirmButtons(
+ 'CategoryController',
+ 'remove',
+ array('project_id' => $project['id'], 'category_id' => $category['id'])
+ ) ?>
+</div>
diff --git a/app/Template/column/create.php b/app/Template/column/create.php
index f4cded52..aad9606b 100644
--- a/app/Template/column/create.php
+++ b/app/Template/column/create.php
@@ -1,8 +1,7 @@
<div class="page-header">
<h2><?= t('Add a new column') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ColumnController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('ColumnController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -18,9 +17,5 @@
<?= $this->form->label(t('Description'), 'description') ?>
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 4)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="5"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'column', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/column/edit.php b/app/Template/column/edit.php
index a72a5c84..e590b5cc 100644
--- a/app/Template/column/edit.php
+++ b/app/Template/column/edit.php
@@ -2,8 +2,7 @@
<h2><?= t('Edit column "%s"', $column['title']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ColumnController', 'update', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('ColumnController', 'update', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -20,9 +19,5 @@
<?= $this->form->label(t('Description'), 'description') ?>
<?= $this->form->textEditor('description', $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ColumnController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/column/index.php b/app/Template/column/index.php
index 8c96a350..eaaae332 100644
--- a/app/Template/column/index.php
+++ b/app/Template/column/index.php
@@ -2,8 +2,7 @@
<h2><?= t('Edit the board for "%s"', $project['name']) ?></h2>
<ul>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new column'), 'ColumnController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new column'), 'ColumnController', 'create', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
@@ -17,7 +16,8 @@
<thead>
<tr>
<th class="column-70"><?= t('Column title') ?></th>
- <th class="column-25"><?= t('Task limit') ?></th>
+ <th class="column-10"><?= t('Task limit') ?></th>
+ <th class="column-20"><?= t('Visible on dashboard') ?></th>
<th class="column-5"><?= t('Actions') ?></th>
</tr>
</thead>
@@ -37,16 +37,17 @@
<?= $this->text->e($column['task_limit']) ?>
</td>
<td>
+ <?= $column['hide_in_dashboard'] == 1 ? t('Yes') : t('No') ?>
+ </td>
+ <td>
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'ColumnController', 'edit', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ColumnController', 'confirm', array('project_id' => $project['id'], 'column_id' => $column['id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/column/remove.php b/app/Template/column/remove.php
index dc0a4712..4134b175 100644
--- a/app/Template/column/remove.php
+++ b/app/Template/column/remove.php
@@ -8,8 +8,9 @@
<?= t('This action will REMOVE ALL TASKS associated to this column!') ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ColumnController', 'remove', array('project_id' => $project['id'], 'column_id' => $column['id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ColumnController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ColumnController',
+ 'remove',
+ array('project_id' => $project['id'], 'column_id' => $column['id'])
+ ) ?>
</div>
diff --git a/app/Template/column_move_restriction/create.php b/app/Template/column_move_restriction/create.php
index 1eb6d539..852df971 100644
--- a/app/Template/column_move_restriction/create.php
+++ b/app/Template/column_move_restriction/create.php
@@ -1,24 +1,18 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('New drag and drop restriction for the role "%s"', $role['role']) ?></h2>
- </div>
- <form class="popover-form" method="post" action="<?= $this->url->href('ColumnMoveRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('project_id', $values) ?>
- <?= $this->form->hidden('role_id', $values) ?>
+<div class="page-header">
+ <h2><?= t('New drag and drop restriction for the role "%s"', $role['role']) ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('ColumnMoveRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('project_id', $values) ?>
+ <?= $this->form->hidden('role_id', $values) ?>
- <?= $this->form->label(t('Source column'), 'src_column_id') ?>
- <?= $this->form->select('src_column_id', $columns, $values, $errors) ?>
+ <?= $this->form->label(t('Source column'), 'src_column_id') ?>
+ <?= $this->form->select('src_column_id', $columns, $values, $errors) ?>
- <?= $this->form->label(t('Destination column'), 'dst_column_id') ?>
- <?= $this->form->select('dst_column_id', $columns, $values, $errors) ?>
+ <?= $this->form->label(t('Destination column'), 'dst_column_id') ?>
+ <?= $this->form->select('dst_column_id', $columns, $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
- <p class="alert alert-info"><?= t('People belonging to this role will be able to move tasks only between the source and the destination column.') ?></p>
- </form>
-</section>
+ <p class="alert alert-info"><?= t('People belonging to this role will be able to move tasks only between the source and the destination column.') ?></p>
+</form>
diff --git a/app/Template/column_move_restriction/remove.php b/app/Template/column_move_restriction/remove.php
index 1985e167..4902cd23 100644
--- a/app/Template/column_move_restriction/remove.php
+++ b/app/Template/column_move_restriction/remove.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to remove this column restriction: "%s" to "%s"?', $restriction['src_column_title'], $restriction['dst_column_title']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ColumnMoveRestrictionController', 'remove', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ColumnMoveRestrictionController',
+ 'remove',
+ array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])
+ ) ?>
</div>
diff --git a/app/Template/column_restriction/create.php b/app/Template/column_restriction/create.php
index 982733b4..be158f19 100644
--- a/app/Template/column_restriction/create.php
+++ b/app/Template/column_restriction/create.php
@@ -1,22 +1,16 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('New column restriction for the role "%s"', $role['role']) ?></h2>
- </div>
- <form class="popover-form" method="post" action="<?= $this->url->href('ColumnRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('project_id', $values) ?>
- <?= $this->form->hidden('role_id', $values) ?>
+<div class="page-header">
+ <h2><?= t('New column restriction for the role "%s"', $role['role']) ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('ColumnRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('project_id', $values) ?>
+ <?= $this->form->hidden('role_id', $values) ?>
- <?= $this->form->label(t('Rule'), 'rule') ?>
- <?= $this->form->select('rule', $rules, $values, $errors) ?>
+ <?= $this->form->label(t('Rule'), 'rule') ?>
+ <?= $this->form->select('rule', $rules, $values, $errors) ?>
- <?= $this->form->label(t('Column'), 'column_id') ?>
- <?= $this->form->select('column_id', $columns, $values, $errors) ?>
+ <?= $this->form->label(t('Column'), 'column_id') ?>
+ <?= $this->form->select('column_id', $columns, $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
- </div>
- </form>
-</section>
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/column_restriction/remove.php b/app/Template/column_restriction/remove.php
index 97650e2d..edbd9d6e 100644
--- a/app/Template/column_restriction/remove.php
+++ b/app/Template/column_restriction/remove.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to remove this column restriction?') ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ColumnRestrictionController', 'remove', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ColumnRestrictionController',
+ 'remove',
+ array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])
+ ) ?>
</div>
diff --git a/app/Template/comment/create.php b/app/Template/comment/create.php
index 02cb48eb..8a421759 100644
--- a/app/Template/comment/create.php
+++ b/app/Template/comment/create.php
@@ -1,16 +1,12 @@
<div class="page-header">
<h2><?= t('Add a comment') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('CommentController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CommentController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?>
<?= $this->form->textEditor('comment', $values, $errors, array('autofocus' => true, 'required' => true)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/comment/edit.php b/app/Template/comment/edit.php
index f295c8a7..04f6ffd4 100644
--- a/app/Template/comment/edit.php
+++ b/app/Template/comment/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Edit a comment') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('CommentController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('CommentController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('task_id', $values) ?>
@@ -10,9 +10,5 @@
<?= $this->form->textEditor('comment', $values, $errors, array('autofocus' => true, 'required' => true)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/comment/remove.php b/app/Template/comment/remove.php
index 55587b67..03f16e00 100644
--- a/app/Template/comment/remove.php
+++ b/app/Template/comment/remove.php
@@ -13,9 +13,9 @@
'hide_actions' => true
)) ?>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'CommentController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'CommentController',
+ 'remove',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])
+ ) ?>
</div>
diff --git a/app/Template/comment/show.php b/app/Template/comment/show.php
index 16a807bc..f8d9607e 100644
--- a/app/Template/comment/show.php
+++ b/app/Template/comment/show.php
@@ -7,7 +7,9 @@
<strong class="comment-username"><?= $this->text->e($comment['name'] ?: $comment['username']) ?></strong>
<?php endif ?>
- <small class="comment-date"><?= $this->dt->datetime($comment['date_creation']) ?></small>
+ <small class="comment-date"><?= t('Created at:') ?> <?= $this->dt->datetime($comment['date_creation']) ?></small>
+ <small class="comment-date"><?= t('Updated at:')?> <?= $this->dt->datetime($comment['date_modification']) ?></small>
+
</div>
<div class="comment-content">
@@ -25,12 +27,10 @@
</li>
<?php if ($editable && ($this->user->isAdmin() || $this->user->isCurrentUser($comment['user_id']))): ?>
<li>
- <i class="fa fa-remove fa-fw"></i>
- <?= $this->url->link(t('remove'), 'CommentController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('edit'), 'CommentController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>
</li>
<li>
- <i class="fa fa-edit fa-fw"></i>
- <?= $this->url->link(t('edit'), 'CommentController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('remove'), 'CommentController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'comment_id' => $comment['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/comments/show.php b/app/Template/comments/show.php
index dfc13821..3edf7076 100644
--- a/app/Template/comments/show.php
+++ b/app/Template/comments/show.php
@@ -6,8 +6,7 @@
<?php if (!isset($is_public) || !$is_public): ?>
<div class="comment-sorting">
<small>
- <i class="fa fa-sort"></i>
- <?= $this->url->link(t('change sorting'), 'CommentController', 'toggleSorting', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('sort', t('change sorting'), 'CommentController', 'toggleSorting', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</small>
</div>
<?php endif ?>
diff --git a/app/Template/config/about.php b/app/Template/config/about.php
index 8d5a575d..3f078c3d 100644
--- a/app/Template/config/about.php
+++ b/app/Template/config/about.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('About') ?></h2>
</div>
-<div class="listing">
+<div class="panel">
<ul>
<li>
<?= t('Official website:') ?>
@@ -21,7 +21,7 @@
<div class="page-header">
<h2><?= t('Configuration') ?></h2>
</div>
-<div class="listing">
+<div class="panel">
<ul>
<li>
<?= t('Application version:') ?>
@@ -58,7 +58,7 @@
<div class="page-header">
<h2><?= t('Database') ?></h2>
</div>
- <div class="listing">
+ <div class="panel">
<ul>
<li>
<?= t('Database size:') ?>
@@ -81,6 +81,6 @@
<div class="page-header">
<h2><?= t('License') ?></h2>
</div>
-<div class="listing">
+<div class="panel">
<?= nl2br(file_get_contents(ROOT_DIR.DIRECTORY_SEPARATOR.'LICENSE')) ?>
</div>
diff --git a/app/Template/config/api.php b/app/Template/config/api.php
index 95f77355..9a3b06ce 100644
--- a/app/Template/config/api.php
+++ b/app/Template/config/api.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('API') ?></h2>
</div>
-<section class="listing">
+<div class="panel">
<ul>
<li>
<?= t('API token:') ?>
@@ -9,10 +9,10 @@
</li>
<li>
<?= t('API endpoint:') ?>
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().'jsonrpc.php' ?>">
- </li>
- <li>
- <?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'api'), true) ?>
+ <strong><?= $this->url->base().'jsonrpc.php' ?></strong>
</li>
</ul>
-</section>
+</div>
+
+<?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'api'), true, 'btn btn-red') ?>
+
diff --git a/app/Template/config/application.php b/app/Template/config/application.php
index 0f842f6e..d3d8c858 100644
--- a/app/Template/config/application.php
+++ b/app/Template/config/application.php
@@ -2,33 +2,35 @@
<h2><?= t('Application settings') ?></h2>
</div>
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'application')) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Application URL'), 'application_url') ?>
- <?= $this->form->text('application_url', $values, $errors, array('placeholder="http://example.kanboard.net/"')) ?>
- <p class="form-help"><?= t('Example: http://example.kanboard.net/ (used to generate absolute URLs)') ?></p>
-
- <?= $this->form->label(t('Language'), 'application_language') ?>
- <?= $this->form->select('application_language', $languages, $values, $errors) ?>
+ <fieldset>
+ <?= $this->form->label(t('Application URL'), 'application_url') ?>
+ <?= $this->form->text('application_url', $values, $errors, array('placeholder="http://example.kanboard.net/"')) ?>
+ <p class="form-help"><?= t('Example: http://example.kanboard.net/ (used to generate absolute URLs)') ?></p>
- <?= $this->form->label(t('Timezone'), 'application_timezone') ?>
- <?= $this->form->select('application_timezone', $timezones, $values, $errors) ?>
+ <?= $this->form->label(t('Language'), 'application_language') ?>
+ <?= $this->form->select('application_language', $languages, $values, $errors) ?>
- <?= $this->form->label(t('Date format'), 'application_date_format') ?>
- <?= $this->form->select('application_date_format', $date_formats, $values, $errors) ?>
- <p class="form-help"><?= t('ISO format is always accepted, example: "%s" and "%s"', date('Y-m-d'), date('Y_m_d')) ?></p>
+ <?= $this->form->checkbox('password_reset', t('Enable "Forget Password"'), 1, $values['password_reset'] == 1) ?>
+ </fieldset>
- <?= $this->form->label(t('Date and time format'), 'application_datetime_format') ?>
- <?= $this->form->select('application_datetime_format', $datetime_formats, $values, $errors) ?>
+ <fieldset>
+ <?= $this->form->label(t('Timezone'), 'application_timezone') ?>
+ <?= $this->form->select('application_timezone', $timezones, $values, $errors) ?>
- <?= $this->form->label(t('Time format'), 'application_time_format') ?>
- <?= $this->form->select('application_time_format', $time_formats, $values, $errors) ?>
+ <?= $this->form->label(t('Date format'), 'application_date_format') ?>
+ <?= $this->form->select('application_date_format', $date_formats, $values, $errors) ?>
+ <p class="form-help"><?= t('ISO format is always accepted, example: "%s" and "%s"', date('Y-m-d'), date('Y_m_d')) ?></p>
- <?= $this->form->checkbox('password_reset', t('Enable "Forget Password"'), 1, $values['password_reset'] == 1) ?>
+ <?= $this->form->label(t('Time format'), 'application_time_format') ?>
+ <?= $this->form->select('application_time_format', $time_formats, $values, $errors) ?>
+ </fieldset>
- <?= $this->form->label(t('Custom Stylesheet'), 'application_stylesheet') ?>
- <?= $this->form->textarea('application_stylesheet', $values, $errors) ?>
+ <fieldset>
+ <?= $this->form->label(t('Custom Stylesheet'), 'application_stylesheet') ?>
+ <?= $this->form->textarea('application_stylesheet', $values, $errors) ?>
+ </fieldset>
<?= $this->hook->render('template:config:application', array('values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Template/config/board.php b/app/Template/config/board.php
index 62a736e7..35058f0f 100644
--- a/app/Template/config/board.php
+++ b/app/Template/config/board.php
@@ -2,20 +2,21 @@
<h2><?= t('Board settings') ?></h2>
</div>
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'board')) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Task highlight period'), 'board_highlight_period') ?>
- <?= $this->form->number('board_highlight_period', $values, $errors) ?>
- <p class="form-help"><?= t('Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)') ?></p>
+ <fieldset>
+ <?= $this->form->label(t('Task highlight period'), 'board_highlight_period') ?>
+ <?= $this->form->number('board_highlight_period', $values, $errors) ?>
+ <p class="form-help"><?= t('Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)') ?></p>
- <?= $this->form->label(t('Refresh interval for public board'), 'board_public_refresh_interval') ?>
- <?= $this->form->number('board_public_refresh_interval', $values, $errors) ?>
- <p class="form-help"><?= t('Frequency in second (60 seconds by default)') ?></p>
+ <?= $this->form->label(t('Refresh interval for public board'), 'board_public_refresh_interval') ?>
+ <?= $this->form->number('board_public_refresh_interval', $values, $errors) ?>
+ <p class="form-help"><?= t('Frequency in second (60 seconds by default)') ?></p>
- <?= $this->form->label(t('Refresh interval for private board'), 'board_private_refresh_interval') ?>
- <?= $this->form->number('board_private_refresh_interval', $values, $errors) ?>
- <p class="form-help"><?= t('Frequency in second (0 to disable this feature, 10 seconds by default)') ?></p>
+ <?= $this->form->label(t('Refresh interval for private board'), 'board_private_refresh_interval') ?>
+ <?= $this->form->number('board_private_refresh_interval', $values, $errors) ?>
+ <p class="form-help"><?= t('Frequency in second (0 to disable this feature, 10 seconds by default)') ?></p>
+ </fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
diff --git a/app/Template/config/calendar.php b/app/Template/config/calendar.php
index 90e034e9..0cc3d064 100644
--- a/app/Template/config/calendar.php
+++ b/app/Template/config/calendar.php
@@ -1,34 +1,36 @@
<div class="page-header">
<h2><?= t('Calendar settings') ?></h2>
</div>
-<section>
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'calendar')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
- <div class="listing">
- <h3><?= t('Project calendar view') ?></h3>
+ <fieldset>
+ <legend><?= t('Project calendar view') ?></legend>
<?= $this->form->radios('calendar_project_tasks', array(
'date_creation' => t('Show tasks based on the creation date'),
'date_started' => t('Show tasks based on the start date'),
- ), $values) ?>
- </div>
+ ),
+ $values
+ ) ?>
+ </fieldset>
- <div class="listing">
- <h3><?= t('User calendar view') ?></h3>
+ <fieldset>
+ <legend><?= t('User calendar view') ?></legend>
<?= $this->form->radios('calendar_user_tasks', array(
'date_creation' => t('Show tasks based on the creation date'),
'date_started' => t('Show tasks based on the start date'),
- ), $values) ?>
- </div>
+ ),
+ $values
+ ) ?>
+ </fieldset>
- <div class="listing">
- <h3><?= t('Subtasks time tracking') ?></h3>
+ <fieldset>
+ <legend><?= t('Subtasks time tracking') ?></legend>
<?= $this->form->checkbox('calendar_user_subtasks_time_tracking', t('Show subtasks based on the time tracking'), 1, $values['calendar_user_subtasks_time_tracking'] == 1) ?>
- </div>
+ </fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
</form>
-</section>
diff --git a/app/Template/config/email.php b/app/Template/config/email.php
index 6ff76eca..bc2c2ae5 100644
--- a/app/Template/config/email.php
+++ b/app/Template/config/email.php
@@ -4,11 +4,14 @@
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'email')) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Email sender address'), 'mail_sender_address') ?>
- <?= $this->form->text('mail_sender_address', $values, $errors, array('placeholder="'.MAIL_FROM.'"')) ?>
+ <fieldset>
+ <legend><?= t('Outgoing Emails') ?></legend>
+ <?= $this->form->label(t('Email sender address'), 'mail_sender_address') ?>
+ <?= $this->form->text('mail_sender_address', $values, $errors, array('placeholder="'.MAIL_FROM.'"')) ?>
- <?= $this->form->label(t('Email transport'), 'mail_transport') ?>
- <?= $this->form->select('mail_transport', $mail_transports, $values, $errors) ?>
+ <?= $this->form->label(t('Email transport'), 'mail_transport') ?>
+ <?= $this->form->select('mail_transport', $mail_transports, $values, $errors) ?>
+ </fieldset>
<?= $this->hook->render('template:config:email', array('values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php
index 3ba4e865..07a90ce2 100644
--- a/app/Template/config/integrations.php
+++ b/app/Template/config/integrations.php
@@ -7,11 +7,11 @@
<?= $this->hook->render('template:config:integrations', array('values' => $values)) ?>
<h3><img src="<?= $this->url->dir() ?>assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
- <div class="listing">
+ <div class="panel">
<?= $this->form->checkbox('integration_gravatar', t('Enable Gravatar images'), 1, $values['integration_gravatar'] == 1) ?>
+ <div class="form-actions">
+ <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
+ </div>
</div>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
</form>
diff --git a/app/Template/config/keyboard_shortcuts.php b/app/Template/config/keyboard_shortcuts.php
index 1b1a9477..6ac71ee0 100644
--- a/app/Template/config/keyboard_shortcuts.php
+++ b/app/Template/config/keyboard_shortcuts.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Keyboard shortcuts') ?></h2>
</div>
-<div class="listing">
+<div class="panel">
<h3><?= t('Board/Calendar/List view') ?></h3>
<ul>
<li><?= t('Switch to the project overview') ?> = <strong>v o</strong></li>
diff --git a/app/Template/config/project.php b/app/Template/config/project.php
index 6d8d131a..514a9baa 100644
--- a/app/Template/config/project.php
+++ b/app/Template/config/project.php
@@ -2,24 +2,27 @@
<h2><?= t('Project settings') ?></h2>
</div>
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'project')) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Default task color'), 'default_color') ?>
- <?= $this->form->select('default_color', $colors, $values, $errors) ?>
+ <fieldset>
+ <?= $this->form->label(t('Default task color'), 'default_color') ?>
+ <?= $this->form->select('default_color', $colors, $values, $errors) ?>
- <?= $this->form->label(t('Default columns for new projects (Comma-separated)'), 'board_columns') ?>
- <?= $this->form->text('board_columns', $values, $errors) ?>
- <p class="form-help"><?= t('Default values are "%s"', $default_columns) ?></p>
+ <?= $this->form->label(t('Default columns for new projects (Comma-separated)'), 'board_columns') ?>
+ <?= $this->form->text('board_columns', $values, $errors) ?>
+ <p class="form-help"><?= t('Default values are "%s"', $default_columns) ?></p>
- <?= $this->form->label(t('Default categories for new projects (Comma-separated)'), 'project_categories') ?>
- <?= $this->form->text('project_categories', $values, $errors) ?>
- <p class="form-help"><?= t('Example: "Bug, Feature Request, Improvement"') ?></p>
+ <?= $this->form->label(t('Default categories for new projects (Comma-separated)'), 'project_categories') ?>
+ <?= $this->form->text('project_categories', $values, $errors) ?>
+ <p class="form-help"><?= t('Example: "Bug, Feature Request, Improvement"') ?></p>
+ </fieldset>
- <?= $this->form->checkbox('disable_private_project', t('Disable private projects'), 1, isset($values['disable_private_project']) && $values['disable_private_project'] == 1) ?>
- <?= $this->form->checkbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?>
- <?= $this->form->checkbox('subtask_time_tracking', t('Trigger automatically subtask time tracking'), 1, $values['subtask_time_tracking'] == 1) ?>
- <?= $this->form->checkbox('cfd_include_closed_tasks', t('Include closed tasks in the cumulative flow diagram'), 1, $values['cfd_include_closed_tasks'] == 1) ?>
+ <fieldset>
+ <?= $this->form->checkbox('disable_private_project', t('Disable private projects'), 1, isset($values['disable_private_project']) && $values['disable_private_project'] == 1) ?>
+ <?= $this->form->checkbox('subtask_restriction', t('Allow only one subtask in progress at the same time for a user'), 1, $values['subtask_restriction'] == 1) ?>
+ <?= $this->form->checkbox('subtask_time_tracking', t('Trigger automatically subtask time tracking'), 1, $values['subtask_time_tracking'] == 1) ?>
+ <?= $this->form->checkbox('cfd_include_closed_tasks', t('Include closed tasks in the cumulative flow diagram'), 1, $values['cfd_include_closed_tasks'] == 1) ?>
+ </fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
diff --git a/app/Template/config/sidebar.php b/app/Template/config/sidebar.php
index 239edc19..95be963b 100644
--- a/app/Template/config/sidebar.php
+++ b/app/Template/config/sidebar.php
@@ -22,10 +22,10 @@
<?= $this->url->link(t('Tags management'), 'TagController', 'index') ?>
</li>
<li <?= $this->app->checkMenuSelection('LinkController') ?>>
- <?= $this->url->link(t('Link settings'), 'LinkController', 'index') ?>
+ <?= $this->url->link(t('Link labels'), 'LinkController', 'show') ?>
</li>
- <li <?= $this->app->checkMenuSelection('CurrencyController', 'index') ?>>
- <?= $this->url->link(t('Currency rates'), 'CurrencyController', 'index') ?>
+ <li <?= $this->app->checkMenuSelection('CurrencyController') ?>>
+ <?= $this->url->link(t('Currency rates'), 'CurrencyController', 'show') ?>
</li>
<li <?= $this->app->checkMenuSelection('ConfigController', 'integrations') ?>>
<?= $this->url->link(t('Integrations'), 'ConfigController', 'integrations') ?>
diff --git a/app/Template/config/webhook.php b/app/Template/config/webhook.php
index e3245873..bc4bbfdf 100644
--- a/app/Template/config/webhook.php
+++ b/app/Template/config/webhook.php
@@ -1,9 +1,7 @@
<div class="page-header">
<h2><?= t('Webhook settings') ?></h2>
</div>
-<section>
<form method="post" action="<?= $this->url->href('ConfigController', 'save', array('redirect' => 'webhook')) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Webhook URL'), 'webhook_url') ?>
@@ -13,19 +11,13 @@
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
</div>
</form>
-</section>
-<div class="page-header">
+<div class="page-header margin-top">
<h2><?= t('Webhook token') ?></h2>
</div>
-<section class="listing">
- <ul>
- <li>
- <?= t('Webhook token:') ?>
- <strong><?= $this->text->e($values['webhook_token']) ?></strong>
- </li>
- <li>
- <?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'webhook'), true) ?>
- </li>
- </ul>
-</section>
+<div class="panel">
+ <?= t('Webhook token:') ?>
+ <strong><?= $this->text->e($values['webhook_token']) ?></strong>
+</div>
+
+<?= $this->url->link(t('Reset token'), 'ConfigController', 'token', array('type' => 'webhook'), true, 'btn btn-red') ?>
diff --git a/app/Template/currency/change.php b/app/Template/currency/change.php
new file mode 100644
index 00000000..59a7ce37
--- /dev/null
+++ b/app/Template/currency/change.php
@@ -0,0 +1,9 @@
+<div class="page-header">
+ <h2><?= t('Change reference currency') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('CurrencyController', 'update') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->label(t('Reference currency'), 'application_currency') ?>
+ <?= $this->form->select('application_currency', $currencies, $values, $errors) ?>
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/currency/create.php b/app/Template/currency/create.php
new file mode 100644
index 00000000..578ece81
--- /dev/null
+++ b/app/Template/currency/create.php
@@ -0,0 +1,11 @@
+<div class="page-header">
+ <h2><?= t('Add or change currency rate') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('CurrencyController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->label(t('Currency'), 'currency') ?>
+ <?= $this->form->select('currency', $currencies, $values, $errors) ?>
+ <?= $this->form->label(t('Rate'), 'rate') ?>
+ <?= $this->form->text('rate', $values, $errors, array('autofocus'), 'form-numeric') ?>
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/currency/index.php b/app/Template/currency/index.php
deleted file mode 100644
index db9b21af..00000000
--- a/app/Template/currency/index.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<div class="page-header">
- <h2><?= t('Currency rates') ?></h2>
-</div>
-
-<?php if (! empty($rates)): ?>
-
-<table class="table-striped">
- <tr>
- <th class="column-35"><?= t('Currency') ?></th>
- <th><?= t('Rate') ?></th>
- </tr>
- <?php foreach ($rates as $rate): ?>
- <tr>
- <td>
- <strong><?= $this->text->e($rate['currency']) ?></strong>
- </td>
- <td>
- <?= n($rate['rate']) ?>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-
-<hr/>
-<h3><?= t('Change reference currency') ?></h3>
-<?php endif ?>
-<form method="post" action="<?= $this->url->href('CurrencyController', 'reference') ?>" autocomplete="off">
-
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Reference currency'), 'application_currency') ?>
- <?= $this->form->select('application_currency', $currencies, $config_values, $errors) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
-
-<hr/>
-<h3><?= t('Add a new currency rate') ?></h3>
-<form method="post" action="<?= $this->url->href('CurrencyController', 'create') ?>" autocomplete="off">
-
- <?= $this->form->csrf() ?>
-
- <?= $this->form->label(t('Currency'), 'currency') ?>
- <?= $this->form->select('currency', $currencies, $values, $errors) ?>
-
- <?= $this->form->label(t('Rate'), 'rate') ?>
- <?= $this->form->text('rate', $values, $errors, array(), 'form-numeric') ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
diff --git a/app/Template/currency/show.php b/app/Template/currency/show.php
new file mode 100644
index 00000000..4b7f34bc
--- /dev/null
+++ b/app/Template/currency/show.php
@@ -0,0 +1,34 @@
+<div class="page-header">
+ <h2><?= t('Currency rates') ?></h2>
+ <ul>
+ <li>
+ <?= $this->modal->medium('plus', t('Add or change currency rate'), 'CurrencyController', 'create') ?>
+ </li>
+ <li>
+ <?= $this->modal->medium('edit', t('Change reference currency'), 'CurrencyController', 'change') ?>
+ </li>
+ </ul>
+</div>
+
+<div class="panel">
+ <strong><?= t('Reference currency: %s', $application_currency) ?></strong>
+</div>
+
+<?php if (! empty($rates)): ?>
+ <table class="table-striped">
+ <tr>
+ <th class="column-35"><?= t('Currency') ?></th>
+ <th><?= t('Rate') ?></th>
+ </tr>
+ <?php foreach ($rates as $rate): ?>
+ <tr>
+ <td>
+ <strong><?= $this->text->e($rate['currency']) ?></strong>
+ </td>
+ <td>
+ <?= n($rate['rate']) ?>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+<?php endif ?>
diff --git a/app/Template/custom_filter/add.php b/app/Template/custom_filter/create.php
index 3801cc30..24e896ee 100644
--- a/app/Template/custom_filter/add.php
+++ b/app/Template/custom_filter/create.php
@@ -2,23 +2,20 @@
<h2><?= t('Add a new filter') ?></h2>
</div>
<form method="post" action="<?= $this->url->href('CustomFilterController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('required', 'maxlength="100"')) ?>
+ <?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
<?= $this->form->label(t('Filter'), 'filter') ?>
<?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?>
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<?= $this->form->checkbox('is_shared', t('Share with all project members'), 1) ?>
<?php endif ?>
<?= $this->form->checkbox('append', t('Append filter (instead of replacement)'), 1) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/custom_filter/edit.php b/app/Template/custom_filter/edit.php
index 26da8da2..b64dee53 100644
--- a/app/Template/custom_filter/edit.php
+++ b/app/Template/custom_filter/edit.php
@@ -2,8 +2,7 @@
<h2><?= t('Edit custom filter') ?></h2>
</div>
-<form class="form-popover" method="post" action="<?= $this->url->href('CustomFilterController', 'update', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('CustomFilterController', 'update', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -16,7 +15,7 @@
<?= $this->form->label(t('Filter'), 'filter') ?>
<?= $this->form->text('filter', $values, $errors, array('required', 'maxlength="100"')) ?>
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<?= $this->form->checkbox('is_shared', t('Share with all project members'), 1, $values['is_shared'] == 1) ?>
<?php else: ?>
<?= $this->form->hidden('is_shared', $values) ?>
@@ -24,9 +23,5 @@
<?= $this->form->checkbox('append', t('Append filter (instead of replacement)'), 1, $values['append'] == 1) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'CustomFilterController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/custom_filter/index.php b/app/Template/custom_filter/index.php
index dcab891b..9475c278 100644
--- a/app/Template/custom_filter/index.php
+++ b/app/Template/custom_filter/index.php
@@ -1,8 +1,12 @@
-<?php if (! empty($custom_filters)): ?>
<div class="page-header">
<h2><?= t('Custom filters') ?></h2>
+ <ul>
+ <li>
+ <?= $this->modal->medium('filter', t('Add custom filters'), 'CustomFilterController', 'create', array('project_id' => $project['id'])) ?>
+ </li>
+ </ul>
</div>
-<div>
+<?php if (! empty($custom_filters)): ?>
<table class="table-striped table-scrolling">
<tr>
<th class="column-15"><?= t('Name') ?></th>
@@ -36,8 +40,8 @@
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Remove'), 'CustomFilterController', 'confirm', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Edit'), 'CustomFilterController', 'edit', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id']), false, 'popover') ?></li>
+ <li><?= $this->modal->medium('edit', t('Edit'), 'CustomFilterController', 'edit', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?></li>
+ <li><?= $this->modal->confirm('trash-o', t('Remove'), 'CustomFilterController', 'confirm', array('project_id' => $filter['project_id'], 'filter_id' => $filter['id'])) ?></li>
</ul>
</div>
<?php endif ?>
@@ -45,7 +49,7 @@
</tr>
<?php endforeach ?>
</table>
-</div>
+<?php else: ?>
+ <p class="alert"><?= t('There is no custom filter.') ?></p>
<?php endif ?>
-<?= $this->render('custom_filter/add', array('project' => $project, 'values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Template/custom_filter/remove.php b/app/Template/custom_filter/remove.php
index 609f19b2..1c576fa2 100644
--- a/app/Template/custom_filter/remove.php
+++ b/app/Template/custom_filter/remove.php
@@ -1,17 +1,15 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('Remove a custom filter') ?></h2>
- </div>
+<div class="page-header">
+ <h2><?= t('Remove a custom filter') ?></h2>
+</div>
- <div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to remove this custom filter: "%s"?', $filter['name']) ?>
- </p>
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this custom filter: "%s"?', $filter['name']) ?>
+ </p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'CustomFilterController', 'remove', array('project_id' => $project['id'], 'filter_id' => $filter['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'CustomFilterController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
- </div>
-</section>
+ <?= $this->modal->confirmButtons(
+ 'CustomFilterController',
+ 'remove',
+ array('project_id' => $project['id'], 'filter_id' => $filter['id'])
+ ) ?>
+</div>
diff --git a/app/Template/dashboard/layout.php b/app/Template/dashboard/layout.php
index 795537a6..15ab8a1a 100644
--- a/app/Template/dashboard/layout.php
+++ b/app/Template/dashboard/layout.php
@@ -3,23 +3,19 @@
<ul>
<?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('New project'), 'ProjectCreationController', 'create', array(), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
</li>
<?php endif ?>
<?php if ($this->app->config('disable_private_project', 0) == 0): ?>
<li>
- <i class="fa fa-lock fa-fw"></i>
- <?= $this->url->link(t('New private project'), 'ProjectCreationController', 'createPrivate', array(), false, 'popover') ?>
+ <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Search'), 'SearchController', 'index') ?>
+ <?= $this->url->icon('search', t('Search'), 'SearchController', 'index') ?>
</li>
<li>
- <i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Project management'), 'ProjectListController', 'show') ?>
+ <?= $this->url->icon('folder', t('Project management'), 'ProjectListController', 'show') ?>
</li>
</ul>
</div>
diff --git a/app/Template/dashboard/notifications.php b/app/Template/dashboard/notifications.php
index 4fb59e24..81adb348 100644
--- a/app/Template/dashboard/notifications.php
+++ b/app/Template/dashboard/notifications.php
@@ -7,8 +7,7 @@
<?php else: ?>
<ul>
<li>
- <i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Mark all as read'), 'WebNotificationController', 'flush', array('user_id' => $user['id'])) ?>
+ <?= $this->url->icon('check-square-o', t('Mark all as read'), 'WebNotificationController', 'flush', array('user_id' => $user['id'])) ?>
</li>
</ul>
</div>
@@ -60,8 +59,7 @@
<?= $this->dt->datetime($notification['date_creation']) ?>
</td>
<td>
- <i class="fa fa-check fa-fw"></i>
- <?= $this->url->link(t('Mark as read'), 'WebNotificationController', 'remove', array('user_id' => $user['id'], 'notification_id' => $notification['id'])) ?>
+ <?= $this->url->icon('check', t('Mark as read'), 'WebNotificationController', 'remove', array('user_id' => $user['id'], 'notification_id' => $notification['id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/dashboard/show.php b/app/Template/dashboard/show.php
index aec6f591..b1d877cf 100644
--- a/app/Template/dashboard/show.php
+++ b/app/Template/dashboard/show.php
@@ -1,4 +1,4 @@
-<div class="filter-box">
+<div class="filter-box margin-bottom">
<form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', array('controller' => 'SearchController')) ?>
<?= $this->form->hidden('action', array('action' => 'index')) ?>
diff --git a/app/Template/doc/show.php b/app/Template/doc/show.php
index a8dbd762..879e45b6 100644
--- a/app/Template/doc/show.php
+++ b/app/Template/doc/show.php
@@ -2,8 +2,7 @@
<div class="page-header">
<ul>
<li>
- <i class="fa fa-life-ring fa-fw"></i>
- <?= $this->url->link(t('Table of contents'), 'DocumentationController', 'show', array('file' => 'index')) ?>
+ <?= $this->url->icon('life-ring', t('Table of contents'), 'DocumentationController', 'show', array('file' => 'index')) ?>
</li>
</ul>
</div>
diff --git a/app/Template/export/header.php b/app/Template/export/header.php
new file mode 100644
index 00000000..35591352
--- /dev/null
+++ b/app/Template/export/header.php
@@ -0,0 +1,17 @@
+<div class="page-header">
+ <h2><?= $this->text->e($project['name']) ?> &gt; <?= $title ?></h2>
+ <ul>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'tasks') ?>>
+ <?= $this->modal->replaceLink(t('Tasks'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'subtasks') ?>>
+ <?= $this->modal->replaceLink(t('Subtasks'), 'ExportController', 'subtasks', array('project_id' => $project['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'transitions') ?>>
+ <?= $this->modal->replaceLink(t('Task transitions'), 'ExportController', 'transitions', array('project_id' => $project['id'])) ?>
+ </li>
+ <li <?= $this->app->checkMenuSelection('ExportController', 'summary') ?>>
+ <?= $this->modal->replaceLink(t('Daily project summary'), 'ExportController', 'summary', array('project_id' => $project['id'])) ?>
+ </li>
+ </ul>
+</div>
diff --git a/app/Template/export/sidebar.php b/app/Template/export/sidebar.php
deleted file mode 100644
index 463c0cee..00000000
--- a/app/Template/export/sidebar.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="sidebar">
- <ul>
- <li <?= $this->app->checkMenuSelection('ExportController', 'tasks') ?>>
- <?= $this->url->link(t('Tasks'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('ExportController', 'subtasks') ?>>
- <?= $this->url->link(t('Subtasks'), 'ExportController', 'subtasks', array('project_id' => $project['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('ExportController', 'transitions') ?>>
- <?= $this->url->link(t('Task transitions'), 'ExportController', 'transitions', array('project_id' => $project['id'])) ?>
- </li>
- <li <?= $this->app->checkMenuSelection('ExportController', 'summary') ?>>
- <?= $this->url->link(t('Daily project summary'), 'ExportController', 'summary', array('project_id' => $project['id'])) ?>
- </li>
- <?= $this->hook->render('template:export:sidebar') ?>
- </ul>
-</div>
diff --git a/app/Template/export/subtasks.php b/app/Template/export/subtasks.php
index 959f0e47..0e47772b 100644
--- a/app/Template/export/subtasks.php
+++ b/app/Template/export/subtasks.php
@@ -1,20 +1,16 @@
-<div class="page-header">
- <h2><?= t('Subtasks export') ?></h2>
-</div>
+<?= $this->render('export/header', array('project' => $project, 'title' => $title)) ?>
<p class="alert alert-info"><?= t('This report contains all subtasks information for the given date range.') ?></p>
-<form method="get" action="?" autocomplete="off">
-
- <?= $this->form->hidden('controller', $values) ?>
- <?= $this->form->hidden('action', $values) ?>
+<form class="js-modal-ignore-form" method="post" action="<?= $this->url->href('ExportController', 'subtasks', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->date(t('Start date'), 'from', $values) ?>
<?= $this->form->date(t('End date'), 'to', $values) ?>
- <div class="form-help"><?= t('Others formats accepted: %s and %s', date('Y-m-d'), date('Y_m_d')) ?></div>
-
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
+ <button type="submit" class="btn btn-blue js-form-export"><?= t('Export') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'ExportController', 'subtasks', array('project_id' => $project['id']), false, 'js-modal-close') ?>
</div>
</form>
diff --git a/app/Template/export/summary.php b/app/Template/export/summary.php
index a7483fcb..7dc7482f 100644
--- a/app/Template/export/summary.php
+++ b/app/Template/export/summary.php
@@ -1,20 +1,16 @@
-<div class="page-header">
- <h2><?= t('Daily project summary export') ?></h2>
-</div>
+<?= $this->render('export/header', array('project' => $project, 'title' => $title)) ?>
<p class="alert alert-info"><?= t('This export contains the number of tasks per column grouped per day.') ?></p>
-<form method="get" action="?" autocomplete="off">
- <?= $this->form->hidden('controller', $values) ?>
- <?= $this->form->hidden('action', $values) ?>
+<form class="js-modal-ignore-form" method="post" action="<?= $this->url->href('ExportController', 'summary', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
-
<?= $this->form->date(t('Start date'), 'from', $values) ?>
<?= $this->form->date(t('End date'), 'to', $values) ?>
- <div class="form-help"><?= t('Others formats accepted: %s and %s', date('Y-m-d'), date('Y_m_d')) ?></div>
-
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
+ <button type="submit" class="btn btn-blue js-form-export"><?= t('Export') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'ExportController', 'summary', array('project_id' => $project['id']), false, 'js-modal-close') ?>
</div>
</form>
diff --git a/app/Template/export/tasks.php b/app/Template/export/tasks.php
index ce1c869e..232ff8eb 100644
--- a/app/Template/export/tasks.php
+++ b/app/Template/export/tasks.php
@@ -1,20 +1,16 @@
-<div class="page-header">
- <h2><?= t('Tasks exportation') ?></h2>
-</div>
+<?= $this->render('export/header', array('project' => $project, 'title' => $title)) ?>
<p class="alert alert-info"><?= t('This report contains all tasks information for the given date range.') ?></p>
-<form method="get" action="?" autocomplete="off">
- <?= $this->form->hidden('controller', $values) ?>
- <?= $this->form->hidden('action', $values) ?>
+<form class="js-modal-ignore-form" method="post" action="<?= $this->url->href('ExportController', 'tasks', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
-
<?= $this->form->date(t('Start date'), 'from', $values) ?>
<?= $this->form->date(t('End date'), 'to', $values) ?>
- <div class="form-help"><?= t('Others formats accepted: %s and %s', date('Y-m-d'), date('Y_m_d')) ?></div>
-
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
+ <button type="submit" class="btn btn-blue js-form-export"><?= t('Export') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'ExportController', 'tasks', array('project_id' => $project['id']), false, 'js-modal-close') ?>
</div>
</form>
diff --git a/app/Template/export/transitions.php b/app/Template/export/transitions.php
index 7cd355db..4f3749b8 100644
--- a/app/Template/export/transitions.php
+++ b/app/Template/export/transitions.php
@@ -1,21 +1,16 @@
-<div class="page-header">
- <h2><?= t('Task transitions export') ?></h2>
-</div>
+<?= $this->render('export/header', array('project' => $project, 'title' => $title)) ?>
<p class="alert alert-info"><?= t('This report contains all column moves for each task with the date, the user and the time spent for each transition.') ?></p>
-<form method="get" action="?" autocomplete="off">
-
- <?= $this->form->hidden('controller', $values) ?>
- <?= $this->form->hidden('action', $values) ?>
+<form class="js-modal-ignore-form" method="post" action="<?= $this->url->href('ExportController', 'transitions', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
-
<?= $this->form->date(t('Start date'), 'from', $values) ?>
<?= $this->form->date(t('End date'), 'to', $values) ?>
- <div class="form-help"><?= t('Others formats accepted: %s and %s', date('Y-m-d'), date('Y_m_d')) ?></div>
-
<div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
+ <button type="submit" class="btn btn-blue js-form-export"><?= t('Export') ?></button>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'ExportController', 'transitions', array('project_id' => $project['id']), false, 'js-modal-close') ?>
</div>
</form>
diff --git a/app/Template/external_task_creation/step1.php b/app/Template/external_task_creation/step1.php
index 2af9b427..2a3b0144 100644
--- a/app/Template/external_task_creation/step1.php
+++ b/app/Template/external_task_creation/step1.php
@@ -1,4 +1,4 @@
-<form class="popover-form" method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step2', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
+<form method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step2', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('swimlane_id', $values) ?>
<?= $this->form->hidden('column_id', $values) ?>
@@ -12,8 +12,5 @@
<div class="alert alert-error"><?= $this->text->e($error_message) ?></div>
<?php endif ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Next') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Next'))) ?>
</form>
diff --git a/app/Template/external_task_creation/step2.php b/app/Template/external_task_creation/step2.php
index 4bc0e509..baace3ae 100644
--- a/app/Template/external_task_creation/step2.php
+++ b/app/Template/external_task_creation/step2.php
@@ -1,4 +1,4 @@
-<form class="popover-form" method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step3', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
+<form method="post" action="<?= $this->url->href('ExternalTaskCreationController', 'step3', array('project_id' => $project['id'], 'provider_name' => $provider_name)) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('external_provider', $values) ?>
<?= $this->form->hidden('external_uri', $values) ?>
@@ -18,8 +18,5 @@
<div class="alert alert-error"><?= $this->text->e($error_message) ?></div>
<?php endif ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/external_task_modification/show.php b/app/Template/external_task_modification/show.php
index 79dd9556..55180b96 100644
--- a/app/Template/external_task_modification/show.php
+++ b/app/Template/external_task_modification/show.php
@@ -1,4 +1,4 @@
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskModificationController', 'update', array('task_id' => $task['id'], 'project_id' => $project['id'])) ?>">
+<form method="post" action="<?= $this->url->href('TaskModificationController', 'update', array('task_id' => $task['id'], 'project_id' => $project['id'])) ?>">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -18,9 +18,5 @@
)) ?>
<?php endif ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/group/associate.php b/app/Template/group/associate.php
index 24edd133..cd7f2b77 100644
--- a/app/Template/group/associate.php
+++ b/app/Template/group/associate.php
@@ -3,8 +3,11 @@
</div>
<?php if (empty($users)): ?>
<p class="alert"><?= t('There is no user available.') ?></p>
+ <div class="form-actions">
+ <?= $this->url->link(t('Close this window'), 'GroupListController', 'index', array(), false, 'btn js-modal-close') ?>
+ </div>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('GroupListController', 'addUser', array('group_id' => $group['id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('GroupListController', 'addUser', array('group_id' => $group['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('group_id', $values) ?>
@@ -12,13 +15,9 @@
<?= $this->app->component('select-dropdown-autocomplete', array(
'name' => 'user_id',
'items' => $users,
- 'defaultValue' => isset($values['user_id']) ? $values['user_id'] : null,
+ 'defaultValue' => isset($values['user_id']) ? $values['user_id'] : key($users),
)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/group/dissociate.php b/app/Template/group/dissociate.php
index 50ef6d61..24836397 100644
--- a/app/Template/group/dissociate.php
+++ b/app/Template/group/dissociate.php
@@ -4,9 +4,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove the user "%s" from the group "%s"?', $user['name'] ?: $user['username'], $group['name']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'GroupListController', 'removeUser', array('group_id' => $group['id'], 'user_id' => $user['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'GroupListController', 'users', array('group_id' => $group['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'GroupListController',
+ 'removeUser',
+ array('group_id' => $group['id'], 'user_id' => $user['id'])
+ ) ?>
</div>
diff --git a/app/Template/group/index.php b/app/Template/group/index.php
index fe8a07e7..fe3f398e 100644
--- a/app/Template/group/index.php
+++ b/app/Template/group/index.php
@@ -1,14 +1,14 @@
<section id="main">
<div class="page-header">
<ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'UserListController', 'show') ?></li>
- <li><i class="fa fa-user-plus fa-fw"></i><?= $this->url->link(t('New group'), 'GroupCreationController', 'show', array(), false, 'popover') ?></li>
+ <li><?= $this->url->icon('user', t('All users'), 'UserListController', 'show') ?></li>
+ <li><?= $this->modal->medium('user-plus', t('New group'), 'GroupCreationController', 'show') ?></li>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
<p class="alert"><?= t('There is no group.') ?></p>
<?php else: ?>
- <table class="table-small table-fixed table-scrolling">
+ <table class="table-fixed table-scrolling">
<tr>
<th class="column-5"><?= $paginator->order(t('Id'), 'id') ?></th>
<th class="column-20"><?= $paginator->order(t('External Id'), 'external_id') ?></th>
@@ -30,10 +30,10 @@
<div class="dropdown">
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
- <li><?= $this->url->link(t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Members'), 'GroupListController', 'users', array('group_id' => $group['id'])) ?></li>
- <li><?= $this->url->link(t('Edit'), 'GroupModificationController', 'show', array('group_id' => $group['id']), false, 'popover') ?></li>
- <li><?= $this->url->link(t('Remove'), 'GroupListController', 'confirm', array('group_id' => $group['id']), false, 'popover') ?></li>
+ <li><?= $this->modal->medium('plus', t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id'])) ?></li>
+ <li><?= $this->url->icon('users', t('Members'), 'GroupListController', 'users', array('group_id' => $group['id'])) ?></li>
+ <li><?= $this->modal->medium('edit', t('Edit'), 'GroupModificationController', 'show', array('group_id' => $group['id'])) ?></li>
+ <li><?= $this->modal->confirm('trash-o', t('Remove'), 'GroupListController', 'confirm', array('group_id' => $group['id'])) ?></li>
</ul>
</div>
</td>
diff --git a/app/Template/group/remove.php b/app/Template/group/remove.php
index 408b3d83..77d602f9 100644
--- a/app/Template/group/remove.php
+++ b/app/Template/group/remove.php
@@ -4,9 +4,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this group: "%s"?', $group['name']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'GroupListController', 'remove', array('group_id' => $group['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'GroupListController',
+ 'remove',
+ array('group_id' => $group['id'])
+ ) ?>
</div>
diff --git a/app/Template/group/users.php b/app/Template/group/users.php
index 73597b39..ef179674 100644
--- a/app/Template/group/users.php
+++ b/app/Template/group/users.php
@@ -1,8 +1,8 @@
<section id="main">
<div class="page-header">
<ul>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id']), false, 'popover') ?></li>
+ <li><?= $this->url->icon('users', t('View all groups'), 'GroupListController', 'index') ?></li>
+ <li><?= $this->modal->medium('plus', t('Add group member'), 'GroupListController', 'associate', array('group_id' => $group['id'])) ?></li>
</ul>
</div>
<?php if ($paginator->isEmpty()): ?>
@@ -31,8 +31,7 @@
<a href="mailto:<?= $this->text->e($user['email']) ?>"><?= $this->text->e($user['email']) ?></a>
</td>
<td>
- <i class="fa fa-times fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove this user'), 'GroupListController', 'dissociate', array('group_id' => $group['id'], 'user_id' => $user['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove this user'), 'GroupListController', 'dissociate', array('group_id' => $group['id'], 'user_id' => $user['id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/group_creation/show.php b/app/Template/group_creation/show.php
index b219bd70..9f4f5608 100644
--- a/app/Template/group_creation/show.php
+++ b/app/Template/group_creation/show.php
@@ -1,15 +1,11 @@
<div class="page-header">
<h2><?= t('New group') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('GroupCreationController', 'save') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('GroupCreationController', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/group_modification/show.php b/app/Template/group_modification/show.php
index ddf07369..df4ed01e 100644
--- a/app/Template/group_modification/show.php
+++ b/app/Template/group_modification/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit group') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('GroupModificationController', 'save') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('GroupModificationController', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -10,9 +10,5 @@
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="100"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'GroupListController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/header/creation_dropdown.php b/app/Template/header/creation_dropdown.php
index d3b9e7cb..9bdf5ad2 100644
--- a/app/Template/header/creation_dropdown.php
+++ b/app/Template/header/creation_dropdown.php
@@ -6,14 +6,13 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-plus fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<?php if ($has_project_creation_access): ?>
- <li><i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('New project'), 'ProjectCreationController', 'create', array(), false, 'popover') ?>
+ <li>
+ <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
</li>
<?php endif ?>
<?php if ($is_private_project_enabled): ?>
<li>
- <i class="fa fa-lock fa-fw"></i>
- <?= $this->url->link(t('New private project'), 'ProjectCreationController', 'createPrivate', array(), false, 'popover') ?>
+ <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
</li>
<?php endif ?>
<?= $this->hook->render('template:header:creation-dropdown') ?>
diff --git a/app/Template/header/user_dropdown.php b/app/Template/header/user_dropdown.php
index 49d08213..a74bdd52 100644
--- a/app/Template/header/user_dropdown.php
+++ b/app/Template/header/user_dropdown.php
@@ -3,46 +3,37 @@
<ul>
<li class="no-hover"><strong><?= $this->text->e($this->user->getFullname()) ?></strong></li>
<li>
- <i class="fa fa-tachometer fa-fw"></i>
- <?= $this->url->link(t('My dashboard'), 'DashboardController', 'show', array('user_id' => $this->user->getId())) ?>
+ <?= $this->url->icon('tachometer', t('My dashboard'), 'DashboardController', 'show', array('user_id' => $this->user->getId())) ?>
</li>
<li>
- <i class="fa fa-home fa-fw"></i>
- <?= $this->url->link(t('My profile'), 'UserViewController', 'show', array('user_id' => $this->user->getId())) ?>
+ <?= $this->url->icon('home', t('My profile'), 'UserViewController', 'show', array('user_id' => $this->user->getId())) ?>
</li>
<li>
- <i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Projects management'), 'ProjectListController', 'show') ?>
+ <?= $this->url->icon('folder', t('Projects management'), 'ProjectListController', 'show') ?>
</li>
<?php if ($this->user->hasAccess('UserListController', 'show')): ?>
<li>
- <i class="fa fa-user fa-fw"></i>
- <?= $this->url->link(t('Users management'), 'UserListController', 'show') ?>
+ <?= $this->url->icon('user', t('Users management'), 'UserListController', 'show') ?>
</li>
<li>
- <i class="fa fa-group fa-fw"></i>
- <?= $this->url->link(t('Groups management'), 'GroupListController', 'index') ?>
+ <?= $this->url->icon('group', t('Groups management'), 'GroupListController', 'index') ?>
</li>
<li>
- <i class="fa fa-cubes" aria-hidden="true"></i>
- <?= $this->url->link(t('Plugins'), 'PluginController', 'show') ?>
+ <?= $this->url->icon('cubes', t('Plugins'), 'PluginController', 'show') ?>
</li>
<li>
- <i class="fa fa-cog fa-fw"></i>
- <?= $this->url->link(t('Settings'), 'ConfigController', 'index') ?>
+ <?= $this->url->icon('cog', t('Settings'), 'ConfigController', 'index') ?>
</li>
<?php endif ?>
<?= $this->hook->render('template:header:dropdown') ?>
<li>
- <i class="fa fa-life-ring fa-fw"></i>
- <?= $this->url->link(t('Documentation'), 'DocumentationController', 'show') ?>
+ <?= $this->url->icon('life-ring', t('Documentation'), 'DocumentationController', 'show') ?>
</li>
<?php if (! DISABLE_LOGOUT): ?>
<li>
- <i class="fa fa-sign-out fa-fw"></i>
- <?= $this->url->link(t('Logout'), 'AuthController', 'logout') ?>
+ <?= $this->url->icon('sign-out', t('Logout'), 'AuthController', 'logout') ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/layout.php b/app/Template/layout.php
index 8c85ffc6..241b99df 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -53,6 +53,7 @@
>
<?php if (isset($no_layout) && $no_layout): ?>
+ <?= $this->app->flashMessage() ?>
<?= $content_for_layout ?>
<?php else: ?>
<?= $this->hook->render('template:layout:top') ?>
diff --git a/app/Template/link/create.php b/app/Template/link/create.php
index 23990604..37610a3b 100644
--- a/app/Template/link/create.php
+++ b/app/Template/link/create.php
@@ -1,18 +1,12 @@
<div class="page-header">
- <h2><?= t('Add a new link') ?></h2>
+ <h2><?= t('Add link label') ?></h2>
</div>
<form action="<?= $this->url->href('LinkController', 'save') ?>" method="post" autocomplete="off">
-
<?= $this->form->csrf() ?>
-
<?= $this->form->label(t('Label'), 'label') ?>
- <?= $this->form->text('label', $values, $errors, array('required')) ?>
-
+ <?= $this->form->text('label', $values, $errors, array('required', 'autofocus')) ?>
<?= $this->form->label(t('Opposite label'), 'opposite_label') ?>
<?= $this->form->text('opposite_label', $values, $errors) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/link/edit.php b/app/Template/link/edit.php
index cb4f29e2..4be56573 100644
--- a/app/Template/link/edit.php
+++ b/app/Template/link/edit.php
@@ -13,9 +13,5 @@
<?= $this->form->label(t('Opposite label'), 'opposite_id') ?>
<?= $this->form->select('opposite_id', $labels, $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'LinkController', 'index') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/link/index.php b/app/Template/link/index.php
deleted file mode 100644
index 70ead4a6..00000000
--- a/app/Template/link/index.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<div class="page-header">
- <h2><?= t('Link labels') ?></h2>
-</div>
-<?php if (! empty($links)): ?>
-<table class="table-striped table-scrolling">
- <tr>
- <th class="column-70"><?= t('Link labels') ?></th>
- <th><?= t('Actions') ?></th>
- </tr>
- <?php foreach ($links as $link): ?>
- <tr>
- <td>
- <strong><?= t($link['label']) ?></strong>
-
- <?php if (! empty($link['opposite_label'])): ?>
- | <?= t($link['opposite_label']) ?>
- <?php endif ?>
- </td>
- <td>
- <ul>
- <?= $this->url->link(t('Edit'), 'LinkController', 'edit', array('link_id' => $link['id'])) ?>
- <?= t('or') ?>
- <?= $this->url->link(t('Remove'), 'LinkController', 'confirm', array('link_id' => $link['id'])) ?>
- </ul>
- </td>
- </tr>
- <?php endforeach ?>
-</table>
-<?php else: ?>
- <?= t('There is no link.') ?>
-<?php endif ?>
-
-<?= $this->render('link/create', array('values' => $values, 'errors' => $errors)) ?>
diff --git a/app/Template/link/remove.php b/app/Template/link/remove.php
index b7fbef5e..e5ea2466 100644
--- a/app/Template/link/remove.php
+++ b/app/Template/link/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this link: "%s"?', $link['label']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'LinkController', 'remove', array('link_id' => $link['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'LinkController', 'index') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'LinkController',
+ 'remove',
+ array('link_id' => $link['id'])
+ ) ?>
</div>
diff --git a/app/Template/link/show.php b/app/Template/link/show.php
new file mode 100644
index 00000000..6aadd66b
--- /dev/null
+++ b/app/Template/link/show.php
@@ -0,0 +1,36 @@
+<div class="page-header">
+ <h2><?= t('Link labels') ?></h2>
+ <ul>
+ <li>
+ <?= $this->modal->medium('plus', t('Add link label'), 'LinkController', 'create') ?>
+ </li>
+ </ul>
+</div>
+<?php if (! empty($links)): ?>
+ <table class="table-striped table-scrolling">
+ <tr>
+ <th class="column-70"><?= t('Link labels') ?></th>
+ <th><?= t('Actions') ?></th>
+ </tr>
+ <?php foreach ($links as $link): ?>
+ <tr>
+ <td>
+ <strong><?= t($link['label']) ?></strong>
+
+ <?php if (! empty($link['opposite_label'])): ?>
+ | <?= t($link['opposite_label']) ?>
+ <?php endif ?>
+ </td>
+ <td>
+ <ul>
+ <?= $this->modal->medium('edit', t('Edit'), 'LinkController', 'edit', array('link_id' => $link['id'])) ?>
+ <?= t('or') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'LinkController', 'confirm', array('link_id' => $link['id'])) ?>
+ </ul>
+ </td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+<?php else: ?>
+ <?= t('There is no link.') ?>
+<?php endif ?>
diff --git a/app/Template/plugin/directory.php b/app/Template/plugin/directory.php
index b6c6734c..b2fffcb9 100644
--- a/app/Template/plugin/directory.php
+++ b/app/Template/plugin/directory.php
@@ -28,11 +28,9 @@
<td>
<?php if ($is_configured): ?>
<?php if (! isset($installed_plugins[$plugin['title']])): ?>
- <i class="fa fa-cloud-download fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Install'), 'PluginController', 'install', array('archive_url' => urlencode($plugin['download'])), true) ?>
+ <?= $this->url->icon('cloud-download', t('Install'), 'PluginController', 'install', array('archive_url' => urlencode($plugin['download'])), true) ?>
<?php elseif ($installed_plugins[$plugin['title']] < $plugin['version']): ?>
- <i class="fa fa-refresh fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Update'), 'PluginController', 'update', array('archive_url' => urlencode($plugin['download'])), true) ?>
+ <?= $this->url->icon('refresh', t('Update'), 'PluginController', 'update', array('archive_url' => urlencode($plugin['download'])), true) ?>
<?php else: ?>
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
<?= t('Up to date') ?>
diff --git a/app/Template/plugin/remove.php b/app/Template/plugin/remove.php
index bd8f4eb8..1280f8aa 100644
--- a/app/Template/plugin/remove.php
+++ b/app/Template/plugin/remove.php
@@ -5,9 +5,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this plugin: "%s"?', $plugin->getPluginName()) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'PluginController', 'uninstall', array('pluginId' => $plugin_id), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'PluginController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'PluginController',
+ 'uninstall',
+ array('pluginId' => $plugin_id)
+ ) ?>
</div>
diff --git a/app/Template/plugin/show.php b/app/Template/plugin/show.php
index 9c3d6d20..266568ac 100644
--- a/app/Template/plugin/show.php
+++ b/app/Template/plugin/show.php
@@ -1,3 +1,43 @@
+<?php if (! empty($incompatible_plugins)): ?>
+ <div class="page-header">
+ <h2><?= t('Incompatible Plugins') ?></h2>
+ </div>
+ <table>
+ <tr>
+ <th class="column-35"><?= t('Name') ?></th>
+ <th class="column-25"><?= t('Author') ?></th>
+ <th class="column-10"><?= t('Version') ?></th>
+ <th class="column-12"><?= t('Compatibility') ?></th>
+ <?php if ($is_configured): ?>
+ <th><?= t('Action') ?></th>
+ <?php endif ?>
+ </tr>
+
+ <?php foreach ($incompatible_plugins as $pluginFolder => $plugin): ?>
+ <tr>
+ <td>
+ <?php if ($plugin->getPluginHomepage()): ?>
+ <a href="<?= $plugin->getPluginHomepage() ?>" target="_blank" rel="noreferrer"><?= $this->text->e($plugin->getPluginName()) ?></a>
+ <?php else: ?>
+ <?= $this->text->e($plugin->getPluginName()) ?>
+ <?php endif ?>
+ </td>
+ <td><?= $this->text->e($plugin->getPluginAuthor()) ?></td>
+ <td><?= $this->text->e($plugin->getPluginVersion()) ?></td>
+ <td><?= $this->text->e($plugin->getCompatibleVersion()) ?></td>
+ <?php if ($is_configured): ?>
+ <td>
+ <?= $this->modal->confirm('trash-o', t('Uninstall'), 'PluginController', 'confirm', array('pluginId' => $pluginFolder)) ?>
+ </td>
+ <?php endif ?>
+ </tr>
+ <tr>
+ <td colspan="<?= $is_configured ? 6 : 5 ?>"><?= $this->text->e($plugin->getPluginDescription()) ?></td>
+ </tr>
+ <?php endforeach ?>
+ </table>
+<?php endif ?>
+
<div class="page-header">
<h2><?= t('Installed Plugins') ?></h2>
</div>
@@ -28,8 +68,7 @@
<td><?= $this->text->e($plugin->getPluginVersion()) ?></td>
<?php if ($is_configured): ?>
<td>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Uninstall'), 'PluginController', 'confirm', array('pluginId' => $pluginFolder), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Uninstall'), 'PluginController', 'confirm', array('pluginId' => $pluginFolder)) ?>
</td>
<?php endif ?>
</tr>
diff --git a/app/Template/project/dropdown.php b/app/Template/project/dropdown.php
index e3cf41c2..447cd0b4 100644
--- a/app/Template/project/dropdown.php
+++ b/app/Template/project/dropdown.php
@@ -2,42 +2,35 @@
<a href="#" class="dropdown-menu dashboard-table-link">#<?= $project['id'] ?></a>
<ul>
<li>
- <i class="fa fa-th fa-fw"></i>
- <?= $this->url->link(t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('th', t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'])) ?>
</li>
<li>
- <i class="fa fa-calendar fa-fw"></i>
- <?= $this->url->link(t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('calendar', t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'])) ?>
</li>
<li>
- <i class="fa fa-list fa-fw"></i>
- <?= $this->url->link(t('Listing'), 'TaskListController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('list', t('Listing'), 'TaskListController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('TaskGanttController', 'show', $project['id'])): ?>
<li>
- <i class="fa fa-sliders fa-fw"></i>
- <?= $this->url->link(t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('sliders', t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-dashboard fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->medium('dashboard', t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('AnalyticController', 'taskDistribution', $project['id'])): ?>
<li>
- <i class="fa fa-line-chart fa-fw"></i>&nbsp;
- <?= $this->url->link(t('Analytics'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->large('line-chart', t('Analytics'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<?= $this->hook->render('template:project:dropdown', array('project' => $project)) ?>
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<li>
- <i class="fa fa-cog fa-fw"></i>
- <?= $this->url->link(t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('cog', t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project/sidebar.php b/app/Template/project/sidebar.php
index 6e7fff05..812eb351 100644
--- a/app/Template/project/sidebar.php
+++ b/app/Template/project/sidebar.php
@@ -9,9 +9,9 @@
</li>
<?php endif ?>
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<li <?= $this->app->checkMenuSelection('ProjectEditController') ?>>
- <?= $this->url->link(t('Edit project'), 'ProjectEditController', 'edit', array('project_id' => $project['id'])) ?>
+ <?= $this->url->link(t('Edit project'), 'ProjectEditController', 'show', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('ProjectViewController', 'share') ?>>
<?= $this->url->link(t('Public access'), 'ProjectViewController', 'share', array('project_id' => $project['id'])) ?>
@@ -50,15 +50,15 @@
</li>
<?php if ($project['is_active']): ?>
<li>
- <?= $this->url->link(t('Disable'), 'ProjectStatusController', 'confirmDisable', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->confirmLink(t('Disable'), 'ProjectStatusController', 'confirmDisable', array('project_id' => $project['id'])) ?>
<?php else: ?>
<li>
- <?= $this->url->link(t('Enable'), 'ProjectStatusController', 'confirmEnable', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->confirmLink(t('Enable'), 'ProjectStatusController', 'confirmEnable', array('project_id' => $project['id'])) ?>
<?php endif ?>
</li>
<?php if ($this->user->hasProjectAccess('ProjectStatusController', 'remove', $project['id'])): ?>
<li>
- <?= $this->url->link(t('Remove'), 'ProjectStatusController', 'confirmRemove', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->confirmLink(t('Remove'), 'ProjectStatusController', 'confirmRemove', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<?php endif ?>
diff --git a/app/Template/project_action_duplication/show.php b/app/Template/project_action_duplication/show.php
index 2eebb262..c2f52e35 100644
--- a/app/Template/project_action_duplication/show.php
+++ b/app/Template/project_action_duplication/show.php
@@ -4,16 +4,12 @@
<?php if (empty($projects_list)): ?>
<p class="alert"><?= t('There is no available project.') ?></p>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('ProjectActionDuplicationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('ProjectActionDuplicationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->label(t('Create from another project'), 'src_project_id') ?>
<?= $this->form->select('src_project_id', $projects_list) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'Action', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/project_creation/create.php b/app/Template/project_creation/create.php
index 1df15d7d..171bd17a 100644
--- a/app/Template/project_creation/create.php
+++ b/app/Template/project_creation/create.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= $title ?></h2>
</div>
- <form class="popover-form" id="project-creation-form" method="post" action="<?= $this->url->href('ProjectCreationController', 'save') ?>" autocomplete="off">
+ <form id="project-creation-form" method="post" action="<?= $this->url->href('ProjectCreationController', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('is_private', $values) ?>
@@ -29,11 +29,7 @@
<?= $this->form->checkbox('projectTaskDuplicationModel', t('Tasks'), 1, false) ?>
</div>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectListController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php if ($is_private): ?>
<div class="alert alert-info">
diff --git a/app/Template/project_edit/dates.php b/app/Template/project_edit/dates.php
deleted file mode 100644
index 1c2c3dd4..00000000
--- a/app/Template/project_edit/dates.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<div class="page-header">
- <h2><?= t('Edit project') ?></h2>
- <ul>
- <li ><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- </ul>
-</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'dates')) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('name', $values) ?>
- <?= $this->form->date(t('Start date'), 'start_date', $values, $errors) ?>
- <?= $this->form->date(t('End date'), 'end_date', $values, $errors) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
-
-<p class="alert alert-info"><?= t('Those dates are useful for the project Gantt chart.') ?></p>
diff --git a/app/Template/project_edit/description.php b/app/Template/project_edit/description.php
deleted file mode 100644
index 586ddfcb..00000000
--- a/app/Template/project_edit/description.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="page-header">
- <h2><?= t('Edit project') ?></h2>
- <ul>
- <li><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- </ul>
-</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'description')) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('name', $values) ?>
- <?= $this->form->textEditor('description', $values, $errors, array('autofocus' => true)) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
diff --git a/app/Template/project_edit/general.php b/app/Template/project_edit/general.php
deleted file mode 100644
index c7421477..00000000
--- a/app/Template/project_edit/general.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="page-header">
- <h2><?= t('Edit project') ?></h2>
- <ul>
- <li class="active"><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- </ul>
-</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('id', $values) ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array('required', 'maxlength="50"')) ?>
-
- <?= $this->form->label(t('Identifier'), 'identifier') ?>
- <?= $this->form->text('identifier', $values, $errors, array('maxlength="50"')) ?>
- <p class="form-help"><?= t('The project identifier is optional and must be alphanumeric, example: MYPROJECT.') ?></p>
-
- <hr>
- <div class="form-inline">
- <?= $this->form->label(t('Project owner'), 'owner_id') ?>
- <?= $this->form->select('owner_id', $owners, $values, $errors) ?>
- </div>
-
- <?php if ($this->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])): ?>
- <hr>
- <?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
- <p class="form-help"><?= t('Private projects do not have users and groups management.') ?></p>
- <?php endif ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
diff --git a/app/Template/project_edit/show.php b/app/Template/project_edit/show.php
new file mode 100644
index 00000000..46cdb8fa
--- /dev/null
+++ b/app/Template/project_edit/show.php
@@ -0,0 +1,58 @@
+<div class="page-header">
+ <h2><?= $this->text->e($project['name']) ?> &gt; <?= t('Edit project') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('id', $values) ?>
+
+ <fieldset>
+ <legend><?= t('General') ?></legend>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors, array('required', 'maxlength="50"', 'autofocus', 'tabindex="1"')) ?>
+
+ <?= $this->form->label(t('Identifier'), 'identifier') ?>
+ <?= $this->form->text('identifier', $values, $errors, array('maxlength="50"', 'tabindex="2"')) ?>
+ <p class="form-help"><?= t('The project identifier is optional and must be alphanumeric, example: MYPROJECT.') ?></p>
+
+ <?= $this->form->label(t('Description'), 'description') ?>
+ <?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 3)) ?>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Permissions and ownership') ?></legend>
+
+ <?php if ($this->user->hasProjectAccess('ProjectCreationController', 'create', $project['id'])): ?>
+ <?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
+ <p class="form-help"><?= t('Private projects do not have users and groups management.') ?></p>
+ <?php endif ?>
+
+ <div class="form-inline">
+ <?= $this->form->label(t('Project owner'), 'owner_id') ?>
+ <?= $this->form->select('owner_id', $owners, $values, $errors, array('tabindex="5"')) ?>
+ </div>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Dates') ?></legend>
+
+ <?= $this->form->date(t('Start date'), 'start_date', $values, $errors, array('tabindex="6"')) ?>
+ <?= $this->form->date(t('End date'), 'end_date', $values, $errors, array('tabindex="7"')) ?>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Priorities') ?></legend>
+
+ <?= $this->form->label(t('Default priority'), 'priority_default') ?>
+ <?= $this->form->number('priority_default', $values, $errors, array('tabindex="8"')) ?>
+
+ <?= $this->form->label(t('Lowest priority'), 'priority_start') ?>
+ <?= $this->form->number('priority_start', $values, $errors, array('tabindex="9"')) ?>
+
+ <?= $this->form->label(t('Highest priority'), 'priority_end') ?>
+ <?= $this->form->number('priority_end', $values, $errors, array('tabindex="10"')) ?>
+ <p class="form-help"><?= t('If you put zero to the low and high priority, this feature will be disabled.') ?></p>
+ </fieldset>
+
+ <?= $this->modal->submitButtons(array('tabindex' => 11)) ?>
+</form>
diff --git a/app/Template/project_edit/task_priority.php b/app/Template/project_edit/task_priority.php
deleted file mode 100644
index 3ef4b3cb..00000000
--- a/app/Template/project_edit/task_priority.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<div class="page-header">
- <h2><?= t('Edit project') ?></h2>
- <ul>
- <li ><?= $this->url->link(t('General'), 'ProjectEditController', 'edit', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Dates'), 'ProjectEditController', 'dates', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li><?= $this->url->link(t('Description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- <li class="active"><?= $this->url->link(t('Task priority'), 'ProjectEditController', 'priority', array('project_id' => $project['id']), false, 'popover-link') ?></li>
- </ul>
-</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'priority')) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('name', $values) ?>
-
- <?= $this->form->label(t('Default priority'), 'priority_default') ?>
- <?= $this->form->number('priority_default', $values, $errors) ?>
-
- <?= $this->form->label(t('Lowest priority'), 'priority_start') ?>
- <?= $this->form->number('priority_start', $values, $errors) ?>
-
- <?= $this->form->label(t('Highest priority'), 'priority_end') ?>
- <?= $this->form->number('priority_end', $values, $errors) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- </div>
-</form>
-
-<p class="alert alert-info"><?= t('If you put zero to the low and high priority, this feature will be disabled.') ?></p>
diff --git a/app/Template/project_file/create.php b/app/Template/project_file/create.php
index e262799b..de35f87c 100644
--- a/app/Template/project_file/create.php
+++ b/app/Template/project_file/create.php
@@ -1,33 +1,20 @@
<div class="page-header">
<h2><?= t('Attach a document') ?></h2>
</div>
-<div id="file-done" style="display:none">
- <p class="alert alert-success">
- <?= t('All files have been uploaded successfully.') ?>
- <?= $this->url->link(t('View uploaded files'), 'ProjectOverviewController', 'show', array('project_id' => $project['id'])) ?>
- </p>
-</div>
-
-<div id="file-error-max-size" style="display:none">
- <p class="alert alert-error">
- <?= t('The maximum allowed file size is %sB.', $this->text->bytes($max_size)) ?>
- <a href="#" id="file-browser"><?= t('Choose files again') ?></a>
- </p>
-</div>
-<div
- id="file-dropzone"
- data-max-size="<?= $max_size ?>"
- data-url="<?= $this->url->href('ProjectFileController', 'save', array('project_id' => $project['id'])) ?>">
- <div id="file-dropzone-inner">
- <?= t('Drag and drop your files here') ?> <?= t('or') ?> <a href="#" id="file-browser"><?= t('choose files') ?></a>
- </div>
-</div>
-
-<input type="file" name="files[]" multiple style="display:none" id="file-form-element">
+<?= $this->app->component('file-upload', array(
+ 'maxSize' => $max_size,
+ 'url' => $this->url->to('ProjectFileController', 'save', array('project_id' => $project['id'])),
+ 'labelDropzone' => t('Drag and drop your files here'),
+ 'labelOr' => t('or'),
+ 'labelChooseFiles' => t('choose files'),
+ 'labelOversize' => t('The maximum allowed file size is %sB.', $this->text->bytes($max_size)),
+ 'labelSuccess' => t('All files have been uploaded successfully.'),
+ 'labelCloseSuccess' => t('Close this window'),
+ 'labelUploadError' => t('Unable to upload this file.'),
+)) ?>
-<div class="form-actions">
- <input type="submit" value="<?= t('Upload files') ?>" class="btn btn-blue" id="file-upload-button" disabled>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectOverviewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
-</div>
+<?= $this->modal->submitButtons(array(
+ 'submitLabel' => t('Upload files'),
+ 'disabled' => true,
+)) ?>
diff --git a/app/Template/project_file/remove.php b/app/Template/project_file/remove.php
index 0517a9e7..043b8fc8 100644
--- a/app/Template/project_file/remove.php
+++ b/app/Template/project_file/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this file: "%s"?', $this->text->e($file['name'])) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectFileController', 'remove', array('project_id' => $project['id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectOverviewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectFileController',
+ 'remove',
+ array('project_id' => $project['id'], 'file_id' => $file['id'])
+ ) ?>
</div>
diff --git a/app/Template/project_gantt/show.php b/app/Template/project_gantt/show.php
index af22a6ed..725f348d 100644
--- a/app/Template/project_gantt/show.php
+++ b/app/Template/project_gantt/show.php
@@ -1,11 +1,23 @@
<section id="main">
<div class="page-header">
<ul>
+ <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
+ <li>
+ <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->app->config('disable_private_project', 0) == 0): ?>
+ <li>
+ <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
+ </li>
+ <?php endif ?>
<li>
- <i class="fa fa-folder fa-fw"></i><?= $this->url->link(t('Projects list'), 'ProjectListController', 'show') ?>
+ <?= $this->url->icon('folder', t('Projects list'), 'ProjectListController', 'show') ?>
</li>
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
+ <li>
+ <?= $this->url->icon('user', t('Users overview'), 'ProjectUserOverviewController', 'managers') ?>
+ </li>
<?php endif ?>
</ul>
</div>
diff --git a/app/Template/project_header/dropdown.php b/app/Template/project_header/dropdown.php
index baf4cc16..83c2b97f 100644
--- a/app/Template/project_header/dropdown.php
+++ b/app/Template/project_header/dropdown.php
@@ -4,12 +4,10 @@
<?php if ($board_view): ?>
<li>
<span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? '' : 'style="display: none;"' ?>>
- <i class="fa fa-expand fa-fw"></i>
- <?= $this->url->link(t('Expand tasks'), 'BoardAjaxController', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?= $this->url->icon('expand', t('Expand tasks'), 'BoardAjaxController', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
</span>
<span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? 'style="display: none;"' : '' ?>>
- <i class="fa fa-compress fa-fw"></i>
- <?= $this->url->link(t('Collapse tasks'), 'BoardAjaxController', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
+ <?= $this->url->icon('compress', t('Collapse tasks'), 'BoardAjaxController', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
</span>
</li>
<li>
@@ -24,27 +22,23 @@
<?php if ($this->user->hasProjectAccess('TaskCreationController', 'show', $project['id'])): ?>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new task'), 'TaskCreationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->large('plus', t('Add a new task'), 'TaskCreationController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-dashboard fa-fw"></i>
- <?= $this->url->link(t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->medium('dashboard', t('Activity'), 'ActivityController', 'project', array('project_id' => $project['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('CustomFilterController', 'index', $project['id'])): ?>
<li>
- <i class="fa fa-filter fa-fw"></i>
- <?= $this->url->link(t('Custom filters'), 'CustomFilterController', 'index', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->medium('filter', t('Add custom filters'), 'CustomFilterController', 'create', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<?php if ($project['is_public']): ?>
<li>
- <i class="fa fa-share-alt fa-fw"></i>
- <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?>
+ <?= $this->url->icon('share-alt', t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?>
</li>
<?php endif ?>
@@ -52,35 +46,30 @@
<?php if ($this->user->hasProjectAccess('AnalyticController', 'taskDistribution', $project['id'])): ?>
<li>
- <i class="fa fa-line-chart fa-fw"></i>
- <?= $this->url->link(t('Analytics'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->large('line-chart', t('Analytics'), 'AnalyticController', 'taskDistribution', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<?php if ($this->user->hasProjectAccess('ExportController', 'tasks', $project['id'])): ?>
<li>
- <i class="fa fa-upload fa-fw"></i>
- <?= $this->url->link(t('Exports'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->medium('upload', t('Exports'), 'ExportController', 'tasks', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<?php if ($this->user->hasProjectAccess('TaskImportController', 'tasks', $project['id'])): ?>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Imports'), 'TaskImportController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->modal->medium('download', t('Import tasks'), 'TaskImportController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'edit', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<li>
- <i class="fa fa-cog fa-fw"></i>
- <?= $this->url->link(t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
+ <?= $this->url->icon('cog', t('Settings'), 'ProjectViewController', 'show', array('project_id' => $project['id'])) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-folder fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Manage projects'), 'ProjectListController', 'show') ?>
+ <?= $this->url->icon('folder', t('Manage projects'), 'ProjectListController', 'show') ?>
</li>
</ul>
</div>
diff --git a/app/Template/project_header/views.php b/app/Template/project_header/views.php
index f8a5b39b..0328a051 100644
--- a/app/Template/project_header/views.php
+++ b/app/Template/project_header/views.php
@@ -1,24 +1,19 @@
<ul class="views">
<li <?= $this->app->checkMenuSelection('ProjectOverviewController') ?>>
- <i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('Overview'), 'ProjectOverviewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-overview', t('Keyboard shortcut: "%s"', 'v o')) ?>
+ <?= $this->url->icon('eye', t('Overview'), 'ProjectOverviewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-overview', t('Keyboard shortcut: "%s"', 'v o')) ?>
</li>
<li <?= $this->app->checkMenuSelection('BoardViewController') ?>>
- <i class="fa fa-th fa-fw"></i>
- <?= $this->url->link(t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-board', t('Keyboard shortcut: "%s"', 'v b')) ?>
+ <?= $this->url->icon('th', t('Board'), 'BoardViewController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-board', t('Keyboard shortcut: "%s"', 'v b')) ?>
</li>
<li <?= $this->app->checkMenuSelection('CalendarController') ?>>
- <i class="fa fa-calendar fa-fw"></i>
- <?= $this->url->link(t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-calendar', t('Keyboard shortcut: "%s"', 'v c')) ?>
+ <?= $this->url->icon('calendar', t('Calendar'), 'CalendarController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-calendar', t('Keyboard shortcut: "%s"', 'v c')) ?>
</li>
<li <?= $this->app->checkMenuSelection('TaskListController') ?>>
- <i class="fa fa-list fa-fw"></i>
- <?= $this->url->link(t('List'), 'TaskListController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
+ <?= $this->url->icon('list', t('List'), 'TaskListController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
</li>
<?php if ($this->user->hasProjectAccess('TaskGanttController', 'show', $project['id'])): ?>
<li <?= $this->app->checkMenuSelection('TaskGanttController') ?>>
- <i class="fa fa-sliders fa-fw"></i>
- <?= $this->url->link(t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-gantt', t('Keyboard shortcut: "%s"', 'v g')) ?>
+ <?= $this->url->icon('sliders', t('Gantt'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-gantt', t('Keyboard shortcut: "%s"', 'v g')) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project_list/show.php b/app/Template/project_list/show.php
index f8f5862c..a6364585 100644
--- a/app/Template/project_list/show.php
+++ b/app/Template/project_list/show.php
@@ -2,12 +2,26 @@
<div class="page-header">
<ul>
<?= $this->hook->render('template:project-list:menu:before') ?>
+
+ <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
+ <li>
+ <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->app->config('disable_private_project', 0) == 0): ?>
+ <li>
+ <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
+ </li>
+ <?php endif ?>
+
<?php if ($this->user->hasAccess('ProjectUserOverviewController', 'managers')): ?>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
+ <li><?= $this->url->icon('user', t('Users overview'), 'ProjectUserOverviewController', 'managers') ?></li>
<?php endif ?>
+
<?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
- <li><i class="fa fa-sliders fa-fw"></i><?= $this->url->link(t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?></li>
+ <li><?= $this->url->icon('sliders', t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?></li>
<?php endif ?>
+
<?= $this->hook->render('template:project-list:menu:after') ?>
</ul>
</div>
diff --git a/app/Template/project_overview/attachments.php b/app/Template/project_overview/attachments.php
index ab8cf2ad..b8baadd0 100644
--- a/app/Template/project_overview/attachments.php
+++ b/app/Template/project_overview/attachments.php
@@ -5,7 +5,7 @@
<div class="accordion-content">
<?php if ($this->user->hasProjectAccess('ProjectFileController', 'create', $project['id'])): ?>
<div class="buttons-header">
- <?= $this->url->button('fa-plus', t('Upload a file'), 'ProjectFileController', 'create', array('project_id' => $project['id']), 'popover') ?>
+ <?= $this->modal->mediumButton('plus', t('Upload a file'), 'ProjectFileController', 'create', array('project_id' => $project['id'])) ?>
</div>
<?php endif ?>
diff --git a/app/Template/project_overview/description.php b/app/Template/project_overview/description.php
index 0c2027ed..80b93efe 100644
--- a/app/Template/project_overview/description.php
+++ b/app/Template/project_overview/description.php
@@ -3,9 +3,9 @@
<h3><a href="#" class="fa accordion-toggle"></a> <?= t('Description') ?></h3>
</div>
<div class="accordion-content">
- <?php if ($this->user->hasProjectAccess('ProjectEditController', 'description', $project['id'])): ?>
+ <?php if ($this->user->hasProjectAccess('ProjectEditController', 'show', $project['id'])): ?>
<div class="buttons-header">
- <?= $this->url->button('fa-edit', t('Edit description'), 'ProjectEditController', 'description', array('project_id' => $project['id']), 'popover') ?>
+ <?= $this->modal->mediumButton('edit', t('Edit description'), 'ProjectEditController', 'show', array('project_id' => $project['id'])) ?>
</div>
<?php endif ?>
<article class="markdown">
diff --git a/app/Template/project_overview/files.php b/app/Template/project_overview/files.php
index 826e6325..85de52f7 100644
--- a/app/Template/project_overview/files.php
+++ b/app/Template/project_overview/files.php
@@ -15,18 +15,19 @@
<ul>
<?php if ($this->file->getPreviewType($file['name']) !== null): ?>
<li>
- <i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('View file'), 'FileViewerController', 'show', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->modal->large('eye', t('View file'), 'FileViewerController', 'show', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
+ </li>
+ <?php elseif ($this->file->getBrowserViewType($file['name']) !== null): ?>
+ <li>
+ <?= $this->url->icon('eye', t('View file'), 'FileViewerController', 'browser', array('project_id' => $project['id'], 'file_id' => $file['id']), false, '', '', true) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->icon('download', t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('ProjectFileController', 'remove', $project['id'])): ?>
<li>
- <i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project_overview/images.php b/app/Template/project_overview/images.php
index 3b575d3f..7e7962e8 100644
--- a/app/Template/project_overview/images.php
+++ b/app/Template/project_overview/images.php
@@ -19,13 +19,11 @@
<a href="#" class="dropdown-menu dropdown-menu-link-text"><?= $this->text->e($file['name']) ?> <i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->icon('download', t('Download'), 'FileViewerController', 'download', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('ProjectFileController', 'remove', $project['id'])): ?>
<li>
- <i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ProjectFileController', 'confirm', array('project_id' => $project['id'], 'file_id' => $file['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/project_overview/information.php b/app/Template/project_overview/information.php
index fdf0f753..0fe53e08 100644
--- a/app/Template/project_overview/information.php
+++ b/app/Template/project_overview/information.php
@@ -3,7 +3,7 @@
<h3><a href="#" class="fa accordion-toggle"></a> <?= t('Information') ?></h3>
</div>
<div class="accordion-content">
- <div class="listing">
+ <div class="panel">
<ul>
<?php if ($project['owner_id'] > 0): ?>
<li><?= t('Project owner: ') ?><strong><?= $this->text->e($project['owner_name'] ?: $project['owner_username']) ?></strong></li>
@@ -29,9 +29,9 @@
<?php endif ?>
<?php if ($project['is_public']): ?>
- <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
+ <li><?= $this->url->icon('share-alt', t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
<?php endif ?>
</ul>
</div>
diff --git a/app/Template/project_overview/show.php b/app/Template/project_overview/show.php
index 6b2bc2cf..d87b2775 100644
--- a/app/Template/project_overview/show.php
+++ b/app/Template/project_overview/show.php
@@ -1,6 +1,7 @@
<section id="main">
<?= $this->projectHeader->render($project, 'ProjectOverviewController', 'show') ?>
<?= $this->render('project_overview/columns', array('project' => $project)) ?>
+ <?= $this->hook->render('template:project-overview:before-description', array('project' => $project)) ?>
<?= $this->render('project_overview/description', array('project' => $project)) ?>
<?= $this->render('project_overview/attachments', array('project' => $project, 'images' => $images, 'files' => $files)) ?>
<?= $this->render('project_overview/information', array('project' => $project, 'users' => $users, 'roles' => $roles)) ?>
diff --git a/app/Template/project_permission/groups.php b/app/Template/project_permission/groups.php
index 582643a2..c9914344 100644
--- a/app/Template/project_permission/groups.php
+++ b/app/Template/project_permission/groups.php
@@ -25,8 +25,7 @@
)) ?>
</td>
<td>
- <i class="fa fa-trash-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ProjectPermissionController', 'removeGroup', array('project_id' => $project['id'], 'group_id' => $group['id']), true) ?>
+ <?= $this->url->icon('trash-o', t('Remove'), 'ProjectPermissionController', 'removeGroup', array('project_id' => $project['id'], 'group_id' => $group['id']), true) ?>
</td>
</tr>
<?php endforeach ?>
@@ -34,7 +33,7 @@
<?php endif ?>
<?php if ($project['is_private'] == 0): ?>
- <div class="listing">
+ <div class="panel">
<form method="post" action="<?= $this->url->href('ProjectPermissionController', 'addGroup', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', array('project_id' => $project['id'])) ?>
diff --git a/app/Template/project_permission/users.php b/app/Template/project_permission/users.php
index 71cf1c4a..bc92d060 100644
--- a/app/Template/project_permission/users.php
+++ b/app/Template/project_permission/users.php
@@ -21,8 +21,7 @@
)) ?>
</td>
<td>
- <i class="fa fa-trash-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ProjectPermissionController', 'removeUser', array('project_id' => $project['id'], 'user_id' => $user['id']), true) ?>
+ <?= $this->url->icon('trash-o', t('Remove'), 'ProjectPermissionController', 'removeUser', array('project_id' => $project['id'], 'user_id' => $user['id']), true) ?>
</td>
</tr>
<?php endforeach ?>
@@ -30,7 +29,7 @@
<?php endif ?>
<?php if ($project['is_private'] == 0): ?>
- <div class="listing">
+ <div class="panel">
<form method="post" action="<?= $this->url->href('ProjectPermissionController', 'addUser', array('project_id' => $project['id'])) ?>" autocomplete="off" class="form-inline">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', array('project_id' => $project['id'])) ?>
diff --git a/app/Template/project_role/create.php b/app/Template/project_role/create.php
index d0092243..f554eb17 100644
--- a/app/Template/project_role/create.php
+++ b/app/Template/project_role/create.php
@@ -1,16 +1,12 @@
<div class="page-header">
<h2><?= t('New custom project role') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ProjectRoleController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ProjectRoleController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Role'), 'role') ?>
<?= $this->form->text('role', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/project_role/edit.php b/app/Template/project_role/edit.php
index 3aa9e5cf..740ac0fe 100644
--- a/app/Template/project_role/edit.php
+++ b/app/Template/project_role/edit.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit custom project role') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('ProjectRoleController', 'update', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ProjectRoleController', 'update', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->hidden('role_id', $values) ?>
@@ -9,9 +9,5 @@
<?= $this->form->label(t('Role'), 'role') ?>
<?= $this->form->text('role', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/project_role/remove.php b/app/Template/project_role/remove.php
index 25875e3a..44d24eda 100644
--- a/app/Template/project_role/remove.php
+++ b/app/Template/project_role/remove.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to remove this custom role: "%s"? All people assigned to this role will become project member.', $role['role']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectRoleController', 'remove', array('project_id' => $project['id'], 'role_id' => $role['role_id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectRoleController',
+ 'remove',
+ array('project_id' => $project['id'], 'role_id' => $role['role_id'])
+ ) ?>
</div>
diff --git a/app/Template/project_role/show.php b/app/Template/project_role/show.php
index 59200fc9..5377f7bb 100644
--- a/app/Template/project_role/show.php
+++ b/app/Template/project_role/show.php
@@ -2,8 +2,7 @@
<h2><?= t('Custom Project Roles') ?></h2>
<ul>
<li>
- <i class="fa fa-plus fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Add a new custom role'), 'ProjectRoleController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new custom role'), 'ProjectRoleController', 'create', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
@@ -19,24 +18,19 @@
<a href="#" class="dropdown-menu"><?= t('Restrictions for the role "%s"', $role['role']) ?> <i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-plus fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Add a new project restriction'), 'ProjectRoleRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new project restriction'), 'ProjectRoleRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>
</li>
<li>
- <i class="fa fa-plus fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Add a new drag and drop restriction'), 'ColumnMoveRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new drag and drop restriction'), 'ColumnMoveRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>
</li>
<li>
- <i class="fa fa-plus fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Add a new column restriction'), 'ColumnRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new column restriction'), 'ColumnRestrictionController', 'create', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>
</li>
<li>
- <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit this role'), 'ProjectRoleController', 'edit', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit this role'), 'ProjectRoleController', 'edit', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove this role'), 'ProjectRoleController', 'confirm', array('project_id' => $project['id'], 'role_id' => $role['role_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove this role'), 'ProjectRoleController', 'confirm', array('project_id' => $project['id'], 'role_id' => $role['role_id'])) ?>
</li>
</ul>
</div>
@@ -59,8 +53,7 @@
<?= $this->text->e($restriction['title']) ?>
</td>
<td>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ProjectRoleRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ProjectRoleRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])) ?>
</td>
</tr>
<?php endforeach ?>
@@ -77,8 +70,7 @@
<?= $this->text->e($restriction['title']) ?>
</td>
<td>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ColumnRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ColumnRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])) ?>
</td>
</tr>
<?php endforeach ?>
@@ -91,8 +83,7 @@
<?= t('Only moving task between those columns is permitted') ?>
</td>
<td>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ColumnMoveRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ColumnMoveRestrictionController', 'confirm', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/project_role_restriction/create.php b/app/Template/project_role_restriction/create.php
index f49eafb3..2b6a61dc 100644
--- a/app/Template/project_role_restriction/create.php
+++ b/app/Template/project_role_restriction/create.php
@@ -2,7 +2,7 @@
<div class="page-header">
<h2><?= t('New project restriction for the role "%s"', $role['role']) ?></h2>
</div>
- <form class="popover-form" method="post" action="<?= $this->url->href('ProjectRoleRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('ProjectRoleRestrictionController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->hidden('role_id', $values) ?>
@@ -10,10 +10,6 @@
<?= $this->form->label(t('Restriction'), 'rule') ?>
<?= $this->form->select('rule', $restrictions, $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
</section>
diff --git a/app/Template/project_role_restriction/remove.php b/app/Template/project_role_restriction/remove.php
index db1148e1..1a994199 100644
--- a/app/Template/project_role_restriction/remove.php
+++ b/app/Template/project_role_restriction/remove.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to remove this project restriction: "%s"?', $this->text->in($restriction['rule'], $restrictions)) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectRoleRestrictionController', 'remove', array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectRoleController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectRoleRestrictionController',
+ 'remove',
+ array('project_id' => $project['id'], 'restriction_id' => $restriction['restriction_id'])
+ ) ?>
</div>
diff --git a/app/Template/project_status/disable.php b/app/Template/project_status/disable.php
index d8145d3c..d607cedb 100644
--- a/app/Template/project_status/disable.php
+++ b/app/Template/project_status/disable.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to disable this project: "%s"?', $project['name']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'disable', array('project_id' => $project['id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectStatusController',
+ 'disable',
+ array('project_id' => $project['id'])
+ ) ?>
</div>
diff --git a/app/Template/project_status/enable.php b/app/Template/project_status/enable.php
index 1f76d093..fd8f8c72 100644
--- a/app/Template/project_status/enable.php
+++ b/app/Template/project_status/enable.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to enable this project: "%s"?', $project['name']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'enable', array('project_id' => $project['id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectStatusController',
+ 'enable',
+ array('project_id' => $project['id'])
+ ) ?>
</div>
diff --git a/app/Template/project_status/remove.php b/app/Template/project_status/remove.php
index 8959ef75..27ae2ae0 100644
--- a/app/Template/project_status/remove.php
+++ b/app/Template/project_status/remove.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to remove this project: "%s"?', $project['name']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectStatusController', 'remove', array('project_id' => $project['id']), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'ProjectViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectStatusController',
+ 'remove',
+ array('project_id' => $project['id'])
+ ) ?>
</div>
diff --git a/app/Template/project_tag/create.php b/app/Template/project_tag/create.php
index bfd1084a..a0e6243b 100644
--- a/app/Template/project_tag/create.php
+++ b/app/Template/project_tag/create.php
@@ -1,16 +1,12 @@
<div class="page-header">
<h2><?= t('Add new tag') ?></h2>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectTagController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ProjectTagController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="255"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectTagController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/project_tag/edit.php b/app/Template/project_tag/edit.php
index 9bf261bd..8cb1e209 100644
--- a/app/Template/project_tag/edit.php
+++ b/app/Template/project_tag/edit.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit a tag') ?></h2>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('ProjectTagController', 'update', array('tag_id' => $tag['id'], 'project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('ProjectTagController', 'update', array('tag_id' => $tag['id'], 'project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -9,9 +9,5 @@
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="255"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectTagController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/project_tag/index.php b/app/Template/project_tag/index.php
index f77e21ee..29d7082b 100644
--- a/app/Template/project_tag/index.php
+++ b/app/Template/project_tag/index.php
@@ -2,8 +2,7 @@
<h2><?= t('Project tags') ?></h2>
<ul>
<li>
- <i class="fa fa-plus" aria-hidden="true"></i>
- <?= $this->url->link(t('Add new tag'), 'ProjectTagController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add new tag'), 'ProjectTagController', 'create', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
@@ -20,10 +19,8 @@
<tr>
<td><?= $this->text->e($tag['name']) ?></td>
<td>
- <i class="fa fa-times" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'ProjectTagController', 'confirm', array('tag_id' => $tag['id'], 'project_id' => $project['id']), false, 'popover') ?>
- <i class="fa fa-pencil-square-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'ProjectTagController', 'edit', array('tag_id' => $tag['id'], 'project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'ProjectTagController', 'edit', array('tag_id' => $tag['id'], 'project_id' => $project['id'])) ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'ProjectTagController', 'confirm', array('tag_id' => $tag['id'], 'project_id' => $project['id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/project_tag/remove.php b/app/Template/project_tag/remove.php
index f4aadab1..9f957d10 100644
--- a/app/Template/project_tag/remove.php
+++ b/app/Template/project_tag/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this tag: "%s"?', $tag['name']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'ProjectTagController', 'remove', array('tag_id' => $tag['id'], 'project_id' => $project['id']), true, 'btn btn-red popover-link') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'ProjectTagController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'ProjectTagController',
+ 'remove',
+ array('tag_id' => $tag['id'], 'project_id' => $project['id'])
+ ) ?>
</div>
diff --git a/app/Template/project_user_overview/layout.php b/app/Template/project_user_overview/layout.php
index 19b83436..9115ef3c 100644
--- a/app/Template/project_user_overview/layout.php
+++ b/app/Template/project_user_overview/layout.php
@@ -1,20 +1,27 @@
<section id="main">
<div class="page-header">
<ul>
+ <?php if ($this->user->hasAccess('ProjectCreationController', 'create')): ?>
+ <li>
+ <?= $this->modal->medium('plus', t('New project'), 'ProjectCreationController', 'create') ?>
+ </li>
+ <?php endif ?>
+ <?php if ($this->app->config('disable_private_project', 0) == 0): ?>
+ <li>
+ <?= $this->modal->medium('lock', t('New private project'), 'ProjectCreationController', 'createPrivate') ?>
+ </li>
+ <?php endif ?>
<li>
- <i class="fa fa-folder fa-fw"></i>
- <?= $this->url->link(t('Projects list'), 'ProjectListController', 'show') ?>
+ <?= $this->url->icon('folder', t('Projects list'), 'ProjectListController', 'show') ?>
</li>
<?php if ($this->user->hasAccess('ProjectGanttController', 'show')): ?>
<li>
- <i class="fa fa-sliders fa-fw"></i>
- <?= $this->url->link(t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?>
+ <?= $this->url->icon('sliders', t('Projects Gantt chart'), 'ProjectGanttController', 'show') ?>
</li>
<?php endif ?>
</ul>
</div>
<section class="sidebar-container">
-
<?= $this->render($sidebar_template, array('users' => $users, 'filter' => $filter)) ?>
<div class="sidebar-content">
diff --git a/app/Template/project_view/share.php b/app/Template/project_view/share.php
index 409f37e6..87c63916 100644
--- a/app/Template/project_view/share.php
+++ b/app/Template/project_view/share.php
@@ -4,11 +4,11 @@
<?php if ($project['is_public']): ?>
- <div class="listing">
+ <div class="panel">
<ul class="no-bullet">
- <li><strong><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('share-alt', t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token']), false, '', '', true) ?></strong></li>
</ul>
</div>
diff --git a/app/Template/project_view/show.php b/app/Template/project_view/show.php
index afe60384..29d558b1 100644
--- a/app/Template/project_view/show.php
+++ b/app/Template/project_view/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Summary') ?></h2>
</div>
-<ul class="listing">
+<ul class="panel">
<li><strong><?= $project['is_active'] ? t('Active') : t('Inactive') ?></strong></li>
<?php if ($project['owner_id'] > 0): ?>
@@ -13,9 +13,9 @@
<?php endif ?>
<?php if ($project['is_public']): ?>
- <li><i class="fa fa-share-alt"></i> <?= $this->url->link(t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
- <li><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
+ <li><?= $this->url->icon('share-alt', t('Public link'), 'BoardViewController', 'readonly', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'project', array('token' => $project['token']), false, '', '', true) ?></li>
+ <li><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'project', array('token' => $project['token'])) ?></li>
<?php else: ?>
<li><?= t('Public access disabled') ?></li>
<?php endif ?>
diff --git a/app/Template/search/activity.php b/app/Template/search/activity.php
index 1dfd9234..2582162b 100644
--- a/app/Template/search/activity.php
+++ b/app/Template/search/activity.php
@@ -2,8 +2,7 @@
<div class="page-header">
<ul>
<li>
- <i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Search tasks'), 'SearchController', 'index') ?>
+ <?= $this->url->icon('search', t('Search tasks'), 'SearchController', 'index') ?>
</li>
</ul>
</div>
@@ -23,7 +22,7 @@
</div>
<?php if (empty($values['search'])): ?>
- <div class="listing">
+ <div class="panel">
<h3><?= t('Advanced search') ?></h3>
<p><?= t('Example of query: ') ?><strong>project:"My project" creator:me</strong></p>
<ul>
diff --git a/app/Template/search/index.php b/app/Template/search/index.php
index c59a5c99..9a5f2931 100644
--- a/app/Template/search/index.php
+++ b/app/Template/search/index.php
@@ -2,8 +2,7 @@
<div class="page-header">
<ul>
<li>
- <i class="fa fa-search fa-fw"></i>
- <?= $this->url->link(t('Activity stream search'), 'SearchController', 'activity') ?>
+ <?= $this->url->icon('search', t('Activity stream search'), 'SearchController', 'activity') ?>
</li>
</ul>
</div>
@@ -23,7 +22,7 @@
</div>
<?php if (empty($values['search'])): ?>
- <div class="listing">
+ <div class="panel">
<h3><?= t('Advanced search') ?></h3>
<p><?= t('Example of query: ') ?><strong>project:"My project" assignee:me due:tomorrow</strong></p>
<ul>
diff --git a/app/Template/subtask/create.php b/app/Template/subtask/create.php
index cc4ccba6..96ad7a46 100644
--- a/app/Template/subtask/create.php
+++ b/app/Template/subtask/create.php
@@ -2,20 +2,17 @@
<h2><?= t('Add a sub-task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('SubtaskController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('SubtaskController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
- <?= $this->subtask->selectTitle($values, $errors, array('autofocus')) ?>
- <?= $this->subtask->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->subtask->selectTimeEstimated($values, $errors) ?>
+ <?= $this->subtask->renderTitleField($values, $errors, array('autofocus')) ?>
+ <?= $this->subtask->renderAssigneeField($users_list, $values, $errors) ?>
+ <?= $this->subtask->renderTimeEstimatedField($values, $errors) ?>
+
<?= $this->hook->render('template:subtask:form:create', array('values' => $values, 'errors' => $errors)) ?>
<?= $this->form->checkbox('another_subtask', t('Create another sub-task'), 1, isset($values['another_subtask']) && $values['another_subtask'] == 1) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/subtask/edit.php b/app/Template/subtask/edit.php
index 07419f79..7c0266a8 100644
--- a/app/Template/subtask/edit.php
+++ b/app/Template/subtask/edit.php
@@ -2,20 +2,17 @@
<h2><?= t('Edit a sub-task') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('SubtaskController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off">
-
+<form method="post" action="<?= $this->url->href('SubtaskController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('task_id', $values) ?>
- <?= $this->subtask->selectTitle($values, $errors, array('autofocus')) ?>
- <?= $this->subtask->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->subtask->selectTimeEstimated($values, $errors) ?>
- <?= $this->subtask->selectTimeSpent($values, $errors) ?>
+
+ <?= $this->subtask->renderTitleField($values, $errors, array('autofocus')) ?>
+ <?= $this->subtask->renderAssigneeField($users_list, $values, $errors) ?>
+ <?= $this->subtask->renderTimeEstimatedField($values, $errors) ?>
+ <?= $this->subtask->renderTimeSpentField($values, $errors) ?>
+
<?= $this->hook->render('template:subtask:form:edit', array('values' => $values, 'errors' => $errors)) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/subtask/menu.php b/app/Template/subtask/menu.php
index d5d1bf85..a0743a70 100644
--- a/app/Template/subtask/menu.php
+++ b/app/Template/subtask/menu.php
@@ -2,16 +2,13 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-pencil-square-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'SubtaskController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'SubtaskController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>
</li>
<li>
- <i class="fa fa-trash-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'SubtaskController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'SubtaskController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>
</li>
<li>
- <i class="fa fa-clone" aria-hidden="true"></i>
- <?= $this->url->link(t('Convert to task'), 'SubtaskConverterController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('clone', t('Convert to task'), 'SubtaskConverterController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/subtask/remove.php b/app/Template/subtask/remove.php
index 426c1a93..cf9bbc35 100644
--- a/app/Template/subtask/remove.php
+++ b/app/Template/subtask/remove.php
@@ -12,9 +12,9 @@
</ul>
</div>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'SubtaskController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'SubtaskController',
+ 'remove',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])
+ ) ?>
</div>
diff --git a/app/Template/subtask/table.php b/app/Template/subtask/table.php
index bea49aed..156e08c1 100644
--- a/app/Template/subtask/table.php
+++ b/app/Template/subtask/table.php
@@ -45,12 +45,10 @@
<?php if ($editable && $subtask['user_id'] == $this->user->getId()): ?>
<li>
<?php if ($subtask['is_timer_started']): ?>
- <i class="fa fa-pause"></i>
- <?= $this->url->link(t('Stop timer'), 'SubtaskStatusController', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
+ <?= $this->url->icon('pause', t('Stop timer'), 'SubtaskStatusController', 'timer', array('timer' => 'stop', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
(<?= $this->dt->age($subtask['timer_start_date']) ?>)
<?php else: ?>
- <i class="fa fa-play-circle-o"></i>
- <?= $this->url->link(t('Start timer'), 'SubtaskStatusController', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
+ <?= $this->url->icon('play-circle-o', t('Start timer'), 'SubtaskStatusController', 'timer', array('timer' => 'start', 'project_id' => $task['project_id'], 'task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id']), false, 'subtask-toggle-timer') ?>
<?php endif ?>
</li>
<?php endif ?>
diff --git a/app/Template/subtask_converter/show.php b/app/Template/subtask_converter/show.php
index 63f45482..9ecc70c8 100644
--- a/app/Template/subtask_converter/show.php
+++ b/app/Template/subtask_converter/show.php
@@ -12,9 +12,9 @@
</ul>
</div>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'SubtaskConverterController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'SubtaskConverterController',
+ 'save',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])
+ ) ?>
</div>
diff --git a/app/Template/subtask_restriction/show.php b/app/Template/subtask_restriction/show.php
index ec8b8d5b..b6c56a12 100644
--- a/app/Template/subtask_restriction/show.php
+++ b/app/Template/subtask_restriction/show.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('You already have one subtask in progress') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('SubtaskRestrictionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" method="post">
+<form action="<?= $this->url->href('SubtaskRestrictionController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'subtask_id' => $subtask['id'])) ?>" method="post">
<?= $this->form->csrf() ?>
@@ -9,9 +9,5 @@
<?= $this->form->radios('status', $status_list) ?>
<?= $this->form->hidden('id', $subtask_inprogress) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-red"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/swimlane/create.php b/app/Template/swimlane/create.php
index 207b526c..7d05e731 100644
--- a/app/Template/swimlane/create.php
+++ b/app/Template/swimlane/create.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Add a new swimlane') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('SwimlaneController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -12,9 +12,5 @@
<?= $this->form->label(t('Description'), 'description') ?>
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="3"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/swimlane/edit.php b/app/Template/swimlane/edit.php
index d225b345..c1c41196 100644
--- a/app/Template/swimlane/edit.php
+++ b/app/Template/swimlane/edit.php
@@ -2,7 +2,7 @@
<h2><?= t('Swimlane modification for the project "%s"', $project['name']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'update', array('project_id' => $project['id'], 'swimlane_id' => $values['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('SwimlaneController', 'update', array('project_id' => $project['id'], 'swimlane_id' => $values['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -15,9 +15,5 @@
<?= $this->form->label(t('Description'), 'description') ?>
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 2)) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="3"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/swimlane/edit_default.php b/app/Template/swimlane/edit_default.php
index 8a0c0a15..a2c3ee73 100644
--- a/app/Template/swimlane/edit_default.php
+++ b/app/Template/swimlane/edit_default.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Change default swimlane') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('SwimlaneController', 'updateDefault', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('SwimlaneController', 'updateDefault', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
@@ -10,9 +10,5 @@
<?= $this->form->checkbox('show_default_swimlane', t('Show default swimlane'), 1, $values['show_default_swimlane'] == 1) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/swimlane/index.php b/app/Template/swimlane/index.php
index 4f78a405..e05b9088 100644
--- a/app/Template/swimlane/index.php
+++ b/app/Template/swimlane/index.php
@@ -2,8 +2,7 @@
<h2><?= t('Swimlanes') ?></h2>
<ul>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a new swimlane'), 'SwimlaneController', 'create', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a new swimlane'), 'SwimlaneController', 'create', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/swimlane/remove.php b/app/Template/swimlane/remove.php
index f16b778c..02d1e322 100644
--- a/app/Template/swimlane/remove.php
+++ b/app/Template/swimlane/remove.php
@@ -1,17 +1,15 @@
-<section id="main">
- <div class="page-header">
- <h2><?= t('Remove a swimlane') ?></h2>
- </div>
+<div class="page-header">
+ <h2><?= t('Remove a swimlane') ?></h2>
+</div>
- <div class="confirm">
- <p class="alert alert-info">
- <?= t('Do you really want to remove this swimlane: "%s"?', $swimlane['name']) ?>
- </p>
+<div class="confirm">
+ <p class="alert alert-info">
+ <?= t('Do you really want to remove this swimlane: "%s"?', $swimlane['name']) ?>
+ </p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'SwimlaneController', 'remove', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'SwimlaneController', 'index', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
- </div>
-</section>
+ <?= $this->modal->confirmButtons(
+ 'SwimlaneController',
+ 'remove',
+ array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])
+ ) ?>
+</div>
diff --git a/app/Template/swimlane/table.php b/app/Template/swimlane/table.php
index 81daed01..2d783a00 100644
--- a/app/Template/swimlane/table.php
+++ b/app/Template/swimlane/table.php
@@ -20,16 +20,13 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'SwimlaneController', 'editDefault', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'SwimlaneController', 'editDefault', array('project_id' => $project['id'])) ?>
</li>
<li>
<?php if ($default_swimlane['show_default_swimlane'] == 1): ?>
- <i class="fa fa-toggle-off fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Disable'), 'SwimlaneController', 'disableDefault', array('project_id' => $project['id']), true) ?>
+ <?= $this->url->icon('toggle-off', t('Disable'), 'SwimlaneController', 'disableDefault', array('project_id' => $project['id']), true) ?>
<?php else: ?>
- <i class="fa fa-toggle-on fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Enable'), 'SwimlaneController', 'enableDefault', array('project_id' => $project['id']), true) ?>
+ <?= $this->url->icon('toggle-on', t('Enable'), 'SwimlaneController', 'enableDefault', array('project_id' => $project['id']), true) ?>
<?php endif ?>
</li>
</ul>
@@ -58,21 +55,17 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'SwimlaneController', 'edit', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
<li>
<?php if ($swimlane['is_active']): ?>
- <i class="fa fa-toggle-off fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
+ <?= $this->url->icon('toggle-off', t('Disable'), 'SwimlaneController', 'disable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php else: ?>
- <i class="fa fa-toggle-on fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
+ <?= $this->url->icon('toggle-on', t('Enable'), 'SwimlaneController', 'enable', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), true) ?>
<?php endif ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'SwimlaneController', 'confirm', array('project_id' => $project['id'], 'swimlane_id' => $swimlane['id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/tag/create.php b/app/Template/tag/create.php
index 9b32bc46..752a63e5 100644
--- a/app/Template/tag/create.php
+++ b/app/Template/tag/create.php
@@ -1,16 +1,12 @@
<div class="page-header">
<h2><?= t('Add new tag') ?></h2>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('TagController', 'save') ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TagController', 'save') ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('project_id', $values) ?>
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="255"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TagController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/tag/edit.php b/app/Template/tag/edit.php
index f751ff49..adef3568 100644
--- a/app/Template/tag/edit.php
+++ b/app/Template/tag/edit.php
@@ -1,7 +1,7 @@
<div class="page-header">
<h2><?= t('Edit a tag') ?></h2>
</div>
-<form method="post" class="popover-form" action="<?= $this->url->href('TagController', 'update', array('tag_id' => $tag['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TagController', 'update', array('tag_id' => $tag['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
@@ -9,9 +9,5 @@
<?= $this->form->label(t('Name'), 'name') ?>
<?= $this->form->text('name', $values, $errors, array('autofocus', 'required', 'maxlength="255"')) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TagController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/tag/index.php b/app/Template/tag/index.php
index 8e0c9a06..834e8e7c 100644
--- a/app/Template/tag/index.php
+++ b/app/Template/tag/index.php
@@ -2,8 +2,7 @@
<h2><?= t('Global tags') ?></h2>
<ul>
<li>
- <i class="fa fa-plus" aria-hidden="true"></i>
- <?= $this->url->link(t('Add new tag'), 'TagController', 'create', array(), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add new tag'), 'TagController', 'create') ?>
</li>
</ul>
</div>
@@ -20,10 +19,8 @@
<tr>
<td><?= $this->text->e($tag['name']) ?></td>
<td>
- <i class="fa fa-times" aria-hidden="true"></i>
- <?= $this->url->link(t('Remove'), 'TagController', 'confirm', array('tag_id' => $tag['id']), false, 'popover') ?>
- <i class="fa fa-pencil-square-o" aria-hidden="true"></i>
- <?= $this->url->link(t('Edit'), 'TagController', 'edit', array('tag_id' => $tag['id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'TagController', 'edit', array('tag_id' => $tag['id'])) ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TagController', 'confirm', array('tag_id' => $tag['id'])) ?>
</td>
</tr>
<?php endforeach ?>
diff --git a/app/Template/tag/remove.php b/app/Template/tag/remove.php
index 46ea3f99..47ba8d3d 100644
--- a/app/Template/tag/remove.php
+++ b/app/Template/tag/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this tag: "%s"?', $tag['name']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TagController', 'remove', array('tag_id' => $tag['id']), true, 'btn btn-red popover-link') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TagController', 'index', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TagController',
+ 'remove',
+ array('tag_id' => $tag['id'])
+ ) ?>
</div>
diff --git a/app/Template/task/analytics.php b/app/Template/task/analytics.php
index 28c0189c..2d968188 100644
--- a/app/Template/task/analytics.php
+++ b/app/Template/task/analytics.php
@@ -9,7 +9,7 @@
<h2><?= t('Analytics') ?></h2>
</div>
-<div class="listing">
+<div class="panel">
<ul>
<li><?= t('Lead time: ').'<strong>'.$this->dt->duration($lead_time) ?></strong></li>
<li><?= t('Cycle time: ').'<strong>'.$this->dt->duration($cycle_time) ?></strong></li>
diff --git a/app/Template/task/details.php b/app/Template/task/details.php
index 202991d2..24099a3c 100644
--- a/app/Template/task/details.php
+++ b/app/Template/task/details.php
@@ -33,16 +33,14 @@
<?php if ($project['is_public']): ?>
<li>
<small>
- <i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Public link'), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?>
+ <?= $this->url->icon('external-link', t('Public link'), 'TaskViewController', 'readonly', array('task_id' => $task['id'], 'token' => $project['token']), false, '', '', true) ?>
</small>
</li>
<?php endif ?>
<?php if ($project['is_public'] && !$editable): ?>
<li>
<small>
- <i class="fa fa-th fa-fw"></i>
- <?= $this->url->link(t('Back to the board'), 'BoardViewController', 'readonly', array('token' => $project['token'])) ?>
+ <?= $this->url->icon('th', t('Back to the board'), 'BoardViewController', 'readonly', array('token' => $project['token'])) ?>
</small>
</li>
<?php endif ?>
@@ -168,7 +166,7 @@
<?php if ($editable && empty($task['date_started'])): ?>
<div class="buttons-header">
- <?= $this->url->button('fa-play', t('Set start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->button('play', t('Set start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</div>
<?php endif ?>
diff --git a/app/Template/task/dropdown.php b/app/Template/task/dropdown.php
index 86428059..1daf8896 100644
--- a/app/Template/task/dropdown.php
+++ b/app/Template/task/dropdown.php
@@ -3,60 +3,47 @@
<ul>
<?php if (array_key_exists('date_started', $task) && empty($task['date_started'])): ?>
<li>
- <i class="fa fa-play fa-fw"></i>
- <?= $this->url->link(t('Set automatically the start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('play', t('Set automatically the start date'), 'TaskModificationController', 'start', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-pencil-square-o fa-fw"></i>
- <?= $this->url->link(t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->large('edit', t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-code-fork fa-fw"></i>
- <?= $this->url->link(t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('code-fork', t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('external-link', t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-comment-o fa-fw"></i>
- <?= $this->url->link(t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('comment-o', t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-camera fa-fw"></i>
- <?= $this->url->link(t('Add a screenshot'), 'TaskPopoverController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('camera', t('Add a screenshot'), 'TaskPopoverController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-files-o fa-fw"></i>
- <?= $this->url->link(t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('files-o', t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-clipboard fa-fw"></i>
- <?= $this->url->link(t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('clipboard', t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-clone fa-fw"></i>
- <?= $this->url->link(t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('clone', t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php if ($this->projectRole->canRemoveTask($task)): ?>
<li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?php if (isset($task['is_active']) && $this->projectRole->canChangeTaskStatusInColumn($task['project_id'], $task['column_id'])): ?>
<li>
<?php if ($task['is_active'] == 1): ?>
- <i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('times', t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
<?php else: ?>
- <i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('check-square-o', t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
<?php endif ?>
</li>
<?php endif ?>
diff --git a/app/Template/task/sidebar.php b/app/Template/task/sidebar.php
index 9472b6ba..f8f1ebde 100644
--- a/app/Template/task/sidebar.php
+++ b/app/Template/task/sidebar.php
@@ -4,25 +4,20 @@
</div>
<ul>
<li <?= $this->app->checkMenuSelection('TaskViewController', 'show') ?>>
- <i class="fa fa-newspaper-o fa-fw"></i>
- <?= $this->url->link(t('Summary'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('newspaper-o', t('Summary'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('ActivityController', 'task') ?>>
- <i class="fa fa-dashboard fa-fw"></i>
- <?= $this->url->link(t('Activity stream'), 'ActivityController', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('dashboard', t('Activity stream'), 'ActivityController', 'task', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('TaskViewController', 'transitions') ?>>
- <i class="fa fa-arrows-h fa-fw"></i>
- <?= $this->url->link(t('Transitions'), 'TaskViewController', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('arrows-h', t('Transitions'), 'TaskViewController', 'transitions', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('TaskViewController', 'analytics') ?>>
- <i class="fa fa-bar-chart fa-fw"></i>
- <?= $this->url->link(t('Analytics'), 'TaskViewController', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('bar-chart', t('Analytics'), 'TaskViewController', 'analytics', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php if ($task['time_estimated'] > 0 || $task['time_spent'] > 0): ?>
<li <?= $this->app->checkMenuSelection('TaskViewController', 'timetracking') ?>>
- <i class="fa fa-clock-o fa-fw"></i>
- <?= $this->url->link(t('Time tracking'), 'TaskViewController', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
+ <?= $this->url->icon('clock-o', t('Time tracking'), 'TaskViewController', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
@@ -35,72 +30,57 @@
</div>
<ul>
<li>
- <i class="fa fa-pencil-square-o fa-fw"></i>
- <?= $this->url->link(t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->large('edit', t('Edit the task'), 'TaskModificationController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-refresh fa-rotate-90 fa-fw"></i>
- <?= $this->url->link(t('Edit recurrence'), 'TaskRecurrenceController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('refresh fa-rotate-90', t('Edit recurrence'), 'TaskRecurrenceController', 'edit', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('plus', t('Add a sub-task'), 'SubtaskController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-code-fork fa-fw"></i>
- <?= $this->url->link(t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('code-fork', t('Add internal link'), 'TaskInternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-external-link fa-fw"></i>
- <?= $this->url->link(t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('external-link', t('Add external link'), 'TaskExternalLinkController', 'find', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-comment-o fa-fw"></i>
- <?= $this->url->link(t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('comment-o', t('Add a comment'), 'CommentController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-file fa-fw"></i>
- <?= $this->url->link(t('Attach a document'), 'TaskFileController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('file', t('Attach a document'), 'TaskFileController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-camera fa-fw"></i>
- <?= $this->url->link(t('Add a screenshot'), 'TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('camera', t('Add a screenshot'), 'TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-files-o fa-fw"></i>
- <?= $this->url->link(t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('files-o', t('Duplicate'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-clipboard fa-fw"></i>
- <?= $this->url->link(t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('clipboard', t('Duplicate to another project'), 'TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-clone fa-fw"></i>
- <?= $this->url->link(t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('clone', t('Move to another project'), 'TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php if ($task['is_active'] == 1 && $this->projectRole->isSortableColumn($task['project_id'], $task['column_id'])): ?>
<li>
- <i class="fa fa-arrows fa-fw"></i>
- <?= $this->url->link(t('Move position'), 'TaskMovePositionController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->small('arrows', t('Move position'), 'TaskMovePositionController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?php if ($this->projectRole->canChangeTaskStatusInColumn($task['project_id'], $task['column_id'])): ?>
<?php if ($task['is_active'] == 1): ?>
<li>
- <i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('times', t('Close this task'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php else: ?>
<li>
- <i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('check-square-o', t('Open this task'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<?php endif ?>
<?php endif ?>
<?php if ($this->projectRole->canRemoveTask($task)): ?>
<li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskSuppressionController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board')) ?>
</li>
<?php endif ?>
diff --git a/app/Template/task/time_tracking_summary.php b/app/Template/task/time_tracking_summary.php
index 9886ccfa..63de733a 100644
--- a/app/Template/task/time_tracking_summary.php
+++ b/app/Template/task/time_tracking_summary.php
@@ -1,13 +1,13 @@
<?php if ($task['time_estimated'] > 0 || $task['time_spent'] > 0): ?>
+ <div class="page-header">
+ <h2><?= t('Time tracking') ?></h2>
+ </div>
-<div class="page-header">
- <h2><?= t('Time tracking') ?></h2>
-</div>
-
-<ul class="listing">
- <li><?= t('Estimate:') ?> <strong><?= $this->text->e($task['time_estimated']) ?></strong> <?= t('hours') ?></li>
- <li><?= t('Spent:') ?> <strong><?= $this->text->e($task['time_spent']) ?></strong> <?= t('hours') ?></li>
- <li><?= t('Remaining:') ?> <strong><?= $this->text->e($task['time_estimated'] - $task['time_spent']) ?></strong> <?= t('hours') ?></li>
-</ul>
-
+ <div class="panel">
+ <ul>
+ <li><?= t('Estimate:') ?> <strong><?= $this->text->e($task['time_estimated']) ?></strong> <?= t('hours') ?></li>
+ <li><?= t('Spent:') ?> <strong><?= $this->text->e($task['time_spent']) ?></strong> <?= t('hours') ?></li>
+ <li><?= t('Remaining:') ?> <strong><?= $this->text->e($task['time_estimated'] - $task['time_spent']) ?></strong> <?= t('hours') ?></li>
+ </ul>
+ </div>
<?php endif ?> \ No newline at end of file
diff --git a/app/Template/task_bulk/show.php b/app/Template/task_bulk/show.php
index 11ddea31..acf80d8c 100644
--- a/app/Template/task_bulk/show.php
+++ b/app/Template/task_bulk/show.php
@@ -2,23 +2,20 @@
<h2><?= $this->text->e($project['name']) ?> &gt; <?= t('Create tasks in bulk') ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskBulkController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TaskBulkController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('column_id', $values) ?>
<?= $this->form->hidden('swimlane_id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
- <?= $this->task->selectColor($values) ?>
- <?= $this->task->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->task->selectCategory($categories_list, $values, $errors) ?>
+ <?= $this->task->renderColorField($values) ?>
+ <?= $this->task->renderAssigneeField($users_list, $values, $errors) ?>
+ <?= $this->task->renderCategoryField($categories_list, $values, $errors) ?>
<?= $this->form->label(t('Tasks'), 'tasks') ?>
<?= $this->form->textarea('tasks', $values, $errors, array('placeholder="'.t('My task title').'"')) ?>
<p class="form-help"><?= t('Enter one task by line.') ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $project['id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_creation/duplicate_projects.php b/app/Template/task_creation/duplicate_projects.php
index dc0fa105..202b3ffe 100644
--- a/app/Template/task_creation/duplicate_projects.php
+++ b/app/Template/task_creation/duplicate_projects.php
@@ -5,10 +5,10 @@
<?php if (empty($projects_list)): ?>
<p class="alert"><?= t('There is no destination project available.') ?></p>
<div class="form-actions">
- <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $task['project_id']), false, 'close-popover btn') ?>
+ <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $task['project_id']), false, 'js-modal-close btn') ?>
</div>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('TaskCreationController', 'duplicateProjects', array('project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('TaskCreationController', 'duplicateProjects', array('project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', $values) ?>
@@ -20,9 +20,6 @@
array('multiple')
) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Duplicate') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/task_creation/show.php b/app/Template/task_creation/show.php
index 840d1804..e957087f 100644
--- a/app/Template/task_creation/show.php
+++ b/app/Template/task_creation/show.php
@@ -1,50 +1,48 @@
<div class="page-header">
<h2><?= $this->text->e($project['name']) ?> &gt; <?= t('New task') ?><?= $this->task->getNewTaskDropdown($project['id'], $values['swimlane_id'], $values['column_id']) ?></h2>
</div>
-
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TaskCreationController', 'save', array('project_id' => $project['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
+ <?= $this->form->hidden('project_id', $values) ?>
+
+ <div class="task-form-container">
+ <div class="task-form-main-column">
+ <?= $this->task->renderTitleField($values, $errors) ?>
+ <?= $this->task->renderDescriptionField($values, $errors) ?>
+ <?= $this->task->renderTagField($project) ?>
- <div class="form-columns">
- <div class="form-column">
- <?= $this->task->selectTitle($values, $errors) ?>
- <?= $this->task->selectDescription($values, $errors) ?>
- <?= $this->task->selectTags($project) ?>
-
<?= $this->hook->render('template:task:form:first-column', array('values' => $values, 'errors' => $errors)) ?>
-
- <?php if (! isset($duplicate)): ?>
- <?= $this->form->checkbox('another_task', t('Create another task'), 1, isset($values['another_task']) && $values['another_task'] == 1) ?>
- <?= $this->form->checkbox('duplicate_multiple_projects', t('Duplicate to multiple projects'), 1) ?>
- <?php endif ?>
</div>
- <div class="form-column">
- <?= $this->form->hidden('project_id', $values) ?>
- <?= $this->task->selectColor($values) ?>
- <?= $this->task->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->task->selectCategory($categories_list, $values, $errors) ?>
- <?= $this->task->selectSwimlane($swimlanes_list, $values, $errors) ?>
- <?= $this->task->selectColumn($columns_list, $values, $errors) ?>
- <?= $this->task->selectPriority($project, $values) ?>
- <?= $this->task->selectScore($values, $errors) ?>
- <?= $this->task->selectReference($values, $errors) ?>
+ <div class="task-form-secondary-column">
+ <?= $this->task->renderColorField($values) ?>
+ <?= $this->task->renderAssigneeField($users_list, $values, $errors) ?>
+ <?= $this->task->renderCategoryField($categories_list, $values, $errors) ?>
+ <?= $this->task->renderSwimlaneField($swimlanes_list, $values, $errors) ?>
+ <?= $this->task->renderColumnField($columns_list, $values, $errors) ?>
+ <?= $this->task->renderPriorityField($project, $values) ?>
<?= $this->hook->render('template:task:form:second-column', array('values' => $values, 'errors' => $errors)) ?>
</div>
- <div class="form-column">
- <?= $this->task->selectTimeEstimated($values, $errors) ?>
- <?= $this->task->selectTimeSpent($values, $errors) ?>
- <?= $this->task->selectStartDate($values, $errors) ?>
- <?= $this->task->selectDueDate($values, $errors) ?>
+ <div class="task-form-secondary-column">
+ <?= $this->task->renderDueDateField($values, $errors) ?>
+ <?= $this->task->renderStartDateField($values, $errors) ?>
+ <?= $this->task->renderTimeEstimatedField($values, $errors) ?>
+ <?= $this->task->renderTimeSpentField($values, $errors) ?>
+ <?= $this->task->renderScoreField($values, $errors) ?>
+ <?= $this->task->renderReferenceField($values, $errors) ?>
<?= $this->hook->render('template:task:form:third-column', array('values' => $values, 'errors' => $errors)) ?>
</div>
- </div>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'BoardViewController', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
+ <div class="task-form-bottom">
+ <?php if (! isset($duplicate)): ?>
+ <?= $this->form->checkbox('another_task', t('Create another task'), 1, isset($values['another_task']) && $values['another_task'] == 1) ?>
+ <?= $this->form->checkbox('duplicate_multiple_projects', t('Duplicate to multiple projects'), 1) ?>
+ <?php endif ?>
+
+ <?= $this->modal->submitButtons() ?>
+ </div>
</div>
</form>
diff --git a/app/Template/task_duplication/copy.php b/app/Template/task_duplication/copy.php
index 65cfe4d6..d96960fc 100644
--- a/app/Template/task_duplication/copy.php
+++ b/app/Template/task_duplication/copy.php
@@ -5,25 +5,25 @@
<?php if (empty($projects_list)): ?>
<p class="alert"><?= t('There is no destination project available.') ?></p>
<div class="form-actions">
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover btn') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'js-modal-close btn') ?>
</div>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
-
+ <form method="post" action="<?= $this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->label(t('Project'), 'project_id') ?>
- <?= $this->form->select(
- 'project_id',
- $projects_list,
- $values,
- array(),
- array('data-redirect="'.$this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
- 'task-reload-project-destination'
- ) ?>
- <span class="loading-icon" style="display: none">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>
+ <?= $this->app->component('select-dropdown-autocomplete', array(
+ 'name' => 'project_id',
+ 'items' => $projects_list,
+ 'defaultValue' => isset($values['project_id']) ? $values['project_id'] : null,
+ 'placeholder' => t('Choose a project'),
+ 'replace' => array(
+ 'regex' => 'PROJECT_ID',
+ 'url' => $this->url->href('TaskDuplicationController', 'copy', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')),
+ )
+ )) ?>
<?= $this->form->label(t('Swimlane'), 'swimlane_id') ?>
<?= $this->form->select('swimlane_id', $swimlanes_list, $values) ?>
@@ -41,10 +41,6 @@
<?= $this->form->select('owner_id', $users_list, $values) ?>
<p class="form-help"><?= t('Current assignee: %s', ($task['assignee_name'] ?: $task['assignee_username']) ?: e('not assigned')) ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/task_duplication/duplicate.php b/app/Template/task_duplication/duplicate.php
index c0baf94e..aa02b78c 100644
--- a/app/Template/task_duplication/duplicate.php
+++ b/app/Template/task_duplication/duplicate.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to duplicate this task?') ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskDuplicationController', 'duplicate', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskDuplicationController',
+ 'duplicate',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes')
+ ) ?>
</div>
diff --git a/app/Template/task_duplication/move.php b/app/Template/task_duplication/move.php
index 717d15e9..16ce2464 100644
--- a/app/Template/task_duplication/move.php
+++ b/app/Template/task_duplication/move.php
@@ -5,25 +5,26 @@
<?php if (empty($projects_list)): ?>
<p class="alert"><?= t('There is no destination project available.') ?></p>
<div class="form-actions">
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover btn') ?>
+ <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'js-modal-close btn') ?>
</div>
<?php else: ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->label(t('Project'), 'project_id') ?>
- <?= $this->form->select(
- 'project_id',
- $projects_list,
- $values,
- array(),
- array('data-redirect="'.$this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')).'"'),
- 'task-reload-project-destination'
- ) ?>
- <span class="loading-icon" style="display: none">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>
+ <?= $this->app->component('select-dropdown-autocomplete', array(
+ 'name' => 'project_id',
+ 'items' => $projects_list,
+ 'defaultValue' => isset($values['project_id']) ? $values['project_id'] : null,
+ 'placeholder' => t('Choose a project'),
+ 'replace' => array(
+ 'regex' => 'PROJECT_ID',
+ 'url' => $this->url->href('TaskDuplicationController', 'move', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'dst_project_id' => 'PROJECT_ID')),
+ )
+ )) ?>
<?= $this->form->label(t('Swimlane'), 'swimlane_id') ?>
<?= $this->form->select('swimlane_id', $swimlanes_list, $values) ?>
@@ -41,11 +42,7 @@
<?= $this->form->select('owner_id', $users_list, $values) ?>
<p class="form-help"><?= t('Current assignee: %s', ($task['assignee_name'] ?: $task['assignee_username']) ?: e('not assigned')) ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/task_external_link/create.php b/app/Template/task_external_link/create.php
index beddfc90..04d9bed0 100644
--- a/app/Template/task_external_link/create.php
+++ b/app/Template/task_external_link/create.php
@@ -2,12 +2,7 @@
<h2><?= t('Add a new external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('TaskExternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->render('task_external_link/form', array('task' => $task, 'dependencies' => $dependencies, 'values' => $values, 'errors' => $errors)) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_external_link/edit.php b/app/Template/task_external_link/edit.php
index 917a28b9..df10d444 100644
--- a/app/Template/task_external_link/edit.php
+++ b/app/Template/task_external_link/edit.php
@@ -2,12 +2,7 @@
<h2><?= t('Edit external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('TaskExternalLinkController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->render('task_external_link/form', array('task' => $task, 'dependencies' => $dependencies, 'values' => $values, 'errors' => $errors)) ?>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_external_link/find.php b/app/Template/task_external_link/find.php
index a88b29ce..a3665c0d 100644
--- a/app/Template/task_external_link/find.php
+++ b/app/Template/task_external_link/find.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new external link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskExternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('TaskExternalLinkController', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', array('task_id' => $task['id'])) ?>
@@ -20,9 +20,5 @@
<?= $this->form->label(t('Link type'), 'type') ?>
<?= $this->form->select('type', $types, $values) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Next') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_external_link/remove.php b/app/Template/task_external_link/remove.php
index 2a888a60..ed8ad15f 100644
--- a/app/Template/task_external_link/remove.php
+++ b/app/Template/task_external_link/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this link: "%s"?', $link['title']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskExternalLinkController', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskExternalLinkController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskExternalLinkController',
+ 'remove',
+ array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])
+ ) ?>
</div>
diff --git a/app/Template/task_external_link/table.php b/app/Template/task_external_link/table.php
index a5fc7a33..aaa234bb 100644
--- a/app/Template/task_external_link/table.php
+++ b/app/Template/task_external_link/table.php
@@ -33,12 +33,10 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-edit fa-fw"></i>
- <?= $this->url->link(t('Edit'), 'TaskExternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'TaskExternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskExternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskExternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/task_file/create.php b/app/Template/task_file/create.php
index e05cf829..eebb08eb 100644
--- a/app/Template/task_file/create.php
+++ b/app/Template/task_file/create.php
@@ -1,33 +1,20 @@
<div class="page-header">
<h2><?= t('Attach a document') ?></h2>
</div>
-<div id="file-done" style="display:none">
- <p class="alert alert-success">
- <?= t('All files have been uploaded successfully.') ?>
- <?= $this->url->link(t('View uploaded files'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
- </p>
-</div>
-
-<div id="file-error-max-size" style="display:none">
- <p class="alert alert-error">
- <?= t('The maximum allowed file size is %sB.', $this->text->bytes($max_size)) ?>
- <a href="#" id="file-browser"><?= t('Choose files again') ?></a>
- </p>
-</div>
-<div
- id="file-dropzone"
- data-max-size="<?= $max_size ?>"
- data-url="<?= $this->url->href('TaskFileController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>">
- <div id="file-dropzone-inner">
- <?= t('Drag and drop your files here') ?> <?= t('or') ?> <a href="#" id="file-browser"><?= t('choose files') ?></a>
- </div>
-</div>
-
-<input type="file" name="files[]" multiple style="display:none" id="file-form-element">
+<?= $this->app->component('file-upload', array(
+ 'maxSize' => $max_size,
+ 'url' => $this->url->to('TaskFileController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])),
+ 'labelDropzone' => t('Drag and drop your files here'),
+ 'labelOr' => t('or'),
+ 'labelChooseFiles' => t('choose files'),
+ 'labelOversize' => t('The maximum allowed file size is %sB.', $this->text->bytes($max_size)),
+ 'labelSuccess' => t('All files have been uploaded successfully.'),
+ 'labelCloseSuccess' => t('Close this window'),
+ 'labelUploadError' => t('Unable to upload this file.'),
+)) ?>
-<div class="form-actions">
- <input type="submit" value="<?= t('Upload files') ?>" class="btn btn-blue" id="file-upload-button" disabled>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
-</div>
+<?= $this->modal->submitButtons(array(
+ 'submitLabel' => t('Upload files'),
+ 'disabled' => true,
+)) ?>
diff --git a/app/Template/task_file/files.php b/app/Template/task_file/files.php
index 94c26f73..28633dc4 100644
--- a/app/Template/task_file/files.php
+++ b/app/Template/task_file/files.php
@@ -15,18 +15,20 @@
<ul>
<?php if ($this->file->getPreviewType($file['name']) !== null): ?>
<li>
+ <?= $this->modal->large('eye', t('View file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ </li>
+ <?php elseif ($this->file->getBrowserViewType($file['name']) !== null): ?>
+ <li>
<i class="fa fa-eye fa-fw"></i>
- <?= $this->url->link(t('View file'), 'FileViewerController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->url->link(t('View file'), 'FileViewerController', 'browser', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, '', '', true) ?>
</li>
<?php endif ?>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->icon('download', t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('TaskFileController', 'remove', $task['project_id'])): ?>
<li>
- <i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/task_file/images.php b/app/Template/task_file/images.php
index 8be89274..2143455d 100644
--- a/app/Template/task_file/images.php
+++ b/app/Template/task_file/images.php
@@ -16,16 +16,14 @@
<div class="file-thumbnail-content">
<div class="file-thumbnail-title">
<div class="dropdown">
- <a href="#" class="dropdown-menu dropdown-menu-link-text"><?= $this->text->e($file['name']) ?> <i class="fa fa-caret-down"></i></a>
+ <a href="#" class="dropdown-menu dropdown-menu-link-text" title="<?= $this->text->e($file['name']) ?>"><?= $this->text->e($file['name']) ?> <i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
+ <?= $this->url->icon('download', t('Download'), 'FileViewerController', 'download', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
<?php if ($this->user->hasProjectAccess('TaskFileController', 'remove', $task['project_id'])): ?>
<li>
- <i class="fa fa-trash fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskFileController', 'confirm', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/task_file/remove.php b/app/Template/task_file/remove.php
index 42894f05..e7ffe560 100644
--- a/app/Template/task_file/remove.php
+++ b/app/Template/task_file/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this file: "%s"?', $this->text->e($file['name'])) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskFileController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskFileController',
+ 'remove',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'file_id' => $file['id'])
+ ) ?>
</div>
diff --git a/app/Template/task_file/screenshot.php b/app/Template/task_file/screenshot.php
index 6300159f..dad8c233 100644
--- a/app/Template/task_file/screenshot.php
+++ b/app/Template/task_file/screenshot.php
@@ -6,14 +6,10 @@
<p id="screenshot-inner"><?= t('Take a screenshot and press CTRL+V or ⌘+V to paste here.') ?></p>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post">
- <input type="hidden" name="screenshot"/>
+<form action="<?= $this->url->href('TaskFileController', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post">
<?= $this->form->csrf() ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->app->component('screenshot') ?>
+ <?= $this->modal->submitButtons() ?>
</form>
<p class="alert alert-info"><?= t('This feature does not work with all browsers.') ?></p>
diff --git a/app/Template/task_gantt/show.php b/app/Template/task_gantt/show.php
index c5d338fb..61a476b7 100644
--- a/app/Template/task_gantt/show.php
+++ b/app/Template/task_gantt/show.php
@@ -3,16 +3,13 @@
<div class="menu-inline">
<ul>
<li <?= $sorting === 'board' ? 'class="active"' : '' ?>>
- <i class="fa fa-sort-numeric-asc fa-fw"></i>
- <?= $this->url->link(t('Sort by position'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'board')) ?>
+ <?= $this->url->icon('sort-numeric-asc', t('Sort by position'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'board')) ?>
</li>
<li <?= $sorting === 'date' ? 'class="active"' : '' ?>>
- <i class="fa fa-sort-amount-asc fa-fw"></i>
- <?= $this->url->link(t('Sort by date'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'date')) ?>
+ <?= $this->url->icon('sort-amount-asc', t('Sort by date'), 'TaskGanttController', 'show', array('project_id' => $project['id'], 'sorting' => 'date')) ?>
</li>
<li>
- <i class="fa fa-plus fa-fw"></i>
- <?= $this->url->link(t('Add task'), 'TaskGanttCreationController', 'show', array('project_id' => $project['id']), false, 'popover') ?>
+ <?= $this->modal->large('plus', t('Add task'), 'TaskCreationController', 'show', array('project_id' => $project['id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/task_gantt_creation/show.php b/app/Template/task_gantt_creation/show.php
deleted file mode 100644
index 7906c39a..00000000
--- a/app/Template/task_gantt_creation/show.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<div class="page-header">
- <h2><?= $this->text->e($project['name']) ?> &gt; <?= t('New task') ?></h2>
-</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskGanttCreationController', 'save', array('project_id' => $values['project_id'])) ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('project_id', $values) ?>
- <?= $this->form->hidden('column_id', $values) ?>
- <?= $this->form->hidden('position', $values) ?>
-
- <div class="form-columns">
- <div class="form-column">
- <?= $this->task->selectTitle($values, $errors) ?>
- <?= $this->task->selectDescription($values, $errors) ?>
- <?= $this->task->selectTags($project) ?>
-
- <?= $this->hook->render('template:task:form:first-column', array('values' => $values, 'errors' => $errors)) ?>
- </div>
-
- <div class="form-column">
- <?= $this->task->selectColor($values) ?>
- <?= $this->task->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->task->selectCategory($categories_list, $values, $errors) ?>
- <?= $this->task->selectSwimlane($swimlanes_list, $values, $errors) ?>
- <?= $this->task->selectPriority($project, $values) ?>
- <?= $this->task->selectScore($values, $errors) ?>
- <?= $this->task->selectReference($values, $errors) ?>
-
- <?= $this->hook->render('template:task:form:second-column', array('values' => $values, 'errors' => $errors)) ?>
- </div>
-
- <div class="form-column">
- <?= $this->task->selectTimeEstimated($values, $errors) ?>
- <?= $this->task->selectTimeSpent($values, $errors) ?>
- <?= $this->task->selectStartDate($values, $errors) ?>
- <?= $this->task->selectDueDate($values, $errors) ?>
-
- <?= $this->hook->render('template:task:form:third-column', array('values' => $values, 'errors' => $errors)) ?>
- </div>
- </div>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskGanttController', 'show', array('project_id' => $values['project_id']), false, 'close-popover') ?>
- </div>
-</form>
diff --git a/app/Template/task_import/show.php b/app/Template/task_import/show.php
index cc6a7b3a..20b020d3 100644
--- a/app/Template/task_import/show.php
+++ b/app/Template/task_import/show.php
@@ -15,14 +15,11 @@
<p class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->text->bytes($max_size) : $max_size ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Import') ?></button>
- </div>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Import'))) ?>
</form>
-<div class="page-header">
- <h2><?= t('Instructions') ?></h2>
-</div>
-<div class="alert">
+
+<div class="panel">
+ <h3><?= t('Instructions') ?></h3>
<ul>
<li><?= t('Your file must use the predefined CSV format') ?></li>
<li><?= t('Your file must be encoded in UTF-8') ?></li>
@@ -30,5 +27,7 @@
<li><?= t('Duplicates are not verified for you') ?></li>
<li><?= t('The due date must use the ISO format: YYYY-MM-DD') ?></li>
</ul>
+ <p class="margin-top">
+ <?= $this->url->icon('download', t('Download CSV template'), 'TaskImportController', 'template', array('project_id' => $project['id'])) ?>
+ </p>
</div>
-<p><i class="fa fa-download fa-fw"></i><?= $this->url->link(t('Download CSV template'), 'TaskImportController', 'template', array('project_id' => $project['id'])) ?></p>
diff --git a/app/Template/task_import/sidebar.php b/app/Template/task_import/sidebar.php
deleted file mode 100644
index 04896948..00000000
--- a/app/Template/task_import/sidebar.php
+++ /dev/null
@@ -1,8 +0,0 @@
-<div class="sidebar">
- <ul>
- <li <?= $this->app->checkMenuSelection('TaskImportController', 'show') ?>>
- <?= $this->url->link(t('Tasks').' (CSV)', 'TaskImportController', 'show', array('project_id' => $project['id'])) ?>
- </li>
- <?= $this->hook->render('template:task-import:sidebar') ?>
- </ul>
-</div>
diff --git a/app/Template/task_internal_link/create.php b/app/Template/task_internal_link/create.php
index fed29605..3c39b87c 100644
--- a/app/Template/task_internal_link/create.php
+++ b/app/Template/task_internal_link/create.php
@@ -2,7 +2,7 @@
<h2><?= t('Add a new link') ?></h2>
</div>
-<form class="popover-form" action="<?= $this->url->href('TaskInternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
+<form action="<?= $this->url->href('TaskInternalLinkController', 'save', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" method="post" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('task_id', array('task_id' => $task['id'])) ?>
@@ -25,9 +25,5 @@
),
'autocomplete') ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_internal_link/edit.php b/app/Template/task_internal_link/edit.php
index f4df57bd..5abf7b65 100644
--- a/app/Template/task_internal_link/edit.php
+++ b/app/Template/task_internal_link/edit.php
@@ -26,9 +26,5 @@
),
'autocomplete') ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_internal_link/remove.php b/app/Template/task_internal_link/remove.php
index 966ad116..f8d91a81 100644
--- a/app/Template/task_internal_link/remove.php
+++ b/app/Template/task_internal_link/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this link with task #%d?', $link['opposite_task_id']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskInternalLinkController', 'remove', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskInternalLinkController',
+ 'remove',
+ array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])
+ ) ?>
</div>
diff --git a/app/Template/task_internal_link/table.php b/app/Template/task_internal_link/table.php
index 3a3a2b88..255ecc97 100644
--- a/app/Template/task_internal_link/table.php
+++ b/app/Template/task_internal_link/table.php
@@ -73,12 +73,10 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-edit fa-fw"></i>
- <?= $this->url->link(t('Edit'), 'TaskInternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->medium('edit', t('Edit'), 'TaskInternalLinkController', 'edit', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
<li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'TaskInternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'TaskInternalLinkController', 'confirm', array('link_id' => $link['id'], 'task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</li>
</ul>
</div>
diff --git a/app/Template/task_modification/show.php b/app/Template/task_modification/show.php
index 734b247a..710abedf 100644
--- a/app/Template/task_modification/show.php
+++ b/app/Template/task_modification/show.php
@@ -1,44 +1,42 @@
<div class="page-header">
<h2><?= $this->text->e($project['name']) ?> &gt; <?= $this->text->e($task['title']) ?></h2>
</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('TaskModificationController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+<form method="post" action="<?= $this->url->href('TaskModificationController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->hidden('project_id', $values) ?>
- <div class="form-columns">
- <div class="form-column">
- <?= $this->task->selectTitle($values, $errors) ?>
- <?= $this->task->selectDescription($values, $errors) ?>
- <?= $this->task->selectTags($project, $tags) ?>
+ <div class="task-form-container">
+ <div class="task-form-main-column">
+ <?= $this->task->renderTitleField($values, $errors) ?>
+ <?= $this->task->renderDescriptionField($values, $errors) ?>
+ <?= $this->task->renderTagField($project, $tags) ?>
<?= $this->hook->render('template:task:form:first-column', array('values' => $values, 'errors' => $errors)) ?>
</div>
- <div class="form-column">
- <?= $this->task->selectColor($values) ?>
- <?= $this->task->selectAssignee($users_list, $values, $errors) ?>
- <?= $this->task->selectCategory($categories_list, $values, $errors) ?>
- <?= $this->task->selectPriority($project, $values) ?>
- <?= $this->task->selectScore($values, $errors) ?>
- <?= $this->task->selectReference($values, $errors) ?>
+ <div class="task-form-secondary-column">
+ <?= $this->task->renderColorField($values) ?>
+ <?= $this->task->renderAssigneeField($users_list, $values, $errors) ?>
+ <?= $this->task->renderCategoryField($categories_list, $values, $errors) ?>
+ <?= $this->task->renderPriorityField($project, $values) ?>
<?= $this->hook->render('template:task:form:second-column', array('values' => $values, 'errors' => $errors)) ?>
</div>
- <div class="form-column">
- <?= $this->task->selectTimeEstimated($values, $errors) ?>
- <?= $this->task->selectTimeSpent($values, $errors) ?>
- <?= $this->task->selectStartDate($values, $errors) ?>
- <?= $this->task->selectDueDate($values, $errors) ?>
+ <div class="task-form-secondary-column">
+ <?= $this->task->renderDueDateField($values, $errors) ?>
+ <?= $this->task->renderStartDateField($values, $errors) ?>
+ <?= $this->task->renderTimeEstimatedField($values, $errors) ?>
+ <?= $this->task->renderTimeSpentField($values, $errors) ?>
+ <?= $this->task->renderScoreField($values, $errors) ?>
+ <?= $this->task->renderReferenceField($values, $errors) ?>
<?= $this->hook->render('template:task:form:third-column', array('values' => $values, 'errors' => $errors)) ?>
</div>
- </div>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue" tabindex="15"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
+ <div class="task-form-bottom">
+ <?= $this->modal->submitButtons() ?>
+ </div>
</div>
</form>
diff --git a/app/Template/task_move_position/show.php b/app/Template/task_move_position/show.php
index 91241016..a73be785 100644
--- a/app/Template/task_move_position/show.php
+++ b/app/Template/task_move_position/show.php
@@ -14,10 +14,6 @@
'afterLabel' => t('Insert after this task'),
)) ?>
-<?= $this->app->component('submit-cancel', array(
- 'submitLabel' => t('Save'),
- 'orLabel' => t('or'),
- 'cancelLabel' => t('cancel'),
-)) ?>
+<?= $this->modal->submitButtons() ?>
</form>
diff --git a/app/Template/task_recurrence/edit.php b/app/Template/task_recurrence/edit.php
index 09d14826..0db27d46 100644
--- a/app/Template/task_recurrence/edit.php
+++ b/app/Template/task_recurrence/edit.php
@@ -3,7 +3,7 @@
</div>
<?php if ($task['recurrence_status'] != \Kanboard\Model\TaskModel::RECURRING_STATUS_NONE): ?>
-<div class="listing">
+<div class="panel">
<?= $this->render('task_recurrence/info', array(
'task' => $task,
'recurrence_trigger_list' => $recurrence_trigger_list,
@@ -15,7 +15,7 @@
<?php if ($task['recurrence_status'] != \Kanboard\Model\TaskModel::RECURRING_STATUS_PROCESSED): ?>
- <form class="popover-form" method="post" action="<?= $this->url->href('TaskRecurrenceController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('TaskRecurrenceController', 'update', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -37,11 +37,7 @@
<?= $this->form->label(t('Base date to calculate new due date'), 'recurrence_basedate') ?>
<?= $this->form->select('recurrence_basedate', $recurrence_basedate_list, $values, $errors) ?>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons() ?>
</form>
<?php endif ?>
diff --git a/app/Template/task_status/close.php b/app/Template/task_status/close.php
index 2d7b0ce5..0bf3c8e3 100644
--- a/app/Template/task_status/close.php
+++ b/app/Template/task_status/close.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to close the task "%s" as well as all subtasks?', $task['title']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskStatusController', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskStatusController',
+ 'close',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes')
+ ) ?>
</div>
diff --git a/app/Template/task_status/open.php b/app/Template/task_status/open.php
index 242b5db5..42765e34 100644
--- a/app/Template/task_status/open.php
+++ b/app/Template/task_status/open.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to open this task: "%s"?', $task['title']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskStatusController', 'open', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes'), true, 'btn btn-red popover-link') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskStatusController',
+ 'open',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'confirmation' => 'yes')
+ ) ?>
</div>
diff --git a/app/Template/task_suppression/remove.php b/app/Template/task_suppression/remove.php
index 5d0f7720..4b0666d8 100644
--- a/app/Template/task_suppression/remove.php
+++ b/app/Template/task_suppression/remove.php
@@ -7,9 +7,9 @@
<?= t('Do you really want to remove this task: "%s"?', $this->text->e($task['title'])) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TaskSuppressionController', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => $redirect), true, 'btn btn-red popover-link') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TaskSuppressionController',
+ 'remove',
+ array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => $redirect)
+ ) ?>
</div>
diff --git a/app/Template/twofactor/disable.php b/app/Template/twofactor/disable.php
index bc419181..c44c450f 100644
--- a/app/Template/twofactor/disable.php
+++ b/app/Template/twofactor/disable.php
@@ -7,8 +7,9 @@
<?= t('Do you really want to disable the two factor authentication for this user: "%s"?', $user['name'] ?: $user['username']) ?>
</p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'TwoFactorController', 'disable', array('user_id' => $user['id'], 'disable' => 'yes'), true, 'btn btn-red') ?>
- <?= t('or') ?> <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'TwoFactorController',
+ 'disable',
+ array('user_id' => $user['id'], 'disable' => 'yes')
+ ) ?>
</div>
diff --git a/app/Template/twofactor/show.php b/app/Template/twofactor/show.php
index 0aeef427..a5bdeccb 100644
--- a/app/Template/twofactor/show.php
+++ b/app/Template/twofactor/show.php
@@ -3,7 +3,7 @@
</div>
<?php if (! empty($secret) || ! empty($qrcode_url) || ! empty($key_url)): ?>
-<div class="listing">
+<div class="panel">
<?php if (! empty($secret)): ?>
<p><?= t('Secret key: ') ?><strong><?= $this->text->e($secret) ?></strong></p>
<?php endif ?>
diff --git a/app/Template/user_creation/remote.php b/app/Template/user_creation/remote.php
deleted file mode 100644
index 41d0d3c7..00000000
--- a/app/Template/user_creation/remote.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<div class="page-header">
- <h2><?= t('New remote user') ?></h2>
-</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('UserCreationController', 'save') ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
- <?= $this->form->hidden('is_ldap_user', array('is_ldap_user' => 1)) ?>
-
- <div class="form-columns">
- <div class="form-column">
- <?= $this->form->label(t('Username'), 'username') ?>
- <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
-
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors) ?>
-
- <?= $this->form->label(t('Email'), 'email') ?>
- <?= $this->form->email('email', $values, $errors) ?>
-
- <?= $this->hook->render('template:user:create-remote:form', array('values' => $values, 'errors' => $errors)) ?>
- </div>
-
- <div class="form-column">
- <?= $this->form->label(t('Add project member'), 'project_id') ?>
- <?= $this->form->select('project_id', $projects, $values, $errors) ?>
-
- <?= $this->form->label(t('Timezone'), 'timezone') ?>
- <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
-
- <?= $this->form->label(t('Language'), 'language') ?>
- <?= $this->form->select('language', $languages, $values, $errors) ?>
-
- <?= $this->form->label(t('Role'), 'role') ?>
- <?= $this->form->select('role', $roles, $values, $errors) ?>
-
- <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
- <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
- </div>
- </div>
-
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
-</form>
-<div class="alert alert-info">
- <ul>
- <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li>
- <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
- </ul>
-</div>
diff --git a/app/Template/user_creation/show.php b/app/Template/user_creation/show.php
new file mode 100644
index 00000000..597dce55
--- /dev/null
+++ b/app/Template/user_creation/show.php
@@ -0,0 +1,67 @@
+<div class="page-header">
+ <h2><?= t('New User') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('UserCreationController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <div class="form-columns">
+ <div class="form-column">
+ <fieldset>
+ <legend><?= t('Profile') ?></legend>
+
+ <?= $this->form->label(t('Username'), 'username') ?>
+ <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors) ?>
+
+ <?= $this->form->label(t('Email'), 'email') ?>
+ <?= $this->form->email('email', $values, $errors) ?>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Authentication') ?></legend>
+ <?= $this->form->checkbox('is_ldap_user', t('Remote user'), 1, isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) ?>
+ <p class="form-help"><?= t('If checked, this user will use a third-party system for authentication.') ?></p>
+
+ <?= $this->form->label(t('Password'), 'password') ?>
+ <?= $this->form->password('password', $values, $errors) ?>
+ <p class="form-help"><?= t('The password is necessary only for local users.') ?></p>
+
+ <?= $this->form->label(t('Confirmation'), 'confirmation') ?>
+ <?= $this->form->password('confirmation', $values, $errors) ?>
+ </fieldset>
+ </div>
+
+ <div class="form-column">
+ <fieldset>
+ <legend><?= t('Security') ?></legend>
+
+ <?= $this->form->label(t('Role'), 'role') ?>
+ <?= $this->form->select('role', $roles, $values, $errors) ?>
+
+ <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Preferences') ?></legend>
+ <?= $this->form->label(t('Timezone'), 'timezone') ?>
+ <?= $this->form->select('timezone', $timezones, $values, $errors) ?>
+
+ <?= $this->form->label(t('Language'), 'language') ?>
+ <?= $this->form->select('language', $languages, $values, $errors) ?>
+
+ <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
+ </fieldset>
+
+ <fieldset>
+ <legend><?= t('Projects') ?></legend>
+
+ <?= $this->form->label(t('Add this person to this project'), 'project_id') ?>
+ <?= $this->form->select('project_id', $projects, $values, $errors) ?>
+ </fieldset>
+ </div>
+ </div>
+
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/user_credential/authentication.php b/app/Template/user_credential/authentication.php
index fbe2e915..98c0d758 100644
--- a/app/Template/user_credential/authentication.php
+++ b/app/Template/user_credential/authentication.php
@@ -4,13 +4,15 @@
<form method="post" action="<?= $this->url->href('UserCredentialController', 'saveAuthentication', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
- <?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('username', $values) ?>
+ <fieldset>
+ <?= $this->form->hidden('id', $values) ?>
+ <?= $this->form->hidden('username', $values) ?>
- <?= $this->hook->render('template:user:authentication:form', array('values' => $values, 'errors' => $errors, 'user' => $user)) ?>
+ <?= $this->hook->render('template:user:authentication:form', array('values' => $values, 'errors' => $errors, 'user' => $user)) ?>
- <?= $this->form->checkbox('is_ldap_user', t('Remote user'), 1, isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) ?>
- <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+ <?= $this->form->checkbox('is_ldap_user', t('Remote user'), 1, isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) ?>
+ <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+ </fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
diff --git a/app/Template/user_credential/password.php b/app/Template/user_credential/password.php
index 5a6e4403..bd7a47da 100644
--- a/app/Template/user_credential/password.php
+++ b/app/Template/user_credential/password.php
@@ -6,14 +6,16 @@
<?= $this->form->hidden('id', $values) ?>
<?= $this->form->csrf() ?>
- <?= $this->form->label(t('Current password for the user "%s"', $this->user->getFullname()), 'current_password') ?>
- <?= $this->form->password('current_password', $values, $errors) ?>
+ <fieldset>
+ <?= $this->form->label(t('Current password for the user "%s"', $this->user->getFullname()), 'current_password') ?>
+ <?= $this->form->password('current_password', $values, $errors) ?>
- <?= $this->form->label(t('New password for the user "%s"', $this->user->getFullname($user)), 'password') ?>
- <?= $this->form->password('password', $values, $errors) ?>
+ <?= $this->form->label(t('New password for the user "%s"', $this->user->getFullname($user)), 'password') ?>
+ <?= $this->form->password('password', $values, $errors) ?>
- <?= $this->form->label(t('Confirmation'), 'confirmation') ?>
- <?= $this->form->password('confirmation', $values, $errors) ?>
+ <?= $this->form->label(t('Confirmation'), 'confirmation') ?>
+ <?= $this->form->password('confirmation', $values, $errors) ?>
+ </fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
diff --git a/app/Template/user_import/show.php b/app/Template/user_import/show.php
index 663f107e..3b0e599c 100644
--- a/app/Template/user_import/show.php
+++ b/app/Template/user_import/show.php
@@ -2,8 +2,7 @@
<h2><?= t('Import users from CSV file') ?></h2>
<ul>
<li>
- <i class="fa fa-download fa-fw"></i>
- <?= $this->url->link(t('Download CSV template'), 'UserImportController', 'template') ?>
+ <?= $this->url->icon('download', t('Download CSV template'), 'UserImportController', 'template') ?>
</li>
</ul>
</div>
@@ -33,9 +32,5 @@
<p class="form-help"><?= t('Maximum size: ') ?><?= is_integer($max_size) ? $this->text->bytes($max_size) : $max_size ?></p>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Import') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->submitButtons(array('submitLabel' => t('Import'))) ?>
</form>
diff --git a/app/Template/user_invite/email.php b/app/Template/user_invite/email.php
new file mode 100644
index 00000000..674e4a84
--- /dev/null
+++ b/app/Template/user_invite/email.php
@@ -0,0 +1,12 @@
+<p>
+ <?= t('You have been invited to register on Kanboard.') ?>
+</p>
+
+<p>
+ <?= $this->url->absoluteLink(t('Click here to join your team'), 'UserInviteController', 'signup', array('token' => $token)) ?>
+</p>
+
+<?php if ($this->app->config('application_url')): ?>
+ <hr>
+ <a href="<?= $this->app->config('application_url') ?>">Kanboard</a>
+<?php endif ?>
diff --git a/app/Template/user_invite/show.php b/app/Template/user_invite/show.php
new file mode 100644
index 00000000..9d822248
--- /dev/null
+++ b/app/Template/user_invite/show.php
@@ -0,0 +1,15 @@
+<div class="page-header">
+ <h2><?= t('Invite people') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('UserInviteController', 'save') ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->label(t('Emails'), 'emails') ?>
+ <?= $this->form->textarea('emails', $values, $errors, array('required', 'autofocus')) ?>
+ <p class="form-help"><?= t('Enter one email address by line.') ?></p>
+
+ <?= $this->form->label(t('Add these people to this project'), 'project_id') ?>
+ <?= $this->form->select('project_id', $projects, $values, $errors) ?>
+
+ <?= $this->modal->submitButtons() ?>
+</form>
diff --git a/app/Template/user_creation/local.php b/app/Template/user_invite/signup.php
index 059a0114..51edbab7 100644
--- a/app/Template/user_creation/local.php
+++ b/app/Template/user_invite/signup.php
@@ -1,11 +1,13 @@
-<div class="page-header">
- <h2><?= t('New local user') ?></h2>
-</div>
-<form class="popover-form" method="post" action="<?= $this->url->href('UserCreationController', 'save') ?>" autocomplete="off">
- <?= $this->form->csrf() ?>
-
- <div class="form-columns">
- <div class="form-column">
+<div class="form-login">
+ <div class="page-header">
+ <h2><?= t('Sign-up') ?></h2>
+ </div>
+ <form method="post" action="<?= $this->url->href('UserInviteController', 'register', array('token' => $token)) ?>" autocomplete="off">
+ <?= $this->form->csrf() ?>
+
+ <fieldset>
+ <legend><?= t('Profile') ?></legend>
+
<?= $this->form->label(t('Username'), 'username') ?>
<?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?>
@@ -13,18 +15,20 @@
<?= $this->form->text('name', $values, $errors) ?>
<?= $this->form->label(t('Email'), 'email') ?>
- <?= $this->form->email('email', $values, $errors) ?>
+ <?= $this->form->email('email', $values, $errors, array('required')) ?>
+ </fieldset>
+ <fieldset>
+ <legend><?= t('Credentials') ?></legend>
<?= $this->form->label(t('Password'), 'password') ?>
<?= $this->form->password('password', $values, $errors, array('required')) ?>
<?= $this->form->label(t('Confirmation'), 'confirmation') ?>
<?= $this->form->password('confirmation', $values, $errors, array('required')) ?>
- </div>
+ </fieldset>
- <div class="form-column">
- <?= $this->form->label(t('Add project member'), 'project_id') ?>
- <?= $this->form->select('project_id', $projects, $values, $errors) ?>
+ <fieldset>
+ <legend><?= t('Preferences') ?></legend>
<?= $this->form->label(t('Timezone'), 'timezone') ?>
<?= $this->form->select('timezone', $timezones, $values, $errors) ?>
@@ -32,16 +36,11 @@
<?= $this->form->label(t('Language'), 'language') ?>
<?= $this->form->select('language', $languages, $values, $errors) ?>
- <?= $this->form->label(t('Role'), 'role') ?>
- <?= $this->form->select('role', $roles, $values, $errors) ?>
-
<?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
- </div>
- </div>
+ </fieldset>
- <div class="form-actions">
- <button type="submit" class="btn btn-blue"><?= t('Save') ?></button>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
-</form>
+ <div class="form-actions">
+ <button class="btn btn-blue"><?= t('Sign-up') ?></button>
+ </div>
+ </form>
+</div> \ No newline at end of file
diff --git a/app/Template/user_list/dropdown.php b/app/Template/user_list/dropdown.php
index 9e90c230..d18f20aa 100644
--- a/app/Template/user_list/dropdown.php
+++ b/app/Template/user_list/dropdown.php
@@ -2,25 +2,21 @@
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
<ul>
<li>
- <i class="fa fa-user fa-fw"></i>
- <?= $this->url->link(t('View profile'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
+ <?= $this->url->icon('user', t('View profile'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?>
</li>
<?php if ($user['is_active'] == 1 && $this->user->hasAccess('UserStatusController', 'disable') && ! $this->user->isCurrentUser($user['id'])): ?>
<li>
- <i class="fa fa-times fa-fw"></i>
- <?= $this->url->link(t('Disable'), 'UserStatusController', 'confirmDisable', array('user_id' => $user['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('times', t('Disable'), 'UserStatusController', 'confirmDisable', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
<?php if ($user['is_active'] == 0 && $this->user->hasAccess('UserStatusController', 'enable') && ! $this->user->isCurrentUser($user['id'])): ?>
<li>
- <i class="fa fa-check-square-o fa-fw"></i>
- <?= $this->url->link(t('Enable'), 'UserStatusController', 'confirmEnable', array('user_id' => $user['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('check-square-o', t('Enable'), 'UserStatusController', 'confirmEnable', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
<?php if ($this->user->hasAccess('UserStatusController', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?>
<li>
- <i class="fa fa-trash-o fa-fw"></i>
- <?= $this->url->link(t('Remove'), 'UserStatusController', 'confirmRemove', array('user_id' => $user['id']), false, 'popover') ?>
+ <?= $this->modal->confirm('trash-o', t('Remove'), 'UserStatusController', 'confirmRemove', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
</ul>
diff --git a/app/Template/user_list/show.php b/app/Template/user_list/show.php
index 5e285c89..e83895ea 100644
--- a/app/Template/user_list/show.php
+++ b/app/Template/user_list/show.php
@@ -2,10 +2,18 @@
<div class="page-header">
<?php if ($this->user->hasAccess('UserCreationController', 'show')): ?>
<ul>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'UserCreationController', 'show', array(), false, 'popover') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'UserCreationController', 'show', array('remote' => 1), false, 'popover') ?></li>
- <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'UserImportController', 'show', array(), false, 'popover') ?></li>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
+ <li>
+ <?= $this->modal->medium('plus', t('New user'), 'UserCreationController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->modal->medium('paper-plane', t('Invite people'), 'UserInviteController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->modal->medium('upload', t('Import'), 'UserImportController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->url->icon('users', t('View all groups'), 'GroupListController', 'index') ?>
+ </li>
</ul>
<?php endif ?>
</div>
diff --git a/app/Template/user_modification/show.php b/app/Template/user_modification/show.php
index 506c9161..d3f3e0cc 100644
--- a/app/Template/user_modification/show.php
+++ b/app/Template/user_modification/show.php
@@ -2,29 +2,36 @@
<h2><?= t('Edit user') ?></h2>
</div>
<form method="post" action="<?= $this->url->href('UserModificationController', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
-
<?= $this->form->csrf() ?>
-
<?= $this->form->hidden('id', $values) ?>
- <?= $this->form->label(t('Username'), 'username') ?>
- <?= $this->form->text('username', $values, $errors, array('required', isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1 ? 'readonly' : '', 'maxlength="50"')) ?>
+ <fieldset>
+ <legend><?= t('Profile') ?></legend>
+ <?= $this->form->label(t('Username'), 'username') ?>
+ <?= $this->form->text('username', $values, $errors, array('required', isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1 ? 'readonly' : '', 'maxlength="50"')) ?>
- <?= $this->form->label(t('Name'), 'name') ?>
- <?= $this->form->text('name', $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_name') ? '' : 'readonly')) ?>
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_name') ? '' : 'readonly')) ?>
- <?= $this->form->label(t('Email'), 'email') ?>
- <?= $this->form->email('email', $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_email') ? '' : 'readonly')) ?>
+ <?= $this->form->label(t('Email'), 'email') ?>
+ <?= $this->form->email('email', $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_email') ? '' : 'readonly')) ?>
+ </fieldset>
- <?= $this->form->label(t('Timezone'), 'timezone') ?>
- <?= $this->form->select('timezone', $timezones, $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_timezone') ? '' : 'disabled')) ?>
+ <fieldset>
+ <legend><?= t('Preferences') ?></legend>
+ <?= $this->form->label(t('Timezone'), 'timezone') ?>
+ <?= $this->form->select('timezone', $timezones, $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_timezone') ? '' : 'disabled')) ?>
- <?= $this->form->label(t('Language'), 'language') ?>
- <?= $this->form->select('language', $languages, $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_language') ? '' : 'disabled')) ?>
+ <?= $this->form->label(t('Language'), 'language') ?>
+ <?= $this->form->select('language', $languages, $values, $errors, array($this->user->hasAccess('UserModificationController', 'show/edit_language') ? '' : 'disabled')) ?>
+ </fieldset>
<?php if ($this->user->isAdmin()): ?>
- <?= $this->form->label(t('Role'), 'role') ?>
+ <fieldset>
+ <legend><?= t('Security') ?></legend>
+ <?= $this->form->label(t('Application role'), 'role') ?>
<?= $this->form->select('role', $roles, $values, $errors) ?>
+ </fieldset>
<?php endif ?>
<div class="form-actions">
diff --git a/app/Template/user_status/disable.php b/app/Template/user_status/disable.php
index d30b0c20..1309b080 100644
--- a/app/Template/user_status/disable.php
+++ b/app/Template/user_status/disable.php
@@ -5,9 +5,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to disable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatusController', 'disable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'UserStatusController',
+ 'disable',
+ array('user_id' => $user['id'])
+ ) ?>
</div>
diff --git a/app/Template/user_status/enable.php b/app/Template/user_status/enable.php
index 29d25eee..2413739e 100644
--- a/app/Template/user_status/enable.php
+++ b/app/Template/user_status/enable.php
@@ -5,9 +5,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to enable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatusController', 'enable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'UserStatusController',
+ 'enable',
+ array('user_id' => $user['id'])
+ ) ?>
</div>
diff --git a/app/Template/user_status/remove.php b/app/Template/user_status/remove.php
index 2b8f2df5..6cd3f63a 100644
--- a/app/Template/user_status/remove.php
+++ b/app/Template/user_status/remove.php
@@ -5,9 +5,9 @@
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
- <div class="form-actions">
- <?= $this->url->link(t('Yes'), 'UserStatusController', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
- <?= t('or') ?>
- <?= $this->url->link(t('cancel'), 'UserListController', 'show', array(), false, 'close-popover') ?>
- </div>
+ <?= $this->modal->confirmButtons(
+ 'UserStatusController',
+ 'remove',
+ array('user_id' => $user['id'])
+ ) ?>
</div>
diff --git a/app/Template/user_view/layout.php b/app/Template/user_view/layout.php
index c3604b99..8f24adcc 100644
--- a/app/Template/user_view/layout.php
+++ b/app/Template/user_view/layout.php
@@ -2,11 +2,18 @@
<div class="page-header">
<?php if ($this->user->hasAccess('UserCreationController', 'show')): ?>
<ul>
- <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'UserListController', 'show') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'UserCreationController', 'show', array(), false, 'popover') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'UserCreationController', 'show', array('remote' => 1), false, 'popover') ?></li>
- <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'UserImportController', 'show', array(), false, 'popover') ?></li>
- <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li>
+ <li>
+ <?= $this->url->icon('user', t('All users'), 'UserListController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->modal->medium('plus', t('New user'), 'UserCreationController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->modal->medium('upload', t('Import'), 'UserImportController', 'show') ?>
+ </li>
+ <li>
+ <?= $this->url->icon('users', t('View all groups'), 'GroupListController', 'index') ?>
+ </li>
</ul>
<?php endif ?>
</div>
diff --git a/app/Template/user_view/profile.php b/app/Template/user_view/profile.php
index 9c9d3282..486ca428 100644
--- a/app/Template/user_view/profile.php
+++ b/app/Template/user_view/profile.php
@@ -1,9 +1,11 @@
<section id="main">
<br>
<?= $this->avatar->render($user['id'], $user['username'], $user['name'], $user['email'], $user['avatar_path']) ?>
- <ul class="listing">
- <li><?= t('Username:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li>
- <li><?= t('Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li>
- <li><?= t('Email:') ?> <strong><?= $this->text->e($user['email']) ?: t('None') ?></strong></li>
- </ul>
-</section> \ No newline at end of file
+ <div class="panel">
+ <ul>
+ <li><?= t('Login:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li>
+ <li><?= t('Full Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li>
+ <li><?= t('Email:') ?> <strong><?= $this->text->e($user['email']) ?: t('None') ?></strong></li>
+ </ul>
+ </div>
+</section>
diff --git a/app/Template/user_view/share.php b/app/Template/user_view/share.php
index 570b766e..318d98ea 100644
--- a/app/Template/user_view/share.php
+++ b/app/Template/user_view/share.php
@@ -3,10 +3,10 @@
</div>
<?php if (! empty($user['token'])): ?>
- <div class="listing">
+ <div class="panel">
<ul class="no-bullet">
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
</ul>
</div>
<?= $this->url->link(t('Disable public access'), 'UserViewController', 'share', array('user_id' => $user['id'], 'switch' => 'disable'), true, 'btn btn-red') ?>
diff --git a/app/Template/user_view/show.php b/app/Template/user_view/show.php
index 2f5a73af..e57fd4cd 100644
--- a/app/Template/user_view/show.php
+++ b/app/Template/user_view/show.php
@@ -1,9 +1,9 @@
<div class="page-header">
<h2><?= t('Summary') ?></h2>
</div>
-<ul class="listing">
- <li><?= t('Username:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li>
- <li><?= t('Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li>
+<ul class="panel">
+ <li><?= t('Login:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li>
+ <li><?= t('Full Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li>
<li><?= t('Email:') ?> <strong><?= $this->text->e($user['email']) ?: t('None') ?></strong></li>
<li><?= t('Status:') ?> <strong><?= $user['is_active'] ? t('Active') : t('Inactive') ?></strong></li>
</ul>
@@ -11,7 +11,7 @@
<div class="page-header">
<h2><?= t('Security') ?></h2>
</div>
-<ul class="listing">
+<ul class="panel">
<li><?= t('Role:') ?> <strong><?= $this->user->getRoleName($user['role']) ?></strong></li>
<li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li>
<li><?= $user['twofactor_activated'] == 1 ? t('Two factor authentication enabled') : t('Two factor authentication disabled') ?></li>
@@ -29,7 +29,7 @@
<div class="page-header">
<h2><?= t('Preferences') ?></h2>
</div>
-<ul class="listing">
+<ul class="panel">
<li><?= t('Timezone:') ?> <strong><?= $this->text->in($user['timezone'], $timezones) ?></strong></li>
<li><?= t('Language:') ?> <strong><?= $this->text->in($user['language'], $languages) ?></strong></li>
<li><?= t('Notifications:') ?> <strong><?= $user['notifications_enabled'] == 1 ? t('Enabled') : t('Disabled') ?></strong></li>
@@ -40,10 +40,10 @@
<h2><?= t('Public access') ?></h2>
</div>
- <div class="listing">
+ <div class="panel">
<ul class="no-bullet">
- <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
- <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('rss-square', t('RSS feed'), 'FeedController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
+ <li><strong><?= $this->url->icon('calendar', t('iCal feed'), 'ICalendarController', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li>
</ul>
</div>
<?php endif ?>
diff --git a/app/Validator/ProjectValidator.php b/app/Validator/ProjectValidator.php
index 8c6117a4..5b10026c 100644
--- a/app/Validator/ProjectValidator.php
+++ b/app/Validator/ProjectValidator.php
@@ -28,7 +28,6 @@ class ProjectValidator extends BaseValidator
new Validators\Integer('priority_start', t('This value must be an integer')),
new Validators\Integer('priority_end', t('This value must be an integer')),
new Validators\Integer('is_active', t('This value must be an integer')),
- new Validators\NotEmpty('name', t('This field cannot be empty')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
@@ -47,15 +46,15 @@ class ProjectValidator extends BaseValidator
*/
public function validateCreation(array $values)
{
- $rules = array(
- new Validators\Required('name', t('The project name is required')),
- );
-
if (! empty($values['identifier'])) {
$values['identifier'] = strtoupper($values['identifier']);
}
- $v = new Validator($values, array_merge($this->commonValidationRules(), $rules));
+ $rules = array(
+ new Validators\Required('name', t('The project name is required')),
+ );
+
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
return array(
$v->execute(),
@@ -77,6 +76,7 @@ class ProjectValidator extends BaseValidator
}
$rules = array(
+ new Validators\NotEmpty('name', t('This field cannot be empty')),
new Validators\Required('id', t('This value is required')),
);
diff --git a/app/Validator/TaskValidator.php b/app/Validator/TaskValidator.php
index e3b0eded..e824dc05 100644
--- a/app/Validator/TaskValidator.php
+++ b/app/Validator/TaskValidator.php
@@ -42,7 +42,7 @@ class TaskValidator extends BaseValidator
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
new Validators\MaxLength('reference', t('The maximum length is %d characters', 50), 50),
new Validators\Date('date_due', t('Invalid date'), $this->dateParser->getParserFormats()),
- new Validators\Date('date_started', t('Invalid date'), $this->dateParser->getParserFormats()),
+ new Validators\Date('date_started', t('Invalid date'), array($this->dateParser->getUserDateTimeFormat())),
new Validators\Numeric('time_spent', t('This value must be numeric')),
new Validators\Numeric('time_estimated', t('This value must be numeric')),
);
diff --git a/app/Validator/UserValidator.php b/app/Validator/UserValidator.php
index 9911de50..fe402c47 100644
--- a/app/Validator/UserValidator.php
+++ b/app/Validator/UserValidator.php
@@ -25,7 +25,7 @@ class UserValidator extends BaseValidator
return array(
new Validators\MaxLength('role', t('The maximum length is %d characters', 25), 25),
new Validators\MaxLength('username', t('The maximum length is %d characters', 50), 50),
- new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), UserModel::TABLE, 'id'),
+ new Validators\Unique('username', t('This username is already taken'), $this->db->getConnection(), UserModel::TABLE, 'id'),
new Validators\Email('email', t('Email address invalid')),
new Validators\Integer('is_ldap_user', t('This value must be an integer')),
);
diff --git a/app/common.php b/app/common.php
index 6ebb839e..fd55c0bb 100644
--- a/app/common.php
+++ b/app/common.php
@@ -48,6 +48,7 @@ $container->register(new Kanboard\ServiceProvider\ExternalLinkProvider());
$container->register(new Kanboard\ServiceProvider\ExternalTaskProvider());
$container->register(new Kanboard\ServiceProvider\AvatarProvider());
$container->register(new Kanboard\ServiceProvider\FilterProvider());
+$container->register(new Kanboard\ServiceProvider\FormatterProvider());
$container->register(new Kanboard\ServiceProvider\JobProvider());
$container->register(new Kanboard\ServiceProvider\QueueProvider());
$container->register(new Kanboard\ServiceProvider\ApiProvider());
diff --git a/app/functions.php b/app/functions.php
index 9dd054fb..7cd59c41 100644
--- a/app/functions.php
+++ b/app/functions.php
@@ -146,6 +146,17 @@ function get_upload_max_size()
}
/**
+ * Get file extension
+ *
+ * @param $filename
+ * @return string
+ */
+function get_file_extension($filename)
+{
+ return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+}
+
+/**
* Translate a string
*
* @return string
diff --git a/assets/css/app.min.css b/assets/css/app.min.css
index a79615aa..412e4114 100644
--- a/assets/css/app.min.css
+++ b/assets/css/app.min.css
@@ -1 +1 @@
-h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}.chosen-select{min-height:27px}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}form{margin-bottom:20px}label{cursor:pointer;display:block;margin-top:10px}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;margin-top:10px;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{padding:3px;border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif;font-size:1em}textarea::-webkit-input-placeholder{color:#dedede}textarea::-moz-placeholder{color:#dedede}textarea:-ms-input-placeholder{color:#dedede}select{font-size:1.0em;max-width:95%}select:focus{outline:0}select[multiple]{width:300px}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}.form-required{color:red;padding-left:5px;font-weight:bold}@media (max-width: 480px){.form-required{display:none}}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.form-columns .form-column{margin-right:25px;flex-grow:1}.form-login{max-width:350px;margin:8% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-field:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child{border-radius:0 5px 5px 0}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-item:last-child{border-radius:0 5px 5px 0}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.icon-success{color:#468847}.icon-error{color:#b94a48}.icon-fade-out{opacity:1;animation:icon-fadeout 5s linear forwards}@keyframes icon-fadeout{0%{opacity:1}100%{opacity:0}}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999;opacity:1;animation:fadeout 5s linear forwards}@keyframes fadeout{0%{opacity:1}100%{opacity:0}}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}h2 .dropdown ul{display:none}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#select-dropdown-menu{position:absolute;display:block;z-index:1000;min-width:160px;padding:5px 0;background:#fff;list-style:none;border:1px solid #ccc;border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,0.175);overflow:scroll}.select-dropdown-menu-item{white-space:nowrap;overflow:hidden;padding:3px 10px;color:#555;cursor:pointer;border-bottom:1px solid #f8f8f8;line-height:1.5em;font-weight:400}.select-dropdown-menu-item.active{color:#fff;background:#428bca}.select-dropdown-menu-item:last-child{border:none}.select-dropdown-input-container{position:relative;border:1px solid #ccc;border-radius:5px}.select-dropdown-input-container input.select-dropdown-input{margin:0 0 0 5px;border:none}.select-dropdown-input-container input.select-dropdown-input:focus{border:none;box-shadow:none}.select-dropdown-input-container .select-dropdown-chevron{color:#555;position:absolute;top:4px;right:5px;cursor:pointer}#suggest-menu{position:absolute;display:block;z-index:1000;min-width:160px;padding:5px 0;background:#fff;list-style:none;border:1px solid #ccc;border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,0.175)}.suggest-menu-item{white-space:nowrap;padding:3px 10px;color:#333;font-weight:bold;cursor:pointer}.suggest-menu-item.active{color:#fff;background:#428bca}.suggest-menu-item.active small{color:#fff}.suggest-menu-item small{color:#999;font-weight:normal}#main .confirm{max-width:700px}#popover-container{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);overflow:auto;z-index:100}#popover-content{position:fixed;width:950px;max-width:95%;max-height:calc(100% - 50px);top:5%;left:50%;transform:translateX(-50%);padding:0 15px 15px;background:#fff;overflow:auto}#popover-content-header{text-align:right}#popover-close-button{color:#333}#popover-close-button:hover{color:#b94a48}.popover-form{margin-bottom:0}.pagination{text-align:center}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:30%;order:2}}header .board-selector-container{width:25%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:70%;order:1;margin-bottom:5px}}header .title-container{width:65%}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li.file-error{font-weight:bold;color:#b94a48}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{cursor:pointer;border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.filter-box{max-width:800px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.js-project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-bottom:8px}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{margin-top:4px;width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{margin-top:4px;width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{margin-top:0;width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}@media (max-width: 480px){.views{margin-top:5px}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon a{text-decoration:none;color:#36c;font-size:1.6em;line-height:70%}.board-add-icon a:focus,.board-add-icon a:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0;color:#36c}span.task-board-date-overdue{opacity:1.0;color:#b94a48}.task-tags li{display:inline-block;margin:3px 3px 0 0;padding:1px 3px 1px 3px;color:#333;border:1px solid #333;border-radius:4px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}#external-task-view{padding:10px;margin-top:10px;margin-bottom:10px;border:1px dotted #ccc}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.text-editor a{font-size:1em;color:#999;text-decoration:none;margin-right:10px}.text-editor a:hover{color:#36c}.text-editor .text-editor-preview-area{border:1px solid #dedede;width:400px;height:200px;overflow:auto;padding:2px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.listing{border-radius:4px;padding:8px 35px 8px 14px;margin-bottom:20px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.listing li{list-style-type:square;margin-left:20px;margin-bottom:3px}.listing ul{margin-top:15px;margin-bottom:15px}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}.image-slideshow-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.95);overflow:auto;z-index:100}.image-slideshow-overlay img{display:block;margin:auto}.image-slideshow-overlay figcaption{color:#fff;opacity:0.7;position:absolute;bottom:5px;right:15px}.slideshow-icon{color:#fff;position:absolute;font-size:2.5em;opacity:0.6}.slideshow-icon:hover{opacity:0.9;cursor:pointer}.slideshow-previous-icon{left:10px;top:45%}.slideshow-next-icon{right:10px;top:45%}.slideshow-close-icon{right:10px;top:10px;font-size:1.4em}.slideshow-download-icon{left:10px;bottom:10px;font-size:1.3em}
+h1,li,ul,ol,table,tr,td,th,p,blockquote,body{margin:0;padding:0;font-size:100%}body{margin-left:10px;margin-right:10px;padding-bottom:10px;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;text-rendering:optimizeLegibility}small{font-size:0.8em}hr{border:0;height:0;border-top:1px solid rgba(0,0,0,0.1);border-bottom:1px solid rgba(255,255,255,0.3)}.margin-top{margin-top:20px}.margin-bottom{margin-bottom:20px}.pull-right{text-align:right}ul.no-bullet li{list-style-type:none;margin-left:0}#app-loading-icon{position:fixed;right:3px;bottom:3px}.assign-me{vertical-align:bottom}a{color:#36c;border:none}a:focus{outline:0;color:#DF5353;text-decoration:none}a:hover{color:#333;text-decoration:none}a .fa{padding-right:3px;text-decoration:none;color:#333}h1,h2,h3{font-weight:normal;color:#333}h1{font-size:1.5em}h2{font-size:1.4em;margin-bottom:10px}h3{margin-top:10px;font-size:1.2em}table{width:100%;border-collapse:collapse;border-spacing:0;margin-bottom:20px}table.table-fixed{table-layout:fixed;white-space:nowrap}table.table-fixed th{overflow:hidden}table.table-fixed td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}table.table-small{font-size:0.8em}table.table-striped tr:nth-child(odd){background:#fefefe}@media (max-width: 768px){table.table-scrolling{overflow-x:auto;display:inline-block;vertical-align:top;max-width:100%;white-space:nowrap}}table th{text-align:left;padding:0.5em 3px;border:1px solid #eee;background:#fbfbfb}table th a{text-decoration:none;color:#333}table th a:focus,table th a:hover{text-decoration:underline}table td{border:1px solid #eee;padding:0.5em 3px;vertical-align:top}table td li{margin-left:20px}.column-1{width:1%}.column-2{width:2%}.column-3{width:3%}.column-4{width:4%}.column-5{width:5%}.column-6{width:6%}.column-7{width:7%}.column-8{width:8%}.column-9{width:9%}.column-10{width:10%}.column-11{width:11%}.column-12{width:12%}.column-13{width:13%}.column-14{width:14%}.column-15{width:15%}.column-16{width:16%}.column-17{width:17%}.column-18{width:18%}.column-19{width:19%}.column-20{width:20%}.column-21{width:21%}.column-22{width:22%}.column-23{width:23%}.column-24{width:24%}.column-25{width:25%}.column-26{width:26%}.column-27{width:27%}.column-28{width:28%}.column-29{width:29%}.column-30{width:30%}.column-31{width:31%}.column-32{width:32%}.column-33{width:33%}.column-34{width:34%}.column-35{width:35%}.column-36{width:36%}.column-37{width:37%}.column-38{width:38%}.column-39{width:39%}.column-40{width:40%}.column-41{width:41%}.column-42{width:42%}.column-43{width:43%}.column-44{width:44%}.column-45{width:45%}.column-46{width:46%}.column-47{width:47%}.column-48{width:48%}.column-49{width:49%}.column-50{width:50%}.column-51{width:51%}.column-52{width:52%}.column-53{width:53%}.column-54{width:54%}.column-55{width:55%}.column-56{width:56%}.column-57{width:57%}.column-58{width:58%}.column-59{width:59%}.column-60{width:60%}.column-61{width:61%}.column-62{width:62%}.column-63{width:63%}.column-64{width:64%}.column-65{width:65%}.column-66{width:66%}.column-67{width:67%}.column-68{width:68%}.column-69{width:69%}.column-70{width:70%}.column-71{width:71%}.column-72{width:72%}.column-73{width:73%}.column-74{width:74%}.column-75{width:75%}.column-76{width:76%}.column-77{width:77%}.column-78{width:78%}.column-79{width:79%}.column-80{width:80%}.column-81{width:81%}.column-82{width:82%}.column-83{width:83%}.column-84{width:84%}.column-85{width:85%}.column-86{width:86%}.column-87{width:87%}.column-88{width:88%}.column-89{width:89%}.column-90{width:90%}.column-91{width:91%}.column-92{width:92%}.column-93{width:93%}.column-94{width:94%}.column-95{width:95%}.column-96{width:96%}.column-97{width:97%}.column-98{width:98%}.column-99{width:99%}.column-100{width:100%}.draggable-row-handle{cursor:move;color:#dedede}.draggable-row-handle:hover{color:#333}tr.draggable-item-selected{background:#fff;border:2px solid #666;box-shadow:4px 2px 10px -4px rgba(0,0,0,0.55)}tr.draggable-item-selected td{border-top:none;border-bottom:none}tr.draggable-item-selected td:first-child{border-left:none}tr.draggable-item-selected td:last-child{border-right:none}.table-stripped tr.draggable-item-hover,.table-stripped tr.draggable-item-hover{background:#FEFFF2}fieldset{border:1px solid #ccc;margin-top:20px}legend{font-weight:500;font-size:1.2em}label{cursor:pointer;display:block;margin-top:10px;font-weight:400}input[type="number"],input[type="date"],input[type="email"],input[type="password"],input[type="text"]:not(.input-addon-field){color:#999;border:1px solid #ccc;width:300px;max-width:95%;font-size:1em;height:25px;padding-bottom:0;font-family:sans-serif;-webkit-appearance:none;-moz-appearance:none}input[type="number"]::-webkit-input-placeholder,input[type="date"]::-webkit-input-placeholder,input[type="email"]::-webkit-input-placeholder,input[type="password"]::-webkit-input-placeholder,input[type="text"]:not(.input-addon-field)::-webkit-input-placeholder{color:#dedede}input[type="number"]::-moz-placeholder,input[type="date"]::-moz-placeholder,input[type="email"]::-moz-placeholder,input[type="password"]::-moz-placeholder,input[type="text"]:not(.input-addon-field)::-moz-placeholder{color:#dedede}input[type="number"]:-ms-input-placeholder,input[type="date"]:-ms-input-placeholder,input[type="email"]:-ms-input-placeholder,input[type="password"]:-ms-input-placeholder,input[type="text"]:not(.input-addon-field):-ms-input-placeholder{color:#dedede}input[type="number"]:focus,input[type="date"]:focus,input[type="email"]:focus,input[type="password"]:focus,input[type="text"]:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}input[type="number"]{width:70px}input[type="text"]:not(.input-addon-field).form-numeric{width:70px}input[type="text"]:not(.input-addon-field).form-datetime,input[type="text"]:not(.input-addon-field).form-date{width:150px}input[type="text"]:not(.input-addon-field).form-input-large{width:400px}input[type="text"]:not(.input-addon-field).form-input-small{width:150px}textarea:focus{color:#000;border-color:rgba(82,168,236,0.8);outline:0;box-shadow:0 0 8px rgba(82,168,236,0.6)}textarea{padding:3px;border:1px solid #ccc;width:400px;max-width:99%;height:200px;font-family:sans-serif;font-size:1em}textarea::-webkit-input-placeholder{color:#dedede}textarea::-moz-placeholder{color:#dedede}textarea:-ms-input-placeholder{color:#dedede}select{font-size:1.0em;max-width:95%}select:focus{outline:0}select[multiple]{width:300px}.tag-autocomplete{width:400px}span.select2-container{margin-top:2px}.form-actions{padding-top:20px;clear:both}.form-required{color:red;padding-left:5px;font-weight:bold}@media (max-width: 480px){.form-required{display:none}}input.form-error,textarea.form-error{border:2px solid #b94a48}input.form-error:focus,textarea.form-error:focus{box-shadow:none;border:2px solid #b94a48}.form-errors{color:#b94a48;list-style-type:none}ul.form-errors li{margin-left:0}.form-help{font-size:0.8em;color:brown;margin-bottom:15px}.form-inline{padding:0;margin:0;border:none}.form-inline label{display:inline;padding-right:3px}.form-inline input,.form-inline select{margin:0 15px 0 0}.form-inline .form-required{display:none}.form-inline .form-actions{display:inline-block}.form-inline .js-submit-buttons-rendered{display:inline-block}.form-inline-group{display:inline}.form-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.form-columns .form-column{margin-right:25px;flex-grow:1}.form-columns fieldset{margin-top:0}.form-login{max-width:350px;margin:5% auto 0}.form-login li{margin-left:25px;line-height:25px}.form-login h2{margin-bottom:30px;font-weight:bold}.reset-password{margin-top:20px;margin-bottom:20px}.reset-password a{color:#999}.input-addon{display:flex}.input-addon-field{flex:1;font-size:1em;color:#999;margin:0;-webkit-appearance:none;-moz-appearance:none}.input-addon-field:first-child{border-radius:5px 0 0 5px}.input-addon-field:last-child{border-radius:0 5px 5px 0}.input-addon-item{background-color:rgba(147,128,108,0.1);color:#666;font:inherit;font-weight:normal}.input-addon-item:first-child{border-radius:5px 0 0 5px}.input-addon-item:last-child{border-radius:0 5px 5px 0}@media (max-width: 480px){.input-addon-item .dropdown .fa-caret-down{display:none}}.input-addon-field,.input-addon-item{border:1px solid rgba(147,128,108,0.25);padding:4px 0.75em}.input-addon-field:not(:first-child),.input-addon-item:not(:first-child){border-left:0}.icon-success{color:#468847}.icon-error{color:#b94a48}.icon-fade-out{opacity:1;animation:icon-fadeout 5s linear forwards}@keyframes icon-fadeout{0%{opacity:1}100%{opacity:0}}.alert{padding:8px 35px 8px 14px;margin-top:5px;margin-bottom:5px;color:#c09853;background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-normal{color:#333;background-color:#f0f0f0;border-color:#ddd}.alert ul{margin-top:10px;margin-bottom:10px}.alert li{margin-left:25px}.alert-fade-out{text-align:center;position:fixed;bottom:0;left:20%;width:60%;padding-top:5px;padding-bottom:5px;margin-bottom:0;border-width:1px 0 0;border-radius:4px 4px 0 0;z-index:9999;opacity:1;animation:fadeout 5s linear forwards}@keyframes fadeout{0%{opacity:1}100%{opacity:0}}a.btn{text-decoration:none}.btn{-webkit-appearance:none;-moz-appearance:none;font-size:1.2em;font-weight:normal;cursor:pointer;display:inline-block;border-radius:2px;padding:3px 10px;margin:0;border:1px solid #ddd;background:#f5f5f5;color:#333}.btn:hover,.btn:focus{border-color:#bbb;background:#fafafa;color:#000}.btn-red{border-color:#b0281a;background:#d14836;color:#fff}.btn-red:hover,.btn-red:focus{border-color:#b0281a;background:#c53727;color:#fff}.btn-blue{border-color:#3079ed;background:#4d90fe;color:#fff}.btn-blue:hover,.btn-blue:focus{border-color:#3079ed;background:#357ae8;color:#fff}.btn:disabled{color:#ccc;border-color:#ccc;background:#f7f7f7}.buttons-header{font-size:0.8em;margin-top:5px;margin-bottom:15px}.tooltip-arrow:after{background:#fff;border:1px solid #aaaaaa;box-shadow:0 0 5px #aaa}div.ui-tooltip{min-width:200px;max-width:600px}.tooltip-arrow{width:20px;height:10px;overflow:hidden;position:absolute}.tooltip-arrow.top{top:-10px}.tooltip-arrow.bottom{bottom:-10px}.tooltip-arrow.align-left{left:10px}.tooltip-arrow.align-right{right:10px}.tooltip-arrow:after{content:"";position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.tooltip-arrow.bottom:after{top:-10px}.tooltip-arrow.top:after{bottom:-10px}.tooltip-arrow.align-left:after{left:0}.tooltip-arrow.align-right:after{right:0}.tooltip-large{width:600px}.ui-tooltip-content .markdown p{margin-bottom:0}.ui-tooltip li{list-style-type:none}.tooltip .fa-info-circle{color:#999}h2 .dropdown ul{display:none}.dropdown{display:inline;position:relative}.dropdown ul{display:none}ul.dropdown-submenu-open{display:block;position:absolute;z-index:1000;min-width:285px;list-style:none;margin:3px 0 0 1px;padding:6px 0;background-color:#fff;border:1px solid #b2b2b2;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,0.15)}.dropdown-submenu-open li{display:block;margin:0;padding:8px 10px;font-size:0.9em;border-bottom:1px solid #f8f8f8;cursor:pointer}.dropdown-submenu-open li.no-hover{cursor:default}.dropdown-submenu-open li:last-child{border:none}.dropdown-submenu-open li:not(.no-hover):hover{background:#4078C0;color:#fff}.dropdown-submenu-open li:hover a{color:#fff}.dropdown-submenu-open a{text-decoration:none;color:#333}.dropdown-submenu-open a:focus{text-decoration:underline}.dropdown-menu-link-text,.dropdown-menu-link-icon{color:#333;text-decoration:none}.dropdown-menu-link-text:hover{text-decoration:underline}.accordion-title{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NEQ5RDgxQzc2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NEQ5RDgxQzg2RjQ5MTFFMjhEMUNENzFGRUMwRjhBRTciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RDlEODFDNTZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RDlEODFDNjZGNDkxMUUyOEQxQ0Q3MUZFQzBGOEFFNyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvXFWFAAAAAYSURBVHjaYvj//z8D0/Pnz/8zgFgAAQYAS5UJscReGMIAAAAASUVORK5CYII=) repeat-x scroll 0 10px}.accordion-title h3{display:inline;padding-right:5px;background:#fff}.accordion-content{margin-top:15px;margin-bottom:25px}.accordion-toggle{color:#333;text-decoration:none}.accordion-toggle:focus{color:#333}.accordion-toggle:hover{color:#999}.accordion-toggle:before{content:"\f0d7"}.accordion-collapsed{margin-bottom:25px}.accordion-collapsed .accordion-toggle:before{content:"\f0da"}.accordion-collapsed .accordion-content{display:none}#select-dropdown-menu{position:absolute;display:block;z-index:1000;min-width:160px;padding:5px 0;background:#fff;list-style:none;border:1px solid #ccc;border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,0.175);overflow:scroll}.select-dropdown-menu-item{white-space:nowrap;overflow:hidden;padding:3px 10px;color:#555;cursor:pointer;border-bottom:1px solid #f8f8f8;line-height:1.5em;font-weight:400}.select-dropdown-menu-item.active{color:#fff;background:#428bca}.select-dropdown-menu-item:last-child{border:none}.select-dropdown-input-container{position:relative;border:1px solid #ccc;border-radius:5px}.select-dropdown-input-container input.select-dropdown-input{margin:0 0 0 5px;border:none;height:23px}.select-dropdown-input-container input.select-dropdown-input:focus{border:none;box-shadow:none}.select-dropdown-input-container .select-dropdown-chevron{color:#555;position:absolute;top:4px;right:5px;cursor:pointer}.select-dropdown-input-container .select-loading-icon{color:#555;position:absolute;top:4px;right:5px}#suggest-menu{position:absolute;display:block;z-index:1000;min-width:160px;padding:5px 0;background:#fff;list-style:none;border:1px solid #ccc;border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,0.175)}.suggest-menu-item{white-space:nowrap;padding:3px 10px;color:#333;font-weight:bold;cursor:pointer}.suggest-menu-item.active{color:#fff;background:#428bca}.suggest-menu-item.active small{color:#fff}.suggest-menu-item small{color:#999;font-weight:normal}#modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);overflow:auto;z-index:100}#modal-box{position:fixed;max-height:calc(100% - 30px);top:2%;left:50%;transform:translateX(-50%);background:#fff;overflow:auto;border-radius:5px}#modal-content{padding:0 5px 5px}#modal-header{text-align:right;padding-right:5px}#modal-close-button{color:#333}#modal-close-button:hover{color:#b94a48}.pagination{text-align:center}.pagination-showing{margin-right:5px;padding-right:5px;border-right:1px solid #999}.pagination-next{margin-left:5px}.pagination-previous{margin-right:5px}header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-top:5px;margin-bottom:5px;border-bottom:1px solid #dedede}header>*{box-sizing:border-box}header>*{width:1%}header .menus-container{width:10%}@media (min-width: 768px) and (max-width: 1150px){header .menus-container{width:15%}}@media (max-width: 768px){header .menus-container{width:30%;order:2}}header .board-selector-container{width:25%}@media (min-width: 768px) and (max-width: 1150px){header .board-selector-container{width:20%}}@media (max-width: 768px){header .board-selector-container{width:70%;order:1;margin-bottom:5px}}header .title-container{width:65%}@media (max-width: 768px){header .title-container{width:100%;order:3}}header h1{font-size:1.5em}header h1 .tooltip{opacity:0.3;font-size:0.7em}.web-notification-icon{color:#36c}.web-notification-icon:focus,.web-notification-icon:hover{color:#000}.logo a{opacity:0.5;color:#d40000;text-decoration:none}.logo span{color:#333}.logo a:hover{opacity:0.8;color:#333}.logo a:focus span,.logo a:hover span{color:#d40000}.page-header{margin-bottom:20px}.page-header .dropdown{padding-right:10px}.page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #ccc}.page-header h2 a{color:#333;text-decoration:none}.page-header h2 a:focus,.page-header h2 a:hover{color:#999}.page-header ul{text-align:left;margin-top:5px;display:inline-block}.page-header li{display:inline;padding-right:15px}@media (max-width: 480px){.page-header li{display:block;line-height:1.5em}}.page-header li.active a{color:#333;text-decoration:none;font-weight:bold}.page-header li.active a:hover,.page-header li.active a:focus{text-decoration:underline}.menu-inline{margin-bottom:5px}.menu-inline li{display:inline;padding-right:15px}.menu-inline li .active a{font-weight:bold;color:#000;text-decoration:none}.sidebar-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.sidebar-container>*{box-sizing:border-box}.sidebar-container>*{width:1%}.sidebar-content{padding-left:10px;width:82%}@media (max-width: 480px){.sidebar-content{width:100%}}.sidebar{max-width:240px;min-width:190px;width:18%}@media (max-width: 480px){.sidebar{width:100%;max-width:99%;min-width:0}}.sidebar h2{margin-top:0}.sidebar>ul a{text-decoration:none;color:#999;font-weight:300}.sidebar>ul a:hover{color:#333}.sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef;padding-left:13px}.sidebar>ul li:hover{border-left:5px solid #555;padding-left:8px}.sidebar>ul li.active{border-left:5px solid #333;padding-left:8px}.sidebar>ul li.active a{color:#333;font-weight:bold}.sidebar-icons>ul li{padding-left:0}.sidebar-icons>ul li:hover,.sidebar-icons>ul li.active{padding-left:0;border-left:none}.sidebar>ul li.active a:focus,.sidebar>ul li.active a:hover{color:#555}.sidebar>ul li:last-child{margin-bottom:15px}.avatar img{vertical-align:bottom}.avatar-left{float:left;margin-right:10px}.avatar-inline{display:inline-block;margin-right:3px}.avatar-48 img,.avatar-48 div{border-radius:30px}.avatar-48 .avatar-letter{line-height:48px;width:48px;font-size:25px}.avatar-20 img,.avatar-20 div{border-radius:10px}.avatar-20 .avatar-letter{line-height:20px;width:20px;font-size:11px}.avatar-letter{color:#fff;text-align:center}#file-dropzone,#screenshot-zone{position:relative;border:2px dashed #ccc;width:99%;height:250px;overflow:auto}#file-dropzone-inner,#screenshot-inner{position:absolute;left:0;bottom:48%;width:100%;text-align:center;color:#aaa}#screenshot-zone.screenshot-pasted{border:2px solid #333}#file-list{margin:20px}#file-list li{list-style-type:none;padding-top:8px;padding-bottom:8px;border-bottom:1px dotted #ddd;width:95%}#file-list li .file-error{font-weight:bold;color:#b94a48}.file-thumbnails{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:flex-start;justify-content:flex-start}.file-thumbnail{width:250px;border:1px solid #efefef;border-radius:5px;margin-bottom:20px;box-shadow:4px 2px 10px -6px rgba(0,0,0,0.55);margin-right:15px}.file-thumbnail img{cursor:pointer;border-top-left-radius:5px;border-top-right-radius:5px}.file-thumbnail img:hover{opacity:0.5}.file-thumbnail-content{padding-left:8px;padding-right:8px}.file-thumbnail-title{font-weight:700;font-size:0.9em;color:#555;overflow:hidden;text-overflow:ellipsis}.file-thumbnail-description{font-size:0.8em;color:#999;margin-top:8px;margin-bottom:5px}.file-viewer{position:relative}.file-viewer img{max-width:95%;max-height:85%;margin-top:10px}.color-picker{width:180px}.color-picker-option{height:25px}.color-picker-square{display:inline-block;width:18px;height:18px;margin-right:5px;border:1px solid #000}.color-picker-label{display:inline-block;vertical-align:bottom;padding-bottom:3px}.filter-box{max-width:800px}.action-menu{color:#333;text-decoration:none}.action-menu:hover,.action-menu:focus{text-decoration:underline}.js-project-creation-options{max-width:500px;border-left:3px dotted #efefef;margin-top:20px;padding-left:15px;padding-bottom:5px;padding-top:5px}.project-overview-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;margin-bottom:20px;font-size:1.4em}@media (max-width: 480px){.project-overview-columns{display:block}}.project-overview-column{text-align:center;margin-right:3%;margin-top:5px;padding:3px 15px 3px 15px;border:1px dashed #ddd}@media (max-width: 480px){.project-overview-column{text-align:left}}.project-overview-column small{color:#999}.project-overview-column strong{color:#555;display:block}@media (max-width: 480px){.project-overview-column strong{display:inline}}.project-header{box-sizing:border-box;display:flex;flex-wrap:wrap;margin-bottom:8px}.project-header>*{box-sizing:border-box}.project-header>*{width:1%}.project-header .dropdown-component{margin-top:4px;width:5%}@media (min-width: 768px) and (max-width: 1150px){.project-header .dropdown-component{width:8%}}@media (max-width: 768px){.project-header .dropdown-component{width:100%}}.project-header .views-switcher-component{margin-top:4px;width:38%}@media (max-width: 1300px){.project-header .views-switcher-component{width:45%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .views-switcher-component{width:92%}}@media (max-width: 768px){.project-header .views-switcher-component{margin-top:0;width:100%}}.project-header .filter-box-component{margin:0;width:55%}@media (max-width: 1300px){.project-header .filter-box-component{width:50%}}@media (min-width: 768px) and (max-width: 1150px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}@media (max-width: 768px){.project-header .filter-box-component{width:100%;margin-top:10px}.project-header .filter-box-component .filter-box{max-width:100%}}.project-header .filter-box-component form{margin:0}.views{display:inline-block;margin-right:10px;font-size:0.9em}@media (max-width: 560px){.views{width:100%}}@media (max-width: 768px){.views{margin-top:10px;font-size:1em}}@media (max-width: 480px){.views{margin-top:5px}}.views li{white-space:nowrap;background:#fafafa;border:1px solid #ddd;border-right:none;padding:4px 8px;display:inline}@media (max-width: 560px){.views li{display:block;margin-top:5px;border-radius:5px;border:1px solid #ddd}}.views li.active a{font-weight:bold;color:#000;text-decoration:none}.views li:first-child{border-top-left-radius:5px;border-bottom-left-radius:5px}.views li:last-child{border-right:1px solid #ddd;border-top-right-radius:5px;border-bottom-right-radius:5px}.views a{color:#555;text-decoration:none}.views a:hover{color:#333;text-decoration:underline}.dashboard-project-stats small{margin-right:10px;color:#999}.dashboard-table-link{font-weight:bold;color:#000;text-decoration:none}.dashboard-table-link:focus,.dashboard-table-link:hover{color:#999}.public-board{margin-top:5px}.public-task{max-width:800px;margin:5px auto 0}#board-container{overflow-x:auto}#board{table-layout:fixed;margin-bottom:0}#board th.board-column-header{width:240px}#board td{vertical-align:top}.board-container-compact{overflow-x:initial}@media all and (-ms-high-contrast: active), (-ms-high-contrast: none){.board-container-compact #board{table-layout:auto}}#board th.board-column-header.board-column-compact{width:initial}.board-column-collapsed{display:none}td.board-column-task-collapsed{font-weight:bold;background-color:#fbfbfb}#board th.board-column-header-collapsed{width:28px;min-width:28px;text-align:center;overflow:hidden}.board-rotation-wrapper{position:relative;padding:8px 4px;min-height:150px;overflow:hidden}.board-rotation{white-space:nowrap;-webkit-backface-visibility:hidden;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:0 100%;-moz-transform-origin:0 100%;-ms-transform-origin:0 100%;transform-origin:0 100%}.board-column-title .dropdown-menu{text-decoration:none}.board-add-icon{float:left;padding:0 5px}.board-add-icon i{text-decoration:none;color:#36c;font-size:1.4em}.board-add-icon i:focus,.board-add-icon i:hover{text-decoration:none;color:red}.board-column-header-task-count{color:#999;font-weight:normal}a.board-swimlane-toggle{text-decoration:none}a.board-swimlane-toggle:hover,a.board-swimlane-toggle:focus{color:#000;text-decoration:none;border:none}.board-task-list{min-height:60px}.board-task-list-limit{background-color:#DF5353}.draggable-item{cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none}.draggable-placeholder{border:2px dashed #000;background:#fafafa;height:70px;margin-bottom:10px}div.draggable-item-selected{border:1px solid #000}.task-board-sort-handle{float:left;padding-right:5px}.task-board{position:relative;margin-bottom:4px;border:1px solid #000;padding:2px;word-wrap:break-word;font-size:0.9em}div.task-board-recent{border-width:2px}div.task-board-status-closed{user-select:none;border:1px dotted #555}.task-board a{color:#000;text-decoration:none}.task-board .dropdown-menu{font-weight:bold}.task-board .task-score{font-weight:bold}.task-board-collapsed{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.task-board-title{margin-top:5px;margin-bottom:8px}.task-board-title a:hover{text-decoration:underline}.task-board-saving-state{opacity:0.3}.task-board-saving-icon{position:absolute;margin:auto;width:100%;text-align:center;color:#000}.task-board-category-container{text-align:right;margin-top:8px;margin-bottom:8px}.task-board-category{font-weight:500;color:#000;border:1px solid #555;padding:1px 2px 1px 2px;border-radius:4px}.task-board-category:hover{opacity:0.6}.task-board-avatars{text-align:right;float:right}.task-board-change-assignee{cursor:pointer}.task-board-change-assignee:hover{opacity:0.6}.task-board-icons{font-size:0.8em;text-align:right;margin-top:4px;margin-bottom:2px}.task-board-icons a{opacity:0.5}.task-board-icons span{opacity:0.5;margin-left:2px}.task-board-icons a:hover,.task-board-icons span:hover{opacity:1.0}.flag-milestone{color:green}.task-board-age{display:inline-block}span.task-board-age-total{border:#666 1px solid;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px}span.task-board-age-column{border:#666 1px solid;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px}.task-board-date{font-weight:bold;color:#000}span.task-board-date-today{opacity:1.0;color:#36c}span.task-board-date-overdue{opacity:1.0;color:#b94a48}.task-tags li{display:inline-block;margin:3px 3px 0 0;padding:1px 3px 1px 3px;color:#333;border:1px solid #333;border-radius:4px}.task-summary-container .task-tags{margin-top:10px}#task-summary{margin-bottom:15px}#task-summary h2{color:#555;font-size:1.6em;margin-top:0;padding-top:0}.task-summary-container{border:2px solid #000;border-radius:8px;padding:15px}.task-summary-columns{display:-webkit-flex;display:flex;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}@media (max-width: 480px){.task-summary-columns{display:block}}.task-summary-column{color:#333}.task-summary-column span{color:#555}.task-summary-column li{line-height:23px}#external-task-view{padding:10px;margin-top:10px;margin-bottom:10px;border:1px dotted #ccc}.task-form-container{box-sizing:border-box;display:flex;flex-wrap:wrap}.task-form-container>*{box-sizing:border-box}.task-form-container>*{width:1%}.task-form-main-column{width:60%}@media (max-width: 1000px){.task-form-main-column{width:100%}}.task-form-main-column input[type="text"]{width:700px;max-width:99%}.task-form-secondary-column{max-width:250px;min-width:200px;max-height:600px;padding-left:10px;overflow:auto;width:20%}@media (max-width: 1000px){.task-form-secondary-column{width:100%;max-width:99%;max-height:none}}.task-form-secondary-column label:first-child{margin-top:0}@media (max-width: 1000px){.task-form-secondary-column label:first-child{margin-top:10px}}.task-form-bottom{width:100%}.task-table .dropdown-menu{color:#000;text-decoration:none;font-weight:bold}.task-table .dropdown-menu:focus,.task-table .dropdown-menu:hover{text-decoration:underline}td.task-table a{color:#000;text-decoration:none}td.task-table a:hover{text-decoration:underline}.comment-sorting{text-align:right}.comment-sorting a{color:#555;font-weight:normal;text-decoration:none}.comment-sorting a:hover{color:#999}.comment{padding:5px;margin-bottom:15px}.comment:hover{background:#fafafa}.comment-title{border-bottom:1px dotted #eee;margin-left:55px;margin-bottom:10px}.comment-date{color:#999;font-weight:200}.comment-actions{font-size:0.8em;margin-left:55px;margin-top:8px}.comment-actions li{display:inline}.comment-actions a{color:#999;text-decoration:none}.comment-actions a:focus,.comment-actions a:hover{color:#333;text-decoration:underline}.comment-content{margin-left:55px}.subtasks-table td{vertical-align:middle}.task-links-table td{vertical-align:middle}.task-links-task-count{color:#999}.task-link-closed{text-decoration:line-through}.text-editor{margin-top:10px}.text-editor a{font-size:1em;color:#999;text-decoration:none;margin-right:10px}.text-editor a:hover{color:#36c}.text-editor .text-editor-preview-area{border:1px solid #dedede;width:700px;max-width:99%;height:250px;overflow:auto;padding:2px}.text-editor textarea{width:700px;max-width:98%;height:250px}.markdown{line-height:1.4em}.markdown h1{margin-top:5px;margin-bottom:10px;font-weight:bold}.markdown h2{font-weight:bold}.markdown p{margin-bottom:10px}.markdown ol,.markdown ul{margin-left:25px;margin-top:10px;margin-bottom:10px}.markdown pre{background:#fbfbfb;padding:10px;border-radius:5px;border:1px solid #ddd;overflow:auto;color:#555}.markdown blockquote{font-style:italic;border-left:3px solid #ddd;padding-left:10px;margin-bottom:10px;margin-left:20px}.markdown img{display:block;max-width:80%;margin-top:10px}.documentation{margin:0 auto;padding:20px;max-width:850px;background:#fefefe;border:1px solid #ccc;border-radius:5px;color:#555}.documentation img{border:1px solid #333}.documentation h1{text-decoration:none;margin-bottom:30px}.documentation h2{text-decoration:none;border-bottom:1px solid #ccc;margin-bottom:25px}.documentation li{line-height:30px}.panel{border-radius:4px;padding:8px 35px 8px 10px;margin-top:10px;margin-bottom:15px;border:1px solid #ddd;color:#333;background-color:#fcfcfc;overflow:auto}.panel li{list-style-type:square;margin-left:20px;line-height:1.35em}.activity-event{margin-bottom:15px;padding:10px}.activity-event:hover{background:#fafafa}.activity-date{margin-left:10px;font-weight:normal;color:#999}.activity-content{margin-left:55px}.activity-title{font-weight:bold;color:#000;border-bottom:1px dotted #efefef}.activity-description{color:#555;margin-top:10px}@media (max-width: 480px){.activity-description{overflow:auto}}.activity-description li{list-style-type:circle}.activity-description ul{margin-top:10px;margin-left:20px}div.ganttview-hzheader-month,div.ganttview-hzheader-day,div.ganttview-vtheader,div.ganttview-vtheader-item-name,div.ganttview-vtheader-series,div.ganttview-grid,div.ganttview-grid-row-cell{float:left}div.ganttview-hzheader-month,div.ganttview-hzheader-day{text-align:center}div.ganttview-grid-row-cell.last,div.ganttview-hzheader-day.last,div.ganttview-hzheader-month.last{border-right:none}div.ganttview{border:1px solid #999}div.ganttview-hzheader-month{width:60px;height:20px;border-right:1px solid #d0d0d0;line-height:20px;overflow:hidden}div.ganttview-hzheader-day{width:20px;height:20px;border-right:1px solid #f0f0f0;border-top:1px solid #d0d0d0;line-height:20px;color:#555}div.ganttview-vtheader{margin-top:41px;width:400px;overflow:hidden;background-color:#fff}div.ganttview-vtheader-item{color:#555}div.ganttview-vtheader-series-name{width:400px;height:31px;line-height:31px;padding-left:3px;border-top:1px solid #d0d0d0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}div.ganttview-vtheader-series-name a{color:#555;text-decoration:none}div.ganttview-vtheader-series-name a:hover{color:#333;text-decoration:underline}div.ganttview-vtheader-series-name a i{color:#000}div.ganttview-vtheader-series-name a:hover i{color:#555}div.ganttview-slide-container{overflow:auto;border-left:1px solid #999}div.ganttview-grid-row-cell{width:20px;height:31px;border-right:1px solid #f0f0f0;border-top:1px solid #f0f0f0}div.ganttview-grid-row-cell.ganttview-weekend{background-color:#fafafa}div.ganttview-blocks{margin-top:40px}div.ganttview-block-container{height:28px;padding-top:4px}div.ganttview-block{position:relative;height:25px;background-color:#E5ECF9;border:1px solid #c0c0c0;border-radius:3px}.ganttview-block-movable{cursor:move}div.ganttview-block-not-defined{border-color:#000;background-color:#000}div.ganttview-block-text{position:absolute;height:12px;font-size:0.7em;color:#999;padding:2px 3px}div.ganttview-block div.ui-resizable-handle.ui-resizable-s{bottom:-0}.user-mention-link{font-weight:bold;color:#000;text-decoration:none}.user-mention-link:hover{color:#555}.image-slideshow-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.95);overflow:auto;z-index:100}.image-slideshow-overlay img{display:block;margin:auto}.image-slideshow-overlay figcaption{color:#fff;opacity:0.7;position:absolute;bottom:5px;right:15px}.slideshow-icon{color:#fff;position:absolute;font-size:2.5em;opacity:0.6}.slideshow-icon:hover{opacity:0.9;cursor:pointer}.slideshow-previous-icon{left:10px;top:45%}.slideshow-next-icon{right:10px;top:45%}.slideshow-close-icon{right:10px;top:10px;font-size:1.4em}.slideshow-download-icon{left:10px;bottom:10px;font-size:1.3em}
diff --git a/assets/js/app.min.js b/assets/js/app.min.js
index 4f41b58f..5eb6fbca 100644
--- a/assets/js/app.min.js
+++ b/assets/js/app.min.js
@@ -1,2 +1,3 @@
-!function(){function t(t,a,i){if(!o)throw new Error("textarea-caret-position#getCaretCoordinates should only be called in a browser");var r=i&&i.debug||!1;if(r){var s=document.querySelector("#input-textarea-caret-position-mirror-div");s&&s.parentNode.removeChild(s)}var d=document.createElement("div");d.id="input-textarea-caret-position-mirror-div",document.body.appendChild(d);var l=d.style,c=window.getComputedStyle?getComputedStyle(t):t.currentStyle;l.whiteSpace="pre-wrap","INPUT"!==t.nodeName&&(l.wordWrap="break-word"),l.position="absolute",r||(l.visibility="hidden"),e.forEach(function(t){l[t]=c[t]}),n?t.scrollHeight>parseInt(c.height)&&(l.overflowY="scroll"):l.overflow="hidden",d.textContent=t.value.substring(0,a),"INPUT"===t.nodeName&&(d.textContent=d.textContent.replace(/\s/g," "));var p=document.createElement("span");p.textContent=t.value.substring(a)||".",d.appendChild(p);var u={top:p.offsetTop+parseInt(c.borderTopWidth),left:p.offsetLeft+parseInt(c.borderLeftWidth)};return r?p.style.backgroundColor="#aaa":document.body.removeChild(d),u}var e=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],o="undefined"!=typeof window,n=o&&null!=window.mozInnerScreenX;"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=t:o&&(window.getCaretCoordinates=t)}(),Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(t){for(var e=(this.document||this.ownerDocument).querySelectorAll(t),o=e.length;--o>=0&&e.item(o)!==this;);return o>-1});var KB={components:{},utils:{},html:{},http:{},listeners:{clicks:{},changes:{},keys:{},internals:{}}};KB.on=function(t,e){this.listeners.internals.hasOwnProperty(t)||(this.listeners.internals[t]=[]),this.listeners.internals[t].push(e)},KB.trigger=function(t,e){if(this.listeners.internals.hasOwnProperty(t))for(var o=0;o<this.listeners.internals[t].length&&this.listeners.internals[t][o](e);o++);},KB.onClick=function(t,e){this.listeners.clicks[t]=e},KB.onChange=function(t,e){this.listeners.changes[t]=e},KB.onKey=function(t,e){this.listeners.keys[t]=e},KB.listen=function(){function t(t){for(var e in n.listeners.clicks)n.listeners.clicks.hasOwnProperty(e)&&t.target.matches(e)&&(t.preventDefault(),n.listeners.clicks[e](t))}function e(t){for(var e in n.listeners.changes)n.listeners.changes.hasOwnProperty(e)&&t.target.matches(e)&&n.listeners.changes[e](t.target)}function o(t){var e="number"==typeof t.which?t.which:t.keyCode,o=t.target;if("INPUT"!==o.tagName&&"SELECT"!==o.tagName&&"TEXTAREA"!==o.tagName&&!o.isContentEditable)for(var a in n.listeners.keys)n.listeners.keys.hasOwnProperty(a)&&e===parseInt(a)&&(t.preventDefault(),n.listeners.keys[e](t))}var n=this;document.addEventListener("click",t,!1),document.addEventListener("change",e,!1),document.addEventListener("keypress",o,!1)},KB.component=function(t,e){this.components[t]=e},KB.getComponent=function(t,e,o){var n=this.components[t];return new n(e,o)},KB.render=function(){for(var t in this.components)for(var e=document.querySelectorAll(".js-"+t),o=0;o<e.length;o++)if(this.components.hasOwnProperty(t)){var n;e[o].dataset.params&&(n=JSON.parse(e[o].dataset.params));var a=KB.getComponent(t,e[o],n);a.render(),e[o].className=e[o].className+"-rendered"}},KB.interval=function(t,e){setInterval(e,1e3*t)},KB.dom=function(t){function e(t){var e="string"==typeof t?document.createElement(t):t;this.attr=function(t,o){return null!==o&&e.setAttribute(t,o),this},this.data=function(t,o){return 1===arguments.length?e.dataset[t]:(e.dataset[t]=o,this)},this.hide=function(){return e.style.display="none",this},this.show=function(){return e.style.display="block",this},this.toggle=function(){return"none"===e.style.display?this.show():this.hide(),this},this.style=function(t,o){return e.style[t]=o,this},this.on=function(t,o,n){return e.addEventListener(t,function(t){n||t.preventDefault(),o(t.target)}),this},this.click=function(t){return this.on("click",t)},this.mouseover=function(t){return this.on("mouseover",t)},this.change=function(t){return this.on("change",t)},this.add=function(t){return e.appendChild(t),this},this.replace=function(t){return e.parentNode.replaceChild(t,e),this},this.html=function(t){return e.innerHTML=t,this},this.text=function(t){return e.appendChild(document.createTextNode(t)),this},this.addClass=function(t){return e.classList.add(t),this},this.removeClass=function(t){return e.classList.remove(t),this},this.toggleClass=function(t){return e.classList.toggle(t),this},this.hasClass=function(t){return e.classList.contains(t)},this.disable=function(){return e.disabled=!0,this},this.enable=function(){return e.disabled=!1,this},this.remove=function(){return e.parentNode.removeChild(e),this},this.parent=function(t){for(;e&&e!==document;e=e.parentNode)if(e.matches(t))return e;return null},this.find=function(t){return e.querySelector(t)},this["for"]=function(t,o){for(var n=0;n<o.length;n++){var a=o[n];if("object"!=typeof a)e.appendChild(KB.dom(t).text(a).build());else{var i=KB.dom(t);for(var r in a)a.hasOwnProperty(r)&&r in this&&"function"==typeof this[r]?i[r](a[r]):i.attr(r,a[r]);e.appendChild(i.build())}}return this},this.build=function(){return e}}return new e(t)},KB.find=function(t){var e=document.querySelector(t);return e?KB.dom(e):null},KB.html.label=function(t,e){return KB.dom("label").attr("for",e).text(t).build()},KB.html.radio=function(t,e,o){return KB.dom("label").add(KB.dom("input").attr("type","radio").attr("name",e).attr("value",o).build()).text(t).build()},KB.html.radios=function(t){var e=KB.dom("div");for(var o in t)t.hasOwnProperty(o)&&e.add(KB.html.radio(o.label,o.name,o.value))},KB.http.request=function(t,e,o,n){function a(t){try{return JSON.parse(t.responseText)}catch(e){return t.responseText}}var i=function(){},r=function(){};this.execute=function(){var s=new XMLHttpRequest;s.open(t,e,!0),s.setRequestHeader("X-Requested-With","XMLHttpRequest");for(var d in o)o.hasOwnProperty(d)&&s.setRequestHeader(d,o[d]);return s.onerror=function(){r()},s.onreadystatechange=function(){if(s.readyState===XMLHttpRequest.DONE){var t=a(s);200===s.status?i(t):r(t)}},s.send(n),this},this.success=function(t){return i=t,this},this.error=function(t){return r=t,this}},KB.http.get=function(t){return new KB.http.request("GET",t).execute()},KB.http.postJson=function(t,e){var o={"Content-Type":"application/json",Accept:"application/json"};return new KB.http.request("POST",t,o,JSON.stringify(e)).execute()},KB.utils.formatDuration=function(t){return t>=86400?Math.round(t/86400)+"d":t>=3600?Math.round(t/3600)+"h":t>=60?Math.round(t/60)+"m":t+"s"},KB.utils.getSelectionPosition=function(t){var e,o;return e=t.value.length<t.selectionStart?t.value.length:t.selectionStart,o=t.selectionStart===t.selectionEnd?e:t.selectionEnd,{selectionStart:e,selectionEnd:o}},KB.onClick(".accordion-toggle",function(t){var e=KB.dom(t.target).parent(".accordion-section");e&&(KB.dom(e).toggleClass("accordion-collapsed"),KB.dom(KB.dom(e).find(".accordion-content")).toggle())}),KB.component("calendar",function(t,e){this.render=function(){var o=$(t);o.fullCalendar({locale:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(t){$.ajax({cache:!1,url:e.saveUrl,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t.id,date_due:t.start.format()})})},viewRender:function(){var t=e.checkUrl,n={start:o.fullCalendar("getView").start.format(),end:o.fullCalendar("getView").end.format()};for(var a in n)t+="&"+a+"="+n[a];$.getJSON(t,function(t){o.fullCalendar("removeEvents"),o.fullCalendar("addEventSource",t),o.fullCalendar("rerenderEvents")})}})}}),KB.component("chart-project-avg-time-column",function(t,e){this.render=function(){var o=e.metrics,n=[e.label],a=[];for(var i in o)n.push(o[i].average),a.push(o[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[n],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("chart-project-burndown",function(t,e){this.render=function(){for(var o=e.metrics,n=[[e.labelTotal]],a=[],i=d3.time.format("%Y-%m-%d"),r=d3.time.format(e.dateFormat),s=0;s<o.length;s++)for(var d=0;d<o[s].length;d++)0===s?n.push([o[s][d]]):(n[d+1].push(o[s][d]),d>0&&(void 0===n[0][s]&&n[0].push(0),n[0][s]+=o[s][d]),0===d&&a.push(r(i.parse(o[s][d]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n},axis:{x:{type:"category",categories:a}}})}}),KB.component("chart-project-cumulative-flow",function(t,e){this.render=function(){for(var o=e.metrics,n=[],a=[],i=[],r=d3.time.format("%Y-%m-%d"),s=d3.time.format(e.dateFormat),d=0;d<o.length;d++)for(var l=0;l<o[d].length;l++)0===d?(n.push([o[d][l]]),l>0&&a.push(o[d][l])):(n[l].push(o[d][l]),0===l&&i.push(s(r.parse(o[d][l]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n,type:"area-spline",groups:[a]},axis:{x:{type:"category",categories:i}}})}}),KB.component("chart-project-lead-cycle-time",function(t,e){this.render=function(){var o=e.metrics,n=[e.labelCycle],a=[e.labelLead],i=[],r={};r[e.labelCycle]="area",r[e.labelLead]="area-spline";var s={};s[e.labelLead]="#afb42b",s[e.labelCycle]="#4e342e";for(var d=0;d<o.length;d++)n.push(parseInt(o[d].avg_cycle_time)),a.push(parseInt(o[d].avg_lead_time)),i.push(o[d].day);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[a,n],types:r,colors:s},axis:{x:{type:"category",categories:i},y:{tick:{format:KB.utils.formatDuration}}}})}}),KB.component("chart-project-task-distribution",function(t,e){this.render=function(){for(var o=[],n=0;n<e.metrics.length;n++)o.push([e.metrics[n].column_title,e.metrics[n].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-project-time-comparison",function(t,e){this.render=function(){var o=[e.labelSpent],n=[e.labelEstimated],a=[];for(var i in e.metrics)o.push(e.metrics[i].time_spent),n.push(e.metrics[i].time_estimated),a.push("open"===i?e.labelOpen:e.labelClosed);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[o,n],type:"bar"},bar:{width:{ratio:.2}},axis:{x:{type:"category",categories:a}},legend:{show:!0}})}}),KB.component("chart-project-user-distribution",function(t,e){this.render=function(){for(var o=[],n=0;n<e.metrics.length;n++)o.push([e.metrics[n].user,e.metrics[n].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"donut"}})}}),KB.component("chart-task-time-column",function(t,e){this.render=function(){for(var o=e.metrics,n=[e.label],a=[],i=0;i<o.length;i++)n.push(o[i].time_spent),a.push(o[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[n],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("external-task-view",function(t,e){this.render=function(){$.ajax({cache:!1,url:e.url,success:function(e){KB.dom(t).html('<div id="external-task-view">'+e+"</div>")}})}}),KB.component("image-slideshow",function(t,e){function o(t){switch(t.keyCode){case 27:d();break;case 39:i();break;case 37:r()}}function n(t){t.matches(".slideshow-next-icon")?i():t.matches(".slideshow-previous-icon")?r():t.matches(".slideshow-download-icon")?window.location.href=t.href:d()}function a(t){var e=KB.dom(t).data("imageId"),o=l(e);s(o)}function i(){d();for(var t=0;t<e.images.length;t++)if(e.images[t].id===u.id){var o=t+1;o>=e.images.length&&(o=0),u=e.images[o];break}s()}function r(){d();for(var t=0;t<e.images.length;t++)if(e.images[t].id===u.id){var o=t-1;o<0&&(o=e.images.length-1),u=e.images[o];break}s()}function s(){var t=KB.dom("div").attr("class","fa fa-window-close slideshow-icon slideshow-close-icon").build(),e=KB.dom("a").attr("class","fa fa-download slideshow-icon slideshow-download-icon").attr("href",c(u,"download")).build(),a=KB.dom("div").attr("class","fa fa-chevron-circle-left slideshow-icon slideshow-previous-icon").build(),i=KB.dom("div").attr("class","fa fa-chevron-circle-right slideshow-icon slideshow-next-icon").build(),r=KB.dom("img").attr("src",c(u,"image")).attr("alt",u.name).attr("title",u.name).style("maxHeight",window.innerHeight-50+"px").build(),s=KB.dom("figcaption").text(u.name).build(),d=KB.dom("figure").add(r).add(s).build(),l=KB.dom("div").addClass("image-slideshow-overlay").add(t).add(e).add(a).add(i).add(d).click(n).build();document.body.appendChild(l),document.addEventListener("keydown",o,!1)}function d(){var t=KB.find(".image-slideshow-overlay");null!==t&&(document.removeEventListener("keydown",o,!1),t.remove())}function l(t){for(var o=0;o<e.images.length;o++)if(e.images[o].id===t)return e.images[o];return null}function c(t,o){var n=new RegExp(e.regex,"g");return e.url[o].replace(n,t.id)}function p(t){return KB.dom("img").attr("src",c(t,"thumbnail")).attr("alt",t.name).attr("title",t.name).data("imageId",t.id).click(a).build()}var u;this.render=function(){u=e.image,t.appendChild(p(u))}}),KB.onKey(98,function(){KB.trigger("board.selector.open")}),KB.onChange(".js-project-creation-select-options",function(t){var e=t.value;"0"===e?KB.find(".js-project-creation-options").hide():KB.find(".js-project-creation-options").show()}),KB.component("project-select-role",function(t,e){function o(t){s=!0,e.role=t.value,a(),n()}function n(){KB.http.postJson(e.url,{id:e.id,role:e.role}).success(function(){s=!1,d=!0,a()}).error(function(){s=!1,d=!1,l=!0,a()})}function a(){KB.dom(r).remove(),r=i(),t.appendChild(r)}function i(){var t=[],n=KB.dom("div");for(var a in e.roles)if(e.roles.hasOwnProperty(a)){var i={value:a,text:e.roles[a]};e.role===a&&(i.selected="selected"),t.push(i)}return n.add(KB.dom("select").change(o)["for"]("option",t).build()),s?(n.text(" "),n.add(KB.dom("i").attr("class","fa fa-spinner fa-pulse fa-fw").build())):d?(n.text(" "),n.add(KB.dom("i").attr("class","fa fa-check fa-fw icon-fade-out icon-success").build())):l&&(n.text(" "),n.add(KB.dom("i").attr("class","fa fa-check fa-fw icon-fade-out icon-error").build())),n.build()}var r,s=!1,d=!1,l=!1;this.render=function(){r=i(),t.appendChild(r)}}),KB.component("select-dropdown-autocomplete",function(t,e){function o(t){switch(t.keyCode){case 27:y.value="",m();break;case 38:t.preventDefault(),t.stopImmediatePropagation(),c();break;case 40:t.preventDefault(),t.stopImmediatePropagation(),p();break;case 13:t.preventDefault(),t.stopImmediatePropagation(),d()}}function n(){m(),v()}function a(t){KB.dom(t).hasClass("select-dropdown-menu-item")&&(KB.find(".select-dropdown-menu-item.active").removeClass("active"),KB.dom(t).addClass("active"))}function i(){d()}function r(e){t.contains(e.target)||(y.value="",m())}function s(){var t=KB.find("#select-dropdown-menu");null===t?v():m()}function d(){var t=KB.find(".select-dropdown-menu-item.active"),o=t.data("value");if(w.value=o,y.value=e.items[o],m(),e.redirect){var n=new RegExp(e.redirect.regex,"g");window.location=e.redirect.url.replace(n,o)}}function l(){for(var t=document.querySelectorAll(".select-dropdown-menu-item"),e=0;e<t.length;e++)if(KB.dom(t[e]).hasClass("active")){KB.dom(t[e]).removeClass("active");break}return{items:t,index:e}}function c(){var t=l();t.index>0&&(t.index=t.index-1),KB.dom(t.items[t.index]).addClass("active")}function p(){var t=l();t.index<t.items.length-1&&t.index++,KB.dom(t.items[t.index]).addClass("active")}function u(t){var o=[],n=Object.keys(t);e.sortByKeys&&n.sort();for(var a=0;a<n.length;a++)o.push({"class":"select-dropdown-menu-item",text:t[n[a]],"data-label":t[n[a]],"data-value":n[a]});return o}function h(t,o){for(var n=[],a=!1,i=0;i<o.length;i++)if(0===t.length||0===o[i]["data-label"].toLowerCase().indexOf(t.toLowerCase())){var r=o[i];"undefined"!=typeof e.defaultValue&&String(e.defaultValue)===r["data-value"]&&(r["class"]+=" active",a=!0),n.push(r)}return!a&&n.length>0&&(n[0]["class"]+=" active"),n}function f(){var t=h(y.value,u(e.items)),o=b.getBoundingClientRect();return 0===t.length?null:KB.dom("ul").attr("id","select-dropdown-menu").style("top",o.bottom+"px").style("left",o.left+"px").style("width",o.width+"px").style("maxHeight",window.innerHeight-o.bottom-20+"px").mouseover(a).click(i)["for"]("li",t).build()}function m(){var t=KB.find("#select-dropdown-menu");null!==t&&t.remove(),document.removeEventListener("keydown",o,!1),document.removeEventListener("click",r,!1)}function v(){var t=f();null!==t&&document.body.appendChild(t),document.addEventListener("keydown",o,!1),document.addEventListener("click",r,!1)}function g(){return e.defaultValue&&e.defaultValue in e.items?e.items[e.defaultValue]:e.placeholder?e.placeholder:""}var b,y,w;this.render=function(){var o=KB.dom("i").attr("class","fa fa-chevron-down select-dropdown-chevron").click(s).build();w=KB.dom("input").attr("type","hidden").attr("name",e.name).attr("value",e.defaultValue||"").build(),y=KB.dom("input").attr("type","text").attr("placeholder",g()).addClass("select-dropdown-input").style("width",t.offsetWidth-30+"px").on("focus",s).on("input",n,!0).build(),b=KB.dom("div").addClass("select-dropdown-input-container").add(w).add(y).add(o).build(),t.appendChild(b),e.onFocus&&e.onFocus.forEach(function(t){KB.on(t,function(){y.focus()})})}}),KB.interval(60,function(){var t=KB.find("body").data("statusUrl"),e=KB.find("body").data("loginUrl");null===KB.find(".form-login")&&KB.http.get(t).error(function(){window.location=e})}),KB.component("submit-cancel",function(t,e){function o(){r=!0,KB.find("#modal-submit-button").replace(i()),KB.trigger("modal.submit")}function n(){KB.trigger("modal.cancel"),_KB.get("Popover").close()}function a(){r=!1,KB.find("#modal-submit-button").replace(i())}function i(){var t=KB.dom("button").click(o).attr("id","modal-submit-button").attr("type","submit").attr("class","btn btn-blue");return r&&t.disable().add(KB.dom("i").attr("class","fa fa-spinner fa-pulse").build()).text(" "),t.text(e.submitLabel).build()}var r=!1;this.render=function(){KB.on("modal.stop",a);var o=KB.dom("div").attr("class","form-actions").add(i()).text(" "+e.orLabel+" ").add(KB.dom("a").attr("href","#").click(n).text(e.cancelLabel).build()).build();t.appendChild(o)}}),KB.component("suggest-menu",function(t,e){function o(t){switch(t.keyCode){case 27:p();break;case 38:t.preventDefault(),t.stopImmediatePropagation(),l();break;case 40:t.preventDefault(),t.stopImmediatePropagation(),c();break;case 13:t.preventDefault(),t.stopImmediatePropagation(),i()}}function n(){i()}function a(t){KB.dom(t).hasClass("suggest-menu-item")&&(KB.find(".suggest-menu-item.active").removeClass("active"),KB.dom(t).addClass("active"))}function i(){t.focus();var e=KB.find(".suggest-menu-item.active"),o=e.data("value"),n=e.data("trigger"),a=t.value,i=r(t),s=n+o+" ",d=KB.utils.getSelectionPosition(t),l=a.substring(0,d.selectionStart-i.length),c=a.substring(d.selectionEnd),u=l.length+s.length;t.value=l+s+c,t.setSelectionRange(u,u),p()}function r(t){var e=t.value.substring(0,t.selectionEnd).split("\n"),o=e[e.length-1],n=o.split(" ");return n[n.length-1]}function s(){for(var t=[".popover-form","#popover-content","body"],e=0;e<t.length;e++){var o=document.querySelector(t[e]);if(null!==o)return o}return null}function d(){for(var t=document.querySelectorAll(".suggest-menu-item"),e=0;e<t.length;e++)if(KB.dom(t[e]).hasClass("active")){KB.dom(t[e]).removeClass("active");break}return{items:t,index:e}}function l(){var t=d();t.index>0&&(t.index=t.index-1),KB.dom(t.items[t.index]).addClass("active")}function c(){var t=d();t.index<t.items.length-1&&t.index++,KB.dom(t.items[t.index]).addClass("active")}function p(){var t=KB.find("#suggest-menu");null!==t&&t.remove(),document.removeEventListener("keydown",o,!1)}function u(t){var o=r(t),n=h(o,e.triggers);p(),null!==n&&f(n,o.substring(n.length),e.triggers[n])}function h(t,e){for(var o in e)if(e.hasOwnProperty(o)&&0===t.indexOf(o))return o;return null}function f(t,e,o){if("string"==typeof o){var n=new RegExp("SEARCH_TERM","g"),a=o.replace(n,e);KB.http.get(a).success(function(o){m(t,e,o)})}else m(t,e,o)}function m(t,e,o){o=v(e,o),o.length>0&&b(g(t,o))}function v(t,e){var o=[];if(0===t.length)return e;for(var n=0;n<e.length;n++)0===e[n].value.toLowerCase().indexOf(t.toLowerCase())&&o.push(e[n]);return o}function g(t,e){for(var o=[],n=0;n<e.length;n++){var a="suggest-menu-item";0===n&&(a+=" active"),o.push({"class":a,html:e[n].html,"data-value":e[n].value,"data-trigger":t})}return o}function b(e){var i=s(),r=getCaretCoordinates(t,t.selectionEnd),d=r.left+t.offsetLeft-t.scrollLeft,l=r.top+t.offsetTop-t.scrollTop+16;document.addEventListener("keydown",o,!1);var c=KB.dom("ul").attr("id","suggest-menu").click(n).mouseover(a).style("left",d+"px").style("top",l+"px")["for"]("li",e).build();i.appendChild(c)}this.render=function(){t.addEventListener("input",function(){u(this)})}}),KB.component("task-move-position",function(t,e){function o(t){var e=KB.dom(document).find("#"+t);return e?parseInt(e.options[e.selectedIndex].value):null}function n(){var t=o("form-swimlanes");return null===t?e.board[0].id:t}function a(){var t=o("form-columns");return null===t?e.board[0].columns[0].id:t}function i(){var t=o("form-position");return null===t?1:t}function r(){var t=KB.find("input[name=positionChoice]:checked");return t?t.value:"before"}function s(){var t=KB.dom(document).find("#form-columns");KB.dom(t).replace(u());var e=KB.dom(document).find("#form-tasks");KB.dom(e).replace(h())}function d(){var t=KB.dom(document).find("#form-tasks");KB.dom(t).replace(h())}function l(t){KB.trigger("modal.stop"),KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").attr("class","alert alert-error").text(t).build())}function c(){var t=i(),o=r();"after"===o&&t++,KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").build()),KB.http.postJson(e.saveUrl,{column_id:a(),swimlane_id:n(),position:t}).success(function(){window.location.reload(!0)}).error(function(t){t&&l(t.message)})}function p(){var t=[];return e.board.forEach(function(e){t.push({value:e.id,text:e.name})}),KB.dom("select").attr("id","form-swimlanes").change(s)["for"]("option",t).build()}function u(){var t=[],o=n();return e.board.forEach(function(e){o===e.id&&e.columns.forEach(function(e){t.push({value:e.id,text:e.title})})}),KB.dom("select").attr("id","form-columns").change(d)["for"]("option",t).build()}function h(){var t=[],o=n(),i=a(),r=KB.dom("div").attr("id","form-tasks");return e.board.forEach(function(e){o===e.id&&e.columns.forEach(function(e){i===e.id&&e.tasks.forEach(function(e){t.push({value:e.position,text:"#"+e.id+" - "+e.title})})})}),t.length>0&&r.add(KB.html.label(e.positionLabel,"form-position")).add(KB.dom("select").attr("id","form-position")["for"]("option",t).build()).add(KB.html.radio(e.beforeLabel,"positionChoice","before")).add(KB.html.radio(e.afterLabel,"positionChoice","after")),r.build()}this.render=function(){KB.on("modal.submit",c);var o=KB.dom("div").on("submit",c).add(KB.dom("div").attr("id","message-container").build()).add(KB.html.label(e.swimlaneLabel,"form-swimlanes")).add(p()).add(KB.html.label(e.columnLabel,"form-columns")).add(u()).add(h()).build();t.appendChild(o)}}),KB.component("text-editor",function(t,e){function o(){var t=KB.dom("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-pencil-square-o fa-fw"></i> '+e.labelWrite,click:function(){a()}}]).build();return m=KB.dom("div").attr("class","text-editor-preview-area markdown").build(),KB.dom("div").attr("class","text-editor-view-mode").add(t).add(m).hide().build()}function n(){var t=KB.dom("div").attr("class","text-editor-toolbar")["for"]("a",[{href:"#",html:'<i class="fa fa-eye fa-fw"></i> '+e.labelPreview,click:function(){a()}},{href:"#",html:'<i class="fa fa-bold fa-fw"></i>',click:function(){s("**")}},{href:"#",html:'<i class="fa fa-italic fa-fw"></i>',click:function(){s("_")}},{href:"#",html:'<i class="fa fa-strikethrough fa-fw"></i>',click:function(){s("~~")}},{href:"#",html:'<i class="fa fa-quote-right fa-fw"></i>',click:function(){l("> ")}},{href:"#",html:'<i class="fa fa-list-ul fa-fw"></i>',click:function(){l("* ")}},{href:"#",html:'<i class="fa fa-code fa-fw"></i>',click:function(){d("```")}}]).build(),o=KB.dom("textarea");return o.attr("name",e.name),e.tabindex&&o.attr("tabindex",e.tabindex),e.required&&o.attr("required","required"),o.text(e.text),e.placeholder&&o.attr("placeholder",e.placeholder),u=o.build(),e.suggestOptions&&KB.getComponent("suggest-menu",u,e.suggestOptions).render(),KB.dom("div").attr("class","text-editor-write-mode").add(t).add(u).build()}function a(){KB.dom(m).html(marked(u.value,{sanitize:!0})),KB.dom(h).toggle(),KB.dom(f).toggle()}function i(){return u.value.substring(u.selectionStart,u.selectionEnd)}function r(t,e,o,n){return t.substring(0,e)+n+t.substring(o)}function s(t){var e=i();c(t+e+t),p(t)}function d(t){var e=i();c("\n"+t+"\n"+e+"\n"+t),p(t,2)}function l(t){var e=i();if(e.indexOf("\n")===-1)c("\n"+t+e);else{for(var o=e.split("\n"),n=0;n<o.length;n++)o[n].indexOf(t)===-1&&(o[n]=t+o[n]);c(o.join("\n"))}p(t,1)}function c(t){u.focus();var e=!1,o=KB.utils.getSelectionPosition(u);if(v=o.selectionStart,g=o.selectionEnd,document.queryCommandSupported("insertText")&&(e=document.execCommand("insertText",!1,t)),!e){try{document.execCommand("ms-beginUndoUnit")}catch(n){}u.value=r(u.value,v,g,t);try{document.execCommand("ms-endUndoUnit")}catch(n){}}}function p(t,e){e=e||0;var o=g+t.length+e;u.setSelectionRange(o,o)}var u,h,f,m,v,g;this.render=function(){f=n(),h=o(),t.appendChild(KB.dom("div").attr("class","text-editor").add(h).add(f).build()),e.autofocus&&u.focus()}}),document.addEventListener("DOMContentLoaded",function(){KB.render(),KB.listen()});var Kanboard={};Kanboard.App=function(){this.controllers={}},Kanboard.App.prototype.get=function(t){return this.controllers[t]},Kanboard.App.prototype.execute=function(){for(var t in Kanboard)if("App"!==t){var e=new Kanboard[t](this);this.controllers[t]=e,"function"==typeof e.execute&&e.execute(),"function"==typeof e.listen&&e.listen(),"function"==typeof e.focus&&e.focus(),"function"==typeof e.keyboardShortcuts&&e.keyboardShortcuts()}this.focus(),this.keyboardShortcuts(),this.datePicker(),this.autoComplete(),this.tagAutoComplete()},Kanboard.App.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bindGlobal("mod+enter",function(){var e=$("form");1==e.length?e.submit():e.length>1&&("INPUT"===document.activeElement.tagName||"TEXTAREA"===document.activeElement.tagName?$(document.activeElement).parents("form").submit():t.get("Popover").isOpen()&&$("#popover-container form").submit())}),Mousetrap.bindGlobal("esc",function(){document.getElementById("suggest-menu")||(t.get("Popover").close(),t.get("Dropdown").close())}),Mousetrap.bind("?",function(){t.get("Popover").open($("body").data("keyboard-shortcut-url"))})},Kanboard.App.prototype.focus=function(){$(document).on("focus",".auto-select",function(){$(this).select()}),$(document).on("mouseup",".auto-select",function(t){t.preventDefault()})},Kanboard.App.prototype.datePicker=function(){var t=$("body"),e=t.data("js-date-format"),o=t.data("js-time-format"),n=t.data("js-lang");$.datepicker.setDefaults($.datepicker.regional[n]),$.timepicker.setDefaults($.timepicker.regional[n]),$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:e,constrainInput:!1}),$(".form-datetime").datetimepicker({dateFormat:e,timeFormat:o,constrainInput:!1})},Kanboard.App.prototype.tagAutoComplete=function(){$(".tag-autocomplete").select2({tags:!0})},Kanboard.App.prototype.autoComplete=function(){$(".autocomplete").each(function(){var t=$(this),e=t.data("dst-field"),o=t.data("dst-extra-field");""===$("#form-"+e).val()&&t.parent().find("button[type=submit]").attr("disabled","disabled"),t.autocomplete({source:t.data("search-url"),minLength:1,select:function(n,a){$("input[name="+e+"]").val(a.item.id),o&&$("input[name="+o+"]").val(a.item[o]),t.parent().find("button[type=submit]").removeAttr("disabled")}})})},Kanboard.App.prototype.hasId=function(t){return!!document.getElementById(t)},Kanboard.App.prototype.showLoadingIcon=function(){$("body").append('<span id="app-loading-icon">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>')},Kanboard.App.prototype.hideLoadingIcon=function(){$("#app-loading-icon").remove()},Kanboard.App.prototype.isVisible=function(){var t="";return"undefined"!=typeof document.hidden?t="visibilityState":"undefined"!=typeof document.mozHidden?t="mozVisibilityState":"undefined"!=typeof document.msHidden?t="msVisibilityState":"undefined"!=typeof document.webkitHidden&&(t="webkitVisibilityState"),""===t||"visible"==document[t]},Kanboard.BoardCollapsedMode=function(t){this.app=t},Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("s",function(){t.toggle()})},Kanboard.BoardCollapsedMode.prototype.toggle=function(){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$('.filter-display-mode:not([style="display: none;"]) a').attr("href"),success:function(e){$(".filter-display-mode").toggle(),t.app.get("BoardDragAndDrop").refresh(e)}})},Kanboard.BoardColumnView=function(t){this.app=t},Kanboard.BoardColumnView.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardColumnView.prototype.listen=function(){var t=this;$(document).on("click",".board-toggle-column-view",function(){t.toggle($(this).data("column-id"))})},Kanboard.BoardColumnView.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnView.prototype.render=function(){var t=this;$(".board-column-header").each(function(){var e=$(this).data("column-id");localStorage.getItem("hidden_column_"+e)&&t.hideColumn(e)})},Kanboard.BoardColumnView.prototype.toggle=function(t){localStorage.getItem("hidden_column_"+t)?this.showColumn(t):this.hideColumn(t)},Kanboard.BoardColumnView.prototype.hideColumn=function(t){$(".board-column-"+t+" .board-column-expanded").hide(),$(".board-column-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t+" .board-column-expanded").hide(),$(".board-column-header-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t).each(function(){$(this).removeClass("board-column-compact"),$(this).addClass("board-column-header-collapsed")}),$(".board-column-"+t).each(function(){$(this).addClass("board-column-task-collapsed")}),$(".board-column-"+t+" .board-rotation").each(function(){$(this).css("width",$(".board-column-"+t).height())}),localStorage.setItem("hidden_column_"+t,1)},Kanboard.BoardColumnView.prototype.showColumn=function(t){$(".board-column-"+t+" .board-column-expanded").show(),$(".board-column-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t+" .board-column-expanded").show(),$(".board-column-header-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t).removeClass("board-column-header-collapsed"),$(".board-column-"+t).removeClass("board-column-task-collapsed"),0==localStorage.getItem("horizontal_scroll")&&$(".board-column-header-"+t).addClass("board-column-compact"),localStorage.removeItem("hidden_column_"+t)},Kanboard.BoardHorizontalScrolling=function(t){this.app=t},Kanboard.BoardHorizontalScrolling.prototype.execute=function(){this.app.hasId("board")&&this.render();
-},Kanboard.BoardHorizontalScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-scrolling",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("c",function(){t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardHorizontalScrolling.prototype.toggle=function(){var t=localStorage.getItem("horizontal_scroll")||1;localStorage.setItem("horizontal_scroll",0==t?1:0),this.render()},Kanboard.BoardHorizontalScrolling.prototype.render=function(){0==localStorage.getItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))},Kanboard.BoardPolling=function(t){this.app=t},Kanboard.BoardPolling.prototype.execute=function(){if(this.app.hasId("board")){var t=parseInt($("#board").attr("data-check-interval"));t>0&&window.setInterval(this.check.bind(this),1e3*t)}},Kanboard.BoardPolling.prototype.check=function(){if(this.app.isVisible()&&!this.app.get("BoardDragAndDrop").savingInProgress){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$("#board").data("check-url"),statusCode:{200:function(e){t.app.get("BoardDragAndDrop").refresh(e)},304:function(){t.app.hideLoadingIcon()}}})}},Kanboard.BoardTask=function(t){this.app=t},Kanboard.BoardTask.prototype.listen=function(){var t=this;$(document).on("click",".task-board-change-assignee",function(e){e.preventDefault(),e.stopPropagation(),t.app.get("Popover").open($(this).data("url"))}),$(document).on("click",".task-board",function(t){"A"!=t.target.tagName&&"IMG"!=t.target.tagName&&(window.location=$(this).data("task-url"))})},Kanboard.BoardTask.prototype.keyboardShortcuts=function(){var t=this;t.app.hasId("board")&&Mousetrap.bind("n",function(){t.app.get("Popover").open($("#board").data("task-creation-url"))})},Kanboard.Column=function(t){this.app=t},Kanboard.Column.prototype.listen=function(){this.dragAndDrop()},Kanboard.Column.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".columns-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("column-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Column.prototype.savePosition=function(t,e){var o=$(".columns-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Dropdown=function(t){this.app=t},Kanboard.Dropdown.prototype.listen=function(){var t=this;$(document).on("click",function(){t.close()}),$(document).on("click","#popover-content",function(){t.close()}),$(document).on("click",".dropdown-menu",function(e){e.preventDefault(),e.stopImmediatePropagation(),t.close();var o=$(this).next("ul"),n=$(this).offset();$("body").append(jQuery("<div>",{id:"dropdown"})),o.clone().appendTo("#dropdown");var a=$("#dropdown ul");a.addClass("dropdown-submenu-open");var i=a.outerHeight(),r=a.outerWidth();n.top+i-$(window).scrollTop()<$(window).height()||$(window).scrollTop()+n.top<i?a.css("top",n.top+$(this).height()):a.css("top",n.top-i-5),n.left+r>$(window).width()?a.css("left",n.left-r+$(this).outerWidth()):a.css("left",n.left)}),$(document).on("click",".dropdown-submenu-open li",function(t){$(t.target).is("li")&&$(this).find("a:visible")[0].click()})},Kanboard.Dropdown.prototype.close=function(){$("#dropdown").remove()},Kanboard.Dropdown.prototype.onPopoverOpened=function(){this.close()},Kanboard.FileUpload=function(t){this.app=t,this.files=[],this.currentFile=0},Kanboard.FileUpload.prototype.onPopoverOpened=function(){var t=document.getElementById("file-dropzone"),e=this;t&&(t.ondragover=t.ondragenter=function(t){t.stopPropagation(),t.preventDefault()},t.ondrop=function(t){t.stopPropagation(),t.preventDefault(),e.files=t.dataTransfer.files,e.show(),$("#file-error-max-size").hide()},$(document).on("click","#file-browser",function(t){t.preventDefault(),$("#file-form-element").get(0).click()}),$(document).on("click","#file-upload-button",function(t){t.preventDefault(),e.currentFile=0,e.checkFiles()}),$("#file-form-element").change(function(){e.files=document.getElementById("file-form-element").files,e.show(),$("#file-error-max-size").hide()}))},Kanboard.FileUpload.prototype.show=function(){if($("#file-list").remove(),this.files.length>0){$("#file-upload-button").prop("disabled",!1),$("#file-dropzone-inner").hide();for(var t=jQuery("<ul>",{id:"file-list"}),e=0;e<this.files.length;e++){var o=jQuery("<span>",{id:"file-percentage-"+e}).append("(0%)"),n=jQuery("<progress>",{id:"file-progress-"+e,value:0}),a=jQuery("<li>",{id:"file-label-"+e}).append(n).append("&nbsp;").append(this.files[e].name).append("&nbsp;").append(o);t.append(a)}$("#file-dropzone").append(t)}else $("#file-dropzone-inner").show()},Kanboard.FileUpload.prototype.checkFiles=function(){for(var t=parseInt($("#file-dropzone").data("max-size")),e=0;e<this.files.length;e++)if(this.files[e].size>t)return $("#file-error-max-size").show(),$("#file-label-"+e).addClass("file-error"),void $("#file-upload-button").prop("disabled",!0);this.uploadFiles()},Kanboard.FileUpload.prototype.uploadFiles=function(){this.files.length>0&&this.uploadFile(this.files[this.currentFile])},Kanboard.FileUpload.prototype.uploadFile=function(t){var e=document.getElementById("file-dropzone"),o=e.dataset.url,n=new XMLHttpRequest,a=new FormData;n.upload.addEventListener("progress",this.updateProgress.bind(this)),n.upload.addEventListener("load",this.transferComplete.bind(this)),n.open("POST",o,!0),a.append("files[]",t),n.send(a)},Kanboard.FileUpload.prototype.updateProgress=function(t){t.lengthComputable&&($("#file-progress-"+this.currentFile).val(t.loaded/t.total),$("#file-percentage-"+this.currentFile).text("("+Math.floor(t.loaded/t.total*100)+"%)"))},Kanboard.FileUpload.prototype.transferComplete=function(){if(this.currentFile++,this.currentFile<this.files.length)this.uploadFile(this.files[this.currentFile]);else{var t=$("#file-upload-button");t.prop("disabled",!0),t.parent().hide(),$("#file-done").show()}},Kanboard.Gantt=function(t){this.app=t,this.data=[],this.options={container:"#gantt-chart",showWeekends:!0,allowMoves:!0,allowResizes:!0,cellWidth:21,cellHeight:31,slideWidth:1e3,vHeaderWidth:200}},Kanboard.Gantt.prototype.execute=function(){this.app.hasId("gantt-chart")&&this.show()},Kanboard.Gantt.prototype.saveRecord=function(t){this.app.showLoadingIcon(),$.ajax({cache:!1,url:$(this.options.container).data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify(t),complete:this.app.hideLoadingIcon.bind(this)})},Kanboard.Gantt.prototype.show=function(){this.data=this.prepareData($(this.options.container).data("records"));var t=Math.floor(this.options.slideWidth/this.options.cellWidth+5),e=this.getDateRange(t),o=e[0],n=e[1],a=$(this.options.container),i=jQuery("<div>",{"class":"ganttview"});i.append(this.renderVerticalHeader()),i.append(this.renderSlider(o,n)),a.append(i),jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child",a).addClass("last"),$(this.options.container).data("readonly")?(this.options.allowResizes=!1,this.options.allowMoves=!1):(this.listenForBlockResize(o),this.listenForBlockMove(o))},Kanboard.Gantt.prototype.renderVerticalHeader=function(){for(var t=jQuery("<div>",{"class":"ganttview-vtheader"}),e=jQuery("<div>",{"class":"ganttview-vtheader-item"}),o=jQuery("<div>",{"class":"ganttview-vtheader-series"}),n=0;n<this.data.length;n++){var a=jQuery("<span>").append(jQuery("<i>",{"class":"fa fa-info-circle tooltip",title:this.getVerticalHeaderTooltip(this.data[n])})).append("&nbsp;");"task"==this.data[n].type?a.append(jQuery("<a>",{href:this.data[n].link,title:this.data[n].title}).append(this.data[n].title)):a.append(jQuery("<a>",{href:this.data[n].board_link,title:$(this.options.container).data("label-board-link")}).append('<i class="fa fa-th"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[n].gantt_link,title:$(this.options.container).data("label-gantt-link")}).append('<i class="fa fa-sliders"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[n].link}).append(this.data[n].title)),o.append(jQuery("<div>",{"class":"ganttview-vtheader-series-name"}).append(a))}return e.append(o),t.append(e),t},Kanboard.Gantt.prototype.renderSlider=function(t,e){var o=jQuery("<div>",{"class":"ganttview-slide-container"}),n=this.getDates(t,e);return o.append(this.renderHorizontalHeader(n)),o.append(this.renderGrid(n)),o.append(this.addBlockContainers()),this.addBlocks(o,t),o},Kanboard.Gantt.prototype.renderHorizontalHeader=function(t){var e=jQuery("<div>",{"class":"ganttview-hzheader"}),o=jQuery("<div>",{"class":"ganttview-hzheader-months"}),n=jQuery("<div>",{"class":"ganttview-hzheader-days"}),a=0;for(var i in t)for(var r in t[i]){var s=t[i][r].length*this.options.cellWidth;a+=s,o.append(jQuery("<div>",{"class":"ganttview-hzheader-month",css:{width:s-1+"px"}}).append($.datepicker.regional[$("body").data("js-lang")].monthNames[r]+" "+i));for(var d in t[i][r])n.append(jQuery("<div>",{"class":"ganttview-hzheader-day"}).append(t[i][r][d].getDate()))}return o.css("width",a+"px"),n.css("width",a+"px"),e.append(o).append(n),e},Kanboard.Gantt.prototype.renderGrid=function(t){var e=jQuery("<div>",{"class":"ganttview-grid"}),o=jQuery("<div>",{"class":"ganttview-grid-row"});for(var n in t)for(var a in t[n])for(var i in t[n][a]){var r=jQuery("<div>",{"class":"ganttview-grid-row-cell"});this.options.showWeekends&&this.isWeekend(t[n][a][i])&&r.addClass("ganttview-weekend"),o.append(r)}var s=jQuery("div.ganttview-grid-row-cell",o).length*this.options.cellWidth;o.css("width",s+"px"),e.css("width",s+"px");for(var d=0;d<this.data.length;d++)e.append(o.clone());return e},Kanboard.Gantt.prototype.addBlockContainers=function(){for(var t=jQuery("<div>",{"class":"ganttview-blocks"}),e=0;e<this.data.length;e++)t.append(jQuery("<div>",{"class":"ganttview-block-container"}));return t},Kanboard.Gantt.prototype.addBlocks=function(t,e){for(var o=jQuery("div.ganttview-blocks div.ganttview-block-container",t),n=0,a=0;a<this.data.length;a++){var i=this.data[a],r=this.daysBetween(i.start,i.end)+1,s=this.daysBetween(e,i.start),d=jQuery("<div>",{"class":"ganttview-block-text"}),l=jQuery("<div>",{"class":"ganttview-block tooltip"+(this.options.allowMoves?" ganttview-block-movable":""),title:this.getBarTooltip(i),css:{width:r*this.options.cellWidth-9+"px","margin-left":s*this.options.cellWidth+"px"}}).append(d);r>=2&&d.append(i.progress),l.data("record",i),this.setBarColor(l,i),jQuery(o[n]).append(l),n+=1}},Kanboard.Gantt.prototype.getVerticalHeaderTooltip=function(t){var e="";if("task"==t.type)e="<strong>"+t.column_title+"</strong> ("+t.progress+")<br/>"+t.title;else{var o=["project-manager","project-member"];for(var n in o){var a=o[n];if(!jQuery.isEmptyObject(t.users[a])){var i=jQuery("<ul>");for(var r in t.users[a])r&&i.append(jQuery("<li>").append(t.users[a][r]));e+="<p><strong>"+$(this.options.container).data("label-"+a)+"</strong></p>"+i[0].outerHTML}}}return e},Kanboard.Gantt.prototype.getBarTooltip=function(t){var e="";return t.not_defined?e=$(this.options.container).data("label-not-defined"):("task"==t.type&&(e="<strong>"+t.progress+"</strong><br/>"+$(this.options.container).data("label-assignee")+" "+(t.assignee?t.assignee:"")+"<br/>"),e+=$(this.options.container).data("label-start-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.start)+"<br/>",e+=$(this.options.container).data("label-end-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.end)),e},Kanboard.Gantt.prototype.setBarColor=function(t,e){e.not_defined?t.addClass("ganttview-block-not-defined"):(t.css("background-color",e.color.background),t.css("border-color",e.color.border),"0%"!=e.progress&&t.append(jQuery("<div>",{css:{"z-index":0,position:"absolute",top:0,bottom:0,"background-color":e.color.border,width:e.progress,opacity:.4}})))},Kanboard.Gantt.prototype.listenForBlockResize=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).resizable({grid:this.options.cellWidth,handles:"e,w",delay:300,stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.listenForBlockMove=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).draggable({axis:"x",delay:300,grid:[this.options.cellWidth,this.options.cellWidth],stop:function(){var o=jQuery(this);e.updateDataAndPosition(o,t),e.saveRecord(o.data("record"))}})},Kanboard.Gantt.prototype.updateDataAndPosition=function(t,e){var o=jQuery("div.ganttview-slide-container",this.options.container),n=o.scrollLeft(),a=t.offset().left-o.offset().left-1+n,i=t.data("record");i.not_defined=!1,this.setBarColor(t,i);var r=Math.round(a/this.options.cellWidth),s=this.addDays(this.cloneDate(e),r);i.start=s;var d=t.outerWidth(),l=Math.round(d/this.options.cellWidth)-1;i.end=this.addDays(this.cloneDate(s),l),"task"===i.type&&l>0&&jQuery("div.ganttview-block-text",t).text(i.progress),t.attr("title",this.getBarTooltip(i)),t.data("record",i),t.css("top","").css("left","").css("position","relative").css("margin-left",a+"px")},Kanboard.Gantt.prototype.getDates=function(t,e){var o=[];o[t.getFullYear()]=[],o[t.getFullYear()][t.getMonth()]=[t];for(var n=t;this.compareDate(n,e)==-1;){var a=this.addDays(this.cloneDate(n),1);o[a.getFullYear()]||(o[a.getFullYear()]=[]),o[a.getFullYear()][a.getMonth()]||(o[a.getFullYear()][a.getMonth()]=[]),o[a.getFullYear()][a.getMonth()].push(a),n=a}return o},Kanboard.Gantt.prototype.prepareData=function(t){for(var e=0;e<t.length;e++){var o=new Date(t[e].start[0],t[e].start[1]-1,t[e].start[2],0,0,0,0);t[e].start=o;var n=new Date(t[e].end[0],t[e].end[1]-1,t[e].end[2],0,0,0,0);t[e].end=n}return t},Kanboard.Gantt.prototype.getDateRange=function(t){for(var e=new Date,o=new Date,n=0;n<this.data.length;n++){var a=new Date;a.setTime(Date.parse(this.data[n].start));var i=new Date;i.setTime(Date.parse(this.data[n].end)),0==n&&(e=a,o=i),1==this.compareDate(e,a)&&(e=a),this.compareDate(o,i)==-1&&(o=i)}return this.daysBetween(e,o)<t&&(o=this.addDays(this.cloneDate(e),t)),e.setDate(e.getDate()-1),[e,o]},Kanboard.Gantt.prototype.daysBetween=function(t,e){if(!t||!e)return 0;for(var o=0,n=this.cloneDate(t);this.compareDate(n,e)==-1;)o+=1,this.addDays(n,1);return o},Kanboard.Gantt.prototype.isWeekend=function(t){return t.getDay()%6==0},Kanboard.Gantt.prototype.cloneDate=function(t){return new Date(t.getTime())},Kanboard.Gantt.prototype.addDays=function(t,e){return t.setDate(t.getDate()+1*e),t},Kanboard.Gantt.prototype.compareDate=function(t,e){if(isNaN(t)||isNaN(e))throw new Error(t+" - "+e);if(t instanceof Date&&e instanceof Date)return t<e?-1:t>e?1:0;throw new TypeError(t+" - "+e)},Kanboard.Popover=function(t){this.app=t},Kanboard.Popover.prototype.listen=function(){var t=this;$(document).on("click",".popover",function(e){t.onClick(e)}),$(document).on("click",".close-popover",function(e){t.close(e)}),$(document).on("click","#popover-close-button",function(e){t.close(e)}),$(document).on("click","#popover-content",function(t){t.stopPropagation()})},Kanboard.Popover.prototype.onClick=function(t){t.preventDefault(),t.stopPropagation();var e=t.currentTarget||t.target,o=e.getAttribute("href");o||(o=e.getAttribute("data-href")),o&&this.open(o)},Kanboard.Popover.prototype.isOpen=function(){return $("#popover-container").size()>0},Kanboard.Popover.prototype.open=function(t){var e=this;e.isOpen()||$.get(t,function(t){$("body").prepend('<div id="popover-container"><div id="popover-content"><div id="popover-content-header"><a href="#" id="popover-close-button"><i class="fa fa-times"></i></a></div>'+t+"</div></div>"),e.executeOnOpenedListeners()})},Kanboard.Popover.prototype.close=function(t){this.isOpen()&&(t&&t.preventDefault(),$("#popover-container").remove(),this.executeOnClosedListeners())},Kanboard.Popover.prototype.ajaxReload=function(t,e,o){var n=e.getResponseHeader("X-Ajax-Redirect");"self"===n?window.location.reload():n&&n.indexOf("#")>-1?window.location=n.split("#")[0]:n?window.location=n:($("#popover-content").html(t),$("#popover-content input[autofocus]").focus(),o.executeOnOpenedListeners())},Kanboard.Popover.prototype.executeOnOpenedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverOpened&&e.onPopoverOpened()}this.afterOpen()},Kanboard.Popover.prototype.executeOnClosedListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onPopoverClosed&&e.onPopoverClosed()}},Kanboard.Popover.prototype.afterOpen=function(){var t=this,e=$("#popover-content .popover-form");e&&e.on("submit",function(o){o.preventDefault(),$.ajax({type:"POST",url:e.attr("action"),data:e.serialize(),success:function(e,o,n){t.ajaxReload(e,n,t)},beforeSend:function(){var t=$('.popover-form button[type="submit"]');t.html('<i class="fa fa-spinner fa-pulse"></i> '+t.html()),t.attr("disabled",!0)}})}),$(document).on("click",".popover-link",function(e){e.preventDefault(),$.ajax({type:"GET",url:$(this).attr("href"),success:function(e,o,n){t.ajaxReload(e,n,t)}})}),$("#popover-content input[autofocus]").each(function(){$(this).focus()}),this.app.datePicker(),this.app.autoComplete(),this.app.tagAutoComplete(),KB.render()},Kanboard.Screenshot=function(t){this.app=t,this.pasteCatcher=null},Kanboard.Screenshot.prototype.onPopoverOpened=function(){this.app.hasId("screenshot-zone")&&this.initialize()},Kanboard.Screenshot.prototype.initialize=function(){this.destroy(),window.Clipboard||(this.pasteCatcher=document.createElement("div"),this.pasteCatcher.id="screenshot-pastezone",this.pasteCatcher.contentEditable="true",this.pasteCatcher.style.opacity=0,this.pasteCatcher.style.position="fixed",this.pasteCatcher.style.top=0,this.pasteCatcher.style.right=0,this.pasteCatcher.style.width=0,document.body.insertBefore(this.pasteCatcher,document.body.firstChild),this.pasteCatcher.focus(),document.addEventListener("click",this.setFocus.bind(this)),document.getElementById("screenshot-zone").addEventListener("click",this.setFocus.bind(this))),window.addEventListener("paste",this.pasteHandler.bind(this))},Kanboard.Screenshot.prototype.destroy=function(){null!==this.pasteCatcher?document.body.removeChild(this.pasteCatcher):document.getElementById("screenshot-pastezone")&&document.body.removeChild(document.getElementById("screenshot-pastezone")),document.removeEventListener("click",this.setFocus.bind(this)),this.pasteCatcher=null},Kanboard.Screenshot.prototype.setFocus=function(){null!==this.pasteCatcher&&this.pasteCatcher.focus()},Kanboard.Screenshot.prototype.pasteHandler=function(t){if(t.clipboardData&&t.clipboardData.items){var e=t.clipboardData.items;if(e)for(var o=0;o<e.length;o++)if(e[o].type.indexOf("image")!==-1){var n=e[o].getAsFile(),a=new FileReader,i=this;a.onload=function(t){i.createImage(t.target.result)},a.readAsDataURL(n)}}else setTimeout(this.checkInput.bind(this),100)},Kanboard.Screenshot.prototype.checkInput=function(){var t=this.pasteCatcher.childNodes[0];t&&"IMG"===t.tagName&&this.createImage(t.src),this.pasteCatcher.innerHTML=""},Kanboard.Screenshot.prototype.createImage=function(t){var e=new Image;e.src=t,e.onload=function(){var e=t.split("base64,"),o=e[1];$("input[name=screenshot]").val(o)};var o=document.getElementById("screenshot-zone");o.innerHTML="",o.className="screenshot-pasted",o.appendChild(e),this.destroy(),this.initialize()},Kanboard.Search=function(t){this.app=t},Kanboard.Search.prototype.focus=function(){$(document).on("focus","#form-search",function(){var t=$("#form-search");if(t[0].setSelectionRange){var e=2*t.val().length;t[0].setSelectionRange(e,e)}})},Kanboard.Search.prototype.listen=function(){$(document).on("click",".filter-helper",function(t){t.preventDefault();var e=$(this).data("filter"),o=$(this).data("append-filter"),n=$(this).data("unique-filter"),a=$("#form-search");if(n){var i=n.substr(0,n.indexOf(":"));e=a.val().replace(new RegExp("("+i+":[#a-z0-9]+)","g"),""),e=e.replace(new RegExp("("+i+':"(.+)")',"g"),""),e=e.trim(),e+=" "+n}else o&&(e=a.val()+" "+o);a.val(e),$("form.search").submit()})},Kanboard.Search.prototype.goToView=function(t){var e=$(t);e.length&&(window.location=e.attr("href"))},Kanboard.Search.prototype.keyboardShortcuts=function(){var t=this;Mousetrap.bind("v o",function(){t.goToView(".view-overview")}),Mousetrap.bind("v b",function(){t.goToView(".view-board")}),Mousetrap.bind("v c",function(){t.goToView(".view-calendar")}),Mousetrap.bind("v l",function(){t.goToView(".view-listing")}),Mousetrap.bind("v g",function(){t.goToView(".view-gantt")}),Mousetrap.bind("f",function(t){t.preventDefault();var e=document.getElementById("form-search");e&&e.focus()}),Mousetrap.bind("r",function(t){t.preventDefault();var e=$(".filter-reset").data("filter"),o=$("#form-search");o.val(e),$("form.search").submit()})},Kanboard.Subtask=function(t){this.app=t},Kanboard.Subtask.prototype.listen=function(){var t=this;this.dragAndDrop(),$(document).on("click",".subtask-toggle-status",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){o.hasClass("subtask-refresh-table")?$(".subtasks-table").replaceWith(e):o.replaceWith(e),t.dragAndDrop()}})}),$(document).on("click",".subtask-toggle-timer",function(e){var o=$(this);e.preventDefault(),$.ajax({cache:!1,url:o.attr("href"),success:function(e){$(".subtasks-table").replaceWith(e),t.dragAndDrop()}})})},Kanboard.Subtask.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".subtasks-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("subtask-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Subtask.prototype.savePosition=function(t,e){var o=$(".subtasks-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({subtask_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Swimlane=function(t){this.app=t},Kanboard.Swimlane.prototype.execute=function(){$(".swimlanes-table").length&&this.dragAndDrop()},Kanboard.Swimlane.prototype.listen=function(){var t=this;$(document).on("click",".board-swimlane-toggle",function(e){e.preventDefault();var o=$(this).data("swimlane-id");t.isCollapsed(o)?t.expand(o):t.collapse(o)})},Kanboard.Swimlane.prototype.onBoardRendered=function(){for(var t=this.getAllCollapsed(),e=0;e<t.length;e++)this.collapse(t[e])},Kanboard.Swimlane.prototype.getStorageKey=function(){return"hidden_swimlanes_"+$("#board").data("project-id")},Kanboard.Swimlane.prototype.expand=function(t){var e=this.getAllCollapsed(),o=e.indexOf(t);o>-1&&e.splice(o,1),localStorage.setItem(this.getStorageKey(),JSON.stringify(e)),$(".board-swimlane-columns-"+t).css("display","table-row"),$(".board-swimlane-tasks-"+t).css("display","table-row"),$(".hide-icon-swimlane-"+t).css("display","inline"),$(".show-icon-swimlane-"+t).css("display","none")},Kanboard.Swimlane.prototype.collapse=function(t){var e=this.getAllCollapsed();e.indexOf(t)<0&&(e.push(t),localStorage.setItem(this.getStorageKey(),JSON.stringify(e))),$(".board-swimlane-columns-"+t+":not(:first-child)").css("display","none"),$(".board-swimlane-tasks-"+t).css("display","none"),$(".hide-icon-swimlane-"+t).css("display","none"),$(".show-icon-swimlane-"+t).css("display","inline")},Kanboard.Swimlane.prototype.isCollapsed=function(t){return this.getAllCollapsed().indexOf(t)>-1},Kanboard.Swimlane.prototype.getAllCollapsed=function(){return JSON.parse(localStorage.getItem(this.getStorageKey()))||[]},Kanboard.Swimlane.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".swimlanes-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,o){var n=o.item;n.removeClass("draggable-item-selected"),t.savePosition(n.data("swimlane-id"),n.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Swimlane.prototype.savePosition=function(t,e){var o=$(".swimlanes-table").data("save-position-url"),n=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:o,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({swimlane_id:t,position:e}),complete:function(){n.app.hideLoadingIcon()}})},Kanboard.Task=function(t){this.app=t},Kanboard.Task.prototype.keyboardShortcuts=function(){var t=$("#task-view"),e=this;this.app.hasId("task-view")&&(Mousetrap.bind("e",function(){e.app.get("Popover").open(t.data("edit-url"))}),Mousetrap.bind("c",function(){e.app.get("Popover").open(t.data("comment-url"))}),Mousetrap.bind("s",function(){e.app.get("Popover").open(t.data("subtask-url"))}),Mousetrap.bind("l",function(){e.app.get("Popover").open(t.data("internal-link-url"))}))},Kanboard.Task.prototype.onPopoverOpened=function(){var t=this,e=0;t.renderColorPicker(),$(document).on("click",".assign-me",function(t){var e=$(this).data("current-id"),o="#"+$(this).data("target-id");t.preventDefault(),$(o+" option[value="+e+"]").length&&$(o).val(e)}),$(document).on("change","select.task-reload-project-destination",function(){if(e>0)$(this).val(e);else{e=$(this).val();var o=$(this).data("redirect").replace(/PROJECT_ID/g,e);$(".loading-icon").show(),$.ajax({type:"GET",url:o,success:function(o,n,a){e=0,$(".loading-icon").hide(),t.app.get("Popover").ajaxReload(o,a,t.app.get("Popover"))}})}})},Kanboard.Task.prototype.renderColorPicker=function(){function t(t){return $('<div class="color-picker-option"><div class="color-picker-square color-'+t.id+'"></div><div class="color-picker-label">'+t.text+"</div></div>")}$(".color-picker").select2({minimumResultsForSearch:1/0,templateResult:t,templateSelection:t})},Kanboard.Tooltip=function(t){this.app=t},Kanboard.Tooltip.prototype.onBoardRendered=function(){this.execute()},Kanboard.Tooltip.prototype.execute=function(){$(".tooltip").tooltip({track:!1,show:!1,hide:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(t,e){$(this).css(t);var o=e.target.left+e.target.width/2-e.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(e.vertical).addClass(o<1?"align-left":"align-right").appendTo(this)}},content:function(){var t=this,e=$(this).attr("data-href");return e?($.get(e,function(e){var o=$(".ui-tooltip:visible");$(".ui-tooltip-content:visible").html(e),o.css({top:"",left:""}),o.children(".tooltip-arrow").remove();var n=$(t).tooltip("option","position");n.of=$(t),o.position(n)}),'<i class="fa fa-spinner fa-spin"></i>'):'<div class="markdown">'+$(this).attr("title")+"</div>"}}).on("mouseenter",function(){var t=this;$(this).tooltip("open"),$(".ui-tooltip").on("mouseleave",function(){$(t).tooltip("close")})}).on("mouseleave focusout",function(t){t.stopImmediatePropagation();var e=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(e).tooltip("close")},100)})},Kanboard.BoardDragAndDrop=function(t){this.app=t,this.savingInProgress=!1},Kanboard.BoardDragAndDrop.prototype.execute=function(){this.app.hasId("board")&&(this.dragAndDrop(),this.executeListeners())},Kanboard.BoardDragAndDrop.prototype.dragAndDrop=function(){var t=this,e=$(".board-task-list"),o={forcePlaceholderSize:!0,tolerance:"pointer",connectWith:".sortable-column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(e,o){var n=o.item,a=n.attr("data-task-id"),i=n.attr("data-position"),r=n.attr("data-column-id"),s=n.attr("data-swimlane-id"),d=n.parent().attr("data-column-id"),l=n.parent().attr("data-swimlane-id"),c=n.index()+1;n.removeClass("draggable-item-selected"),d==r&&l==s&&c==i||(t.changeTaskState(a),t.save(a,r,d,c,l))},start:function(t,e){e.item.addClass("draggable-item-selected"),e.placeholder.height(e.item.height())}};isMobile.any&&($(".task-board-sort-handle").css("display","inline"),o.handle=".task-board-sort-handle"),e.each(function(){$(this).css("min-height",$(this).parent().height())}),e.sortable(o)},Kanboard.BoardDragAndDrop.prototype.changeTaskState=function(t){var e=$("div[data-task-id="+t+"]");e.addClass("task-board-saving-state"),e.find(".task-board-saving-icon").show()},Kanboard.BoardDragAndDrop.prototype.save=function(t,e,o,n,a){var i=this;i.app.showLoadingIcon(),i.savingInProgress=!0,$.ajax({cache:!1,url:$("#board").data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t,src_column_id:e,dst_column_id:o,swimlane_id:a,position:n}),success:function(t){i.refresh(t),i.savingInProgress=!1},error:function(){i.app.hideLoadingIcon(),i.savingInProgress=!1},statusCode:{403:function(t){window.alert(t.responseJSON.message),document.location.reload(!0)}}})},Kanboard.BoardDragAndDrop.prototype.refresh=function(t){$("#board-container").replaceWith(t),this.app.hideLoadingIcon(),this.dragAndDrop(),this.executeListeners()},Kanboard.BoardDragAndDrop.prototype.executeListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onBoardRendered&&e.onBoardRendered()}};var _KB=null;jQuery(document).ready(function(){_KB=new Kanboard.App,_KB.execute()}); \ No newline at end of file
+!function(){function t(t,a,i){if(!n)throw new Error("textarea-caret-position#getCaretCoordinates should only be called in a browser");var r=i&&i.debug||!1;if(r){var d=document.querySelector("#input-textarea-caret-position-mirror-div");d&&d.parentNode.removeChild(d)}var s=document.createElement("div");s.id="input-textarea-caret-position-mirror-div",document.body.appendChild(s);var l=s.style,c=window.getComputedStyle?getComputedStyle(t):t.currentStyle;l.whiteSpace="pre-wrap","INPUT"!==t.nodeName&&(l.wordWrap="break-word"),l.position="absolute",r||(l.visibility="hidden"),e.forEach(function(t){l[t]=c[t]}),o?t.scrollHeight>parseInt(c.height)&&(l.overflowY="scroll"):l.overflow="hidden",s.textContent=t.value.substring(0,a),"INPUT"===t.nodeName&&(s.textContent=s.textContent.replace(/\s/g," "));var u=document.createElement("span");u.textContent=t.value.substring(a)||".",s.appendChild(u);var p={top:u.offsetTop+parseInt(c.borderTopWidth),left:u.offsetLeft+parseInt(c.borderLeftWidth)};return r?u.style.backgroundColor="#aaa":document.body.removeChild(s),p}var e=["direction","boxSizing","width","height","overflowX","overflowY","borderTopWidth","borderRightWidth","borderBottomWidth","borderLeftWidth","borderStyle","paddingTop","paddingRight","paddingBottom","paddingLeft","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontSizeAdjust","lineHeight","fontFamily","textAlign","textTransform","textIndent","textDecoration","letterSpacing","wordSpacing","tabSize","MozTabSize"],n="undefined"!=typeof window,o=n&&null!=window.mozInnerScreenX;"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=t:n&&(window.getCaretCoordinates=t)}(),function(){function t(){if(!("KeyboardEvent"in window)||"key"in KeyboardEvent.prototype)return!1;var t={get:function(t){var e=n.keys[this.which||this.keyCode];return Array.isArray(e)&&(e=e[+this.shiftKey]),e}};return Object.defineProperty(KeyboardEvent.prototype,"key",t),t}var e,n={polyfill:t,keys:{3:"Cancel",6:"Help",8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",28:"Convert",29:"NonConvert",30:"Accept",31:"ModeChange",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",41:"Select",42:"Print",43:"Execute",44:"PrintScreen",45:"Insert",46:"Delete",48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],91:"OS",93:"ContextMenu",144:"NumLock",145:"ScrollLock",181:"VolumeMute",182:"VolumeDown",183:"VolumeUp",186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"'],224:"Meta",225:"AltGraph",246:"Attn",247:"CrSel",248:"ExSel",249:"EraseEof",250:"Play",251:"ZoomOut"}};for(e=1;e<25;e++)n.keys[111+e]="F"+e;var o="";for(e=65;e<91;e++)o=String.fromCharCode(e),n.keys[e]=[o.toLowerCase(),o.toUpperCase()];n.polyfill()}(),Element.prototype.matches||(Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector||function(t){for(var e=(this.document||this.ownerDocument).querySelectorAll(t),n=e.length;--n>=0&&e.item(n)!==this;);return n>-1});var KB={components:{},utils:{},html:{},http:{},listeners:{clicks:{},changes:{},keys:[],internals:{}}};KB.on=function(t,e){this.listeners.internals.hasOwnProperty(t)||(this.listeners.internals[t]=[]),this.listeners.internals[t].push(e)},KB.trigger=function(t,e){if(this.listeners.internals.hasOwnProperty(t))for(var n=0;n<this.listeners.internals[t].length;n++)this.listeners.internals[t][n](e)},KB.removeListener=function(t,e){if(this.listeners.internals.hasOwnProperty(t))for(var n=0;n<this.listeners.internals[t].length;n++)this.listeners.internals[t][n]===e&&this.listeners.internals[t].splice(n,1)},KB.onClick=function(t,e){this.listeners.clicks[t]=e},KB.onChange=function(t,e){this.listeners.changes[t]=e},KB.onKey=function(t,e,n,o,a){this.listeners.keys.push({combination:t,callback:e,ignoreInputField:n||!1,ctrlKey:o||!1,metaKey:a||!1})},KB.listen=function(){function t(t){for(var e in o.listeners.clicks)o.listeners.clicks.hasOwnProperty(e)&&t.target.matches(e)&&(t.preventDefault(),o.listeners.clicks[e](t))}function e(t){for(var e in o.listeners.changes)o.listeners.changes.hasOwnProperty(e)&&t.target.matches(e)&&o.listeners.changes[e](t.target)}function n(t){var e=KB.utils.getKey(t),n=KB.utils.isInputField(t);if(n&&["Escape","Enter"].indexOf(e)===-1||a.push(e),a.length>0){for(var i=!0,r=0;r<o.listeners.keys.length;r++){var d=o.listeners.keys[r],s=d.combination,l=s.split("+");if(KB.utils.arraysIdentical(a,l)&&t.ctrlKey===d.ctrlKey&&t.metaKey===d.metaKey){if(n&&!d.ignoreInputField)return void(a=[]);t.preventDefault(),t.stopPropagation(),a=[],d.callback(t);break}KB.utils.arraysStartsWith(a,l)&&a.length<l.length&&(i=!1)}i&&(a=[])}}var o=this,a=[];document.addEventListener("click",t,!1),document.addEventListener("change",e,!1),window.addEventListener("keydown",n,!1)},KB.component=function(t,e){this.components[t]=e},KB.getComponent=function(t,e,n){var o=this.components[t];return new o(e,n)},KB.render=function(){for(var t in this.components)for(var e=document.querySelectorAll(".js-"+t),n=0;n<e.length;n++)if(this.components.hasOwnProperty(t)){var o;e[n].dataset.params&&(o=JSON.parse(e[n].dataset.params));var a=KB.getComponent(t,e[n],o);a.render(),e[n].className=e[n].className+"-rendered"}},KB.interval=function(t,e){setInterval(e,1e3*t)},KB.dom=function(t){function e(t){var e="string"==typeof t?document.createElement(t):t;this.attr=function(t,n){return null!==n&&"undefined"!=typeof n?(e.setAttribute(t,n),this):e.getAttribute(t)},this.data=function(t,n){return 1===arguments.length?e.dataset[t]:(e.dataset[t]=n,this)},this.hide=function(){return e.style.display="none",this},this.show=function(){return e.style.display="block",this},this.toggle=function(){return"none"===e.style.display?this.show():this.hide(),this},this.style=function(t,n){return e.style[t]=n,this},this.on=function(t,n,o){return e.addEventListener(t,function(t){o||t.preventDefault(),n(t.target)}),this},this.click=function(t){return this.on("click",t)},this.mouseover=function(t){return this.on("mouseover",t)},this.change=function(t){return this.on("change",t)},this.add=function(t){return e.appendChild(t),this},this.replace=function(t){return e.parentNode.replaceChild(t,e),this},this.html=function(t){return e.innerHTML=t,this},this.text=function(t){return e.appendChild(document.createTextNode(t)),this},this.replaceText=function(t){return e.textContent=t,this},this.addClass=function(t){return e.classList.add(t),this},this.removeClass=function(t){return e.classList.remove(t),this},this.toggleClass=function(t){return e.classList.toggle(t),this},this.hasClass=function(t){return e.classList.contains(t)},this.disable=function(){return e.disabled=!0,this},this.enable=function(){return e.disabled=!1,this},this.remove=function(){return e.parentNode.removeChild(e),this},this.empty=function(){for(;e.firstChild;)e.removeChild(e.firstChild);return this},this.parent=function(t){for(;e&&e!==document;e=e.parentNode)if(e.matches(t))return e;return null},this.find=function(t){return e.querySelector(t)},this.for=function(t,n){for(var o=0;o<n.length;o++){var a=n[o];if("object"!=typeof a)e.appendChild(KB.dom(t).text(a).build());else{var i=KB.dom(t);for(var r in a)a.hasOwnProperty(r)&&r in this&&"function"==typeof this[r]?i[r](a[r]):i.attr(r,a[r]);e.appendChild(i.build())}}return this},this.build=function(){return e}}return new e(t)},KB.find=function(t){var e=document.querySelector(t);return e?KB.dom(e):null},KB.exists=function(t){return!!document.querySelector(t)},KB.focus=function(t){var e=document.querySelector(t);if(e)return e.focus()},KB.html.label=function(t,e){return KB.dom("label").attr("for",e).text(t).build()},KB.html.radio=function(t,e,n){return KB.dom("label").add(KB.dom("input").attr("type","radio").attr("name",e).attr("value",n).build()).text(t).build()},KB.html.radios=function(t){var e=KB.dom("div");for(var n in t)t.hasOwnProperty(n)&&e.add(KB.html.radio(n.label,n.name,n.value))},KB.http.request=function(t,e,n,o){function a(t){var e=t.getResponseHeader("X-Ajax-Redirect"),n=t.getResponseHeader("Location");if("self"===e)window.location.reload();else if(e&&e.indexOf("#")>-1)window.location=e.split("#")[0];else if(e)window.location=e;else if(n)window.location=n;else if("application/json"===t.getResponseHeader("Content-Type"))try{return JSON.parse(t.responseText)}catch(t){}return t.responseText}var i=function(){},r=function(){};this.execute=function(){var d=new XMLHttpRequest;d.open(t,e,!0),d.setRequestHeader("X-Requested-With","XMLHttpRequest");for(var s in n)n.hasOwnProperty(s)&&d.setRequestHeader(s,n[s]);return d.onerror=function(){r()},d.onreadystatechange=function(){if(d.readyState===XMLHttpRequest.DONE){var t=a(d);200===d.status?i(t):r(t)}},d.send(o),this},this.success=function(t){return i=t,this},this.error=function(t){return r=t,this}},KB.http.get=function(t){return new KB.http.request("GET",t).execute()},KB.http.postJson=function(t,e){var n={"Content-Type":"application/json",Accept:"application/json"};return new KB.http.request("POST",t,n,JSON.stringify(e)).execute()},KB.http.postForm=function(t,e){var n=new FormData(e);return new KB.http.request("POST",t,{},n).execute()},KB.http.uploadFile=function(t,e,n,o,a){var i=new FormData;i.append("files[]",e);var r=new XMLHttpRequest;r.upload.addEventListener("progress",n),r.upload.addEventListener("load",o),r.upload.addEventListener("error",a),r.open("POST",t,!0),r.send(i)},function(){function t(t){t.target.matches("#modal-overlay")&&(t.stopPropagation(),t.preventDefault(),s())}function e(){KB.trigger("modal.close")}function n(){KB.trigger("modal.loading"),a()}function o(){return document.querySelector("#modal-content form:not(.js-modal-ignore-form)")}function a(){var t=o();if(t){var e=t.getAttribute("action");e&&KB.http.postForm(e,t).success(function(t){KB.trigger("modal.stop"),t?r(t):s()})}}function i(){var t=KB.find("#modal-content form");t&&t.on("submit",n,!1);var e=document.querySelector("#modal-content input[autofocus]");e&&e.focus(),KB.render(),_KB.datePicker(),_KB.autoComplete(),_KB.tagAutoComplete(),_KB.get("Task").onPopoverOpened()}function r(t){var e=KB.find("#modal-content");e&&(e.replace(KB.dom("div").attr("id","modal-content").html(t).build()),i())}function d(n,o,a){var r=KB.dom("a").attr("href","#").attr("id","modal-close-button").html('<i class="fa fa-times"></i>').click(e).build(),d=KB.dom("div").attr("id","modal-header").add(r).build(),s=KB.dom("div").attr("id","modal-content").html(n).build(),l=KB.dom("div").attr("id","modal-box").style("width",o).add(d).add(s).build(),c=KB.dom("div").attr("id","modal-overlay").add(l).build();a&&c.addEventListener("click",t,!1),document.body.appendChild(c),i()}function s(){c=!1;var t=KB.find("#modal-overlay");t&&t.remove()}function l(t){var e=KB.utils.getViewportSize();switch(t){case"large":return e.width<1350?"98%":"1350px";case"medium":return e.width<1024?"70%":"1024px"}return e.width<800?"75%":"800px"}var c=!1;KB.on("modal.close",function(){s()}),KB.on("modal.submit",function(){a()}),KB.modal={open:function(t,e,n){_KB.get("Dropdown").close(),s(),"undefined"==typeof n&&(n=!0),KB.http.get(t).success(function(t){c=!0,d(t,l(e),n)})},close:function(){s()},isOpen:function(){return c},replace:function(t){KB.http.get(t).success(function(t){r(t)})},getForm:o,submitForm:a}}(),KB.utils.formatDuration=function(t){return t>=86400?Math.round(t/86400)+"d":t>=3600?Math.round(t/3600)+"h":t>=60?Math.round(t/60)+"m":t+"s"},KB.utils.getSelectionPosition=function(t){var e,n;return e=t.value.length<t.selectionStart?t.value.length:t.selectionStart,n=t.selectionStart===t.selectionEnd?e:t.selectionEnd,{selectionStart:e,selectionEnd:n}},KB.utils.arraysIdentical=function(t,e){var n=t.length;if(n!==e.length)return!1;for(;n--;)if(t[n]!==e[n])return!1;return!0},KB.utils.arraysStartsWith=function(t,e){for(var n=Math.min(t.length,e.length),o=0;o<n;o++)if(t[o]!==e[o])return!1;return!0},KB.utils.isInputField=function(t){var e=t.target;return!("INPUT"!==e.tagName&&"SELECT"!==e.tagName&&"TEXTAREA"!==e.tagName&&!e.isContentEditable)},KB.utils.getKey=function(t){var e={Esc:"Escape",Up:"ArrowUp",Down:"ArrowDown",Left:"ArrowLeft",Right:"ArrowRight"};for(var n in e)if(e.hasOwnProperty(n)&&n===t.key)return e[n];return t.key},KB.utils.getViewportSize=function(){return{width:Math.max(document.documentElement.clientWidth,window.innerWidth||0),height:Math.max(document.documentElement.clientHeight,window.innerHeight||0)}},KB.onClick(".accordion-toggle",function(t){var e=KB.dom(t.target).parent(".accordion-section");e&&KB.dom(e).toggleClass("accordion-collapsed")}),KB.component("calendar",function(t,e){this.render=function(){var n=$(t);n.fullCalendar({locale:$("body").data("js-lang"),editable:!0,eventLimit:!0,defaultView:"month",header:{left:"prev,next today",center:"title",right:"month,agendaWeek,agendaDay"},eventDrop:function(t){$.ajax({cache:!1,url:e.saveUrl,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t.id,date_due:t.start.format()})})},viewRender:function(){var t=e.checkUrl,o={start:n.fullCalendar("getView").start.format(),end:n.fullCalendar("getView").end.format()};for(var a in o)t+="&"+a+"="+o[a];$.getJSON(t,function(t){n.fullCalendar("removeEvents"),n.fullCalendar("addEventSource",t),n.fullCalendar("rerenderEvents")})}})}}),KB.component("chart-project-avg-time-column",function(t,e){this.render=function(){var n=e.metrics,o=[e.label],a=[];for(var i in n)o.push(n[i].average),a.push(n[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[o],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("chart-project-burndown",function(t,e){this.render=function(){for(var n=e.metrics,o=[[e.labelTotal]],a=[],i=d3.time.format("%Y-%m-%d"),r=d3.time.format(e.dateFormat),d=0;d<n.length;d++)for(var s=0;s<n[d].length;s++)0===d?o.push([n[d][s]]):(o[s+1].push(n[d][s]),s>0&&(void 0===o[0][d]&&o[0].push(0),o[0][d]+=n[d][s]),0===s&&a.push(r(i.parse(n[d][s]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o},axis:{x:{type:"category",categories:a}}})}}),KB.component("chart-project-cumulative-flow",function(t,e){this.render=function(){for(var n=e.metrics,o=[],a=[],i=[],r=d3.time.format("%Y-%m-%d"),d=d3.time.format(e.dateFormat),s=0;s<n.length;s++)for(var l=0;l<n[s].length;l++)0===s?(o.push([n[s][l]]),l>0&&a.push(n[s][l])):(o[l].push(n[s][l]),0===l&&i.push(d(r.parse(n[s][l]))));KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:o,type:"area-spline",groups:[a]},axis:{x:{type:"category",categories:i}}})}}),KB.component("chart-project-lead-cycle-time",function(t,e){this.render=function(){var n=e.metrics,o=[e.labelCycle],a=[e.labelLead],i=[],r={};r[e.labelCycle]="area",r[e.labelLead]="area-spline";var d={};d[e.labelLead]="#afb42b",d[e.labelCycle]="#4e342e";for(var s=0;s<n.length;s++)o.push(parseInt(n[s].avg_cycle_time)),a.push(parseInt(n[s].avg_lead_time)),i.push(n[s].day);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[a,o],types:r,colors:d},axis:{x:{type:"category",categories:i},y:{tick:{format:KB.utils.formatDuration}}}})}}),KB.component("chart-project-task-distribution",function(t,e){this.render=function(){for(var n=[],o=0;o<e.metrics.length;o++)n.push([e.metrics[o].column_title,e.metrics[o].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n,type:"donut"}})}}),KB.component("chart-project-time-comparison",function(t,e){this.render=function(){var n=[e.labelSpent],o=[e.labelEstimated],a=[];for(var i in e.metrics)n.push(e.metrics[i].time_spent),o.push(e.metrics[i].time_estimated),a.push("open"===i?e.labelOpen:e.labelClosed);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:[n,o],type:"bar"},bar:{width:{ratio:.2}},axis:{x:{type:"category",categories:a}},legend:{show:!0}})}}),KB.component("chart-project-user-distribution",function(t,e){this.render=function(){for(var n=[],o=0;o<e.metrics.length;o++)n.push([e.metrics[o].user,e.metrics[o].nb_tasks]);KB.dom(t).add(KB.dom("div").attr("id","chart").build()),c3.generate({data:{columns:n,type:"donut"}})}}),KB.component("chart-task-time-column",function(t,e){this.render=function(){for(var n=e.metrics,o=[e.label],a=[],i=0;i<n.length;i++)o.push(n[i].time_spent),a.push(n[i].title);KB.dom(t).add(KB.dom("div").attr("id","chart-task-time-column").build()),c3.generate({bindto:"#chart-task-time-column",data:{columns:[o],type:"bar"},bar:{width:{ratio:.5}},axis:{x:{type:"category",categories:a},y:{tick:{format:KB.utils.formatDuration}}},legend:{show:!1}})}}),KB.component("confirm-buttons",function(t,e){function n(){r=!0,KB.find("#modal-confirm-button").replace(i()),KB.http.get(e.url)}function o(){KB.trigger("modal.close")}function a(){r=!1,KB.find("#modal-confirm-button").replace(i())}function i(){var t=KB.dom("button").click(n).attr("id","modal-confirm-button").attr("type","button").attr("class","btn btn-red");return r&&t.disable().add(KB.dom("i").attr("class","fa fa-spinner fa-pulse").build()).text(" "),e.tabindex&&t.attr("tabindex",e.tabindex),t.text(e.submitLabel).build()}var r=!1;this.render=function(){KB.on("modal.stop",a),KB.on("modal.close",function(){KB.removeListener("modal.stop",a)});var n=KB.dom("div").attr("class","form-actions").add(i()).text(" "+e.orLabel+" ").add(KB.dom("a").attr("href","#").click(o).text(e.cancelLabel).build()).build();t.appendChild(n)}}),KB.component("external-task-view",function(t,e){this.render=function(){$.ajax({cache:!1,url:e.url,success:function(e){KB.dom(t).html('<div id="external-task-view">'+e+"</div>")}})}}),KB.component("file-upload",function(t,e){function n(t){if(t.lengthComputable){var e=t.loaded/t.total,n=Math.floor(100*e);KB.find("#file-progress-"+y).attr("value",e),KB.find("#file-percentage-"+y).replaceText("("+n+"%)")}}function o(){var t=KB.dom("div").addClass("file-error").text(e.labelUploadError).build();KB.find("#file-item-"+y).add(t)}function a(){if(y++,y<B.length)KB.http.uploadFile(e.url,B[y],n,a,o);else{KB.trigger("modal.stop"),KB.trigger("modal.hide");var t=KB.dom("div").addClass("alert").addClass("alert-success").text(e.labelSuccess).build(),r=KB.dom("button").attr("type","button").addClass("btn").addClass("btn-blue").click(i).text(e.labelCloseSuccess).build();KB.dom(K).replace(KB.dom("div").add(t).add(r).build())}}function i(){window.location.reload()}function r(){y=0,u()}function d(){B=b.files,p()}function s(){B=[],y=0,b.click()}function l(t){t.stopPropagation(),t.preventDefault()}function c(t){t.stopPropagation(),t.preventDefault(),B=t.dataTransfer.files,p()}function u(){B.length>0&&KB.http.uploadFile(e.url,B[y],n,a,o)}function p(){B.length>0?(KB.trigger("modal.enable"),KB.dom(K).empty().add(v())):(KB.trigger("modal.disable"),KB.dom(K).empty().add(m()))}function f(){return KB.dom("input").attr("id","file-input-element").attr("type","file").attr("name","files[]").attr("multiple",!0).on("change",d).hide().build()}function m(){var t=KB.dom("a").attr("href","#").text(e.labelChooseFiles).click(s).build();return KB.dom("div").attr("id","file-dropzone-inner").text(e.labelDropzone+" "+e.labelOr+" ").add(t).build()}function h(){var t=KB.dom("div").attr("id","file-dropzone").add(m()).build();return t.ondragover=l,t.ondrop=c,t.ondragover=l,t}function g(t){var n=!1,o=KB.dom("progress").attr("id","file-progress-"+t).attr("value",0).build(),a=KB.dom("span").attr("id","file-percentage-"+t).text("(0%)").build(),i=KB.dom("li").attr("id","file-item-"+t).add(o).text(" "+B[t].name+" ").add(a);return B[t].size>e.maxSize&&(i.add(KB.dom("div").addClass("file-error").text(e.labelOversize).build()),n=!0),n&&KB.trigger("modal.disable"),i.build()}function v(){for(var t=KB.dom("ul").attr("id","file-list").build(),e=0;e<B.length;e++)t.appendChild(g(e));return t}var b=null,K=null,B=[],y=0;this.render=function(){KB.on("modal.submit",r),KB.on("modal.close",function(){KB.removeListener("modal.submit",r)}),b=f(),K=h(),t.appendChild(b),t.appendChild(K)}}),KB.onClick(".js-form-export",function(t){var e=document.querySelector("#modal-content form"),n=e.querySelector("#form-from"),o=e.querySelector("#form-to");""!==n.value&&""!==o.value&&e.submit()}),KB.component("image-slideshow",function(t,e){function n(t){switch(KB.utils.getKey(t)){case"Escape":s();break;case"ArrowRight":i();break;case"ArrowLeft":r()}}function o(t){t.matches(".slideshow-next-icon")?i():t.matches(".slideshow-previous-icon")?r():t.matches(".slideshow-download-icon")?window.location.href=t.href:s()}function a(t){var e=KB.dom(t).data("imageId"),n=l(e);d(n)}function i(){s();for(var t=0;t<e.images.length;t++)if(e.images[t].id===p.id){var n=t+1;n>=e.images.length&&(n=0),p=e.images[n];break}d()}function r(){s();for(var t=0;t<e.images.length;t++)if(e.images[t].id===p.id){var n=t-1;n<0&&(n=e.images.length-1),p=e.images[n];break}d()}function d(){var t=KB.dom("div").attr("class","fa fa-window-close slideshow-icon slideshow-close-icon").build(),e=KB.dom("a").attr("class","fa fa-download slideshow-icon slideshow-download-icon").attr("href",c(p,"download")).build(),a=KB.dom("div").attr("class","fa fa-chevron-circle-left slideshow-icon slideshow-previous-icon").build(),i=KB.dom("div").attr("class","fa fa-chevron-circle-right slideshow-icon slideshow-next-icon").build(),r=KB.dom("img").attr("src",c(p,"image")).attr("alt",p.name).attr("title",p.name).style("maxHeight",window.innerHeight-50+"px").build(),d=KB.dom("figcaption").text(p.name).build(),s=KB.dom("figure").add(r).add(d).build(),l=KB.dom("div").addClass("image-slideshow-overlay").add(t).add(e).add(a).add(i).add(s).click(o).build();document.body.appendChild(l),document.addEventListener("keydown",n,!1)}function s(){var t=KB.find(".image-slideshow-overlay");null!==t&&(document.removeEventListener("keydown",n,!1),t.remove())}function l(t){for(var n=0;n<e.images.length;n++)if(e.images[n].id===t)return e.images[n];return null}function c(t,n){var o=new RegExp(e.regex,"g");return e.url[n].replace(o,t.id)}function u(t){return KB.dom("img").attr("src",c(t,"thumbnail")).attr("alt",t.name).attr("title",t.name).data("imageId",t.id).click(a).build()}var p;this.render=function(){p=e.image,t.appendChild(u(p))}}),KB.keyboardShortcuts=function(){function t(t){if(!KB.modal.isOpen()){var e=KB.find(t);null!==e&&(window.location=e.attr("href"))}}function e(){if(KB.modal.isOpen())KB.modal.submitForm();else{var t=$("form");1==t.length?t.submit():t.length>1&&("INPUT"!==document.activeElement.tagName&&"TEXTAREA"!==document.activeElement.tagName||$(document.activeElement).parents("form").submit())}}KB.onKey("?",function(){KB.modal.isOpen()||KB.modal.open(KB.find("body").data("keyboardShortcutUrl"))}),KB.onKey("Escape",function(){KB.exists("#suggest-menu")||(KB.trigger("modal.close"),_KB.get("Dropdown").close())}),KB.onKey("Enter",e,!0,!0),KB.onKey("Enter",e,!0,!1,!0),KB.onKey("b",function(){KB.modal.isOpen()||KB.trigger("board.selector.open")}),KB.exists("#board")&&(KB.onKey("c",function(){KB.modal.isOpen()||_KB.get("BoardHorizontalScrolling").toggle()}),KB.onKey("s",function(){KB.modal.isOpen()||_KB.get("BoardCollapsedMode").toggle()}),KB.onKey("n",function(){KB.modal.isOpen()||KB.modal.open(KB.find("#board").data("taskCreationUrl"),"large",!1)})),KB.exists("#task-view")&&(KB.onKey("e",function(){KB.modal.isOpen()||KB.modal.open(KB.find("#task-view").data("editUrl"),"large",!1)}),KB.onKey("c",function(){KB.modal.isOpen()||KB.modal.open(KB.find("#task-view").data("commentUrl"),"medium",!1)}),KB.onKey("s",function(){KB.modal.isOpen()||KB.modal.open(KB.find("#task-view").data("subtaskUrl"),"medium",!1)}),KB.onKey("l",function(){KB.modal.isOpen()||KB.modal.open(KB.find("#task-view").data("internalLinkUrl"),"medium",!1)})),KB.onKey("f",function(){KB.modal.isOpen()||KB.focus("#form-search")}),KB.onKey("r",function(){if(!KB.modal.isOpen()){var t=$(".filter-reset").data("filter"),e=$("#form-search");e.val(t),$("form.search").submit()}}),KB.onKey("v+o",function(){t("a.view-overview")}),KB.onKey("v+b",function(){t("a.view-board")}),KB.onKey("v+c",function(){t("a.view-calendar")}),KB.onKey("v+l",function(){t("a.view-listing")}),KB.onKey("v+g",function(){t("a.view-gantt")})},function(){function t(t){return"I"===t.target.tagName?t.target.parentNode.getAttribute("href"):t.target.getAttribute("href")}KB.onClick(".js-modal-large",function(e){KB.modal.open(t(e),"large",!1)}),KB.onClick(".js-modal-medium",function(e){KB.modal.open(t(e),"medium",!1)}),KB.onClick(".js-modal-small",function(e){KB.modal.open(t(e),"small",!1)}),KB.onClick(".js-modal-confirm",function(e){KB.modal.open(t(e),"small")}),KB.onClick(".js-modal-close",function(){KB.modal.close()}),KB.onClick(".js-modal-replace",function(e){var n=t(e);KB.modal.isOpen()?KB.modal.replace(n):window.location.href=n})}(),KB.onChange(".js-project-creation-select-options",function(t){var e=t.value;"0"===e?KB.find(".js-project-creation-options").hide():KB.find(".js-project-creation-options").show()}),KB.component("project-select-role",function(t,e){function n(t){d=!0,e.role=t.value,a(),o()}function o(){KB.http.postJson(e.url,{id:e.id,role:e.role}).success(function(){d=!1,s=!0,a()}).error(function(){d=!1,s=!1,l=!0,a()})}function a(){KB.dom(r).remove(),r=i(),t.appendChild(r)}function i(){var t=[],o=KB.dom("div");for(var a in e.roles)if(e.roles.hasOwnProperty(a)){var i={value:a,text:e.roles[a]};e.role===a&&(i.selected="selected"),t.push(i)}return o.add(KB.dom("select").change(n).for("option",t).build()),d?(o.text(" "),o.add(KB.dom("i").attr("class","fa fa-spinner fa-pulse fa-fw").build())):s?(o.text(" "),o.add(KB.dom("i").attr("class","fa fa-check fa-fw icon-fade-out icon-success").build())):l&&(o.text(" "),o.add(KB.dom("i").attr("class","fa fa-check fa-fw icon-fade-out icon-error").build())),o.build()}var r,d=!1,s=!1,l=!1;this.render=function(){r=i(),t.appendChild(r)}}),KB.component("screenshot",function(t){function e(t){d(t.target.result)}function n(t){if(t.clipboardData&&t.clipboardData.items){var n=t.clipboardData.items;if(n)for(var o=0;o<n.length;o++)if(n[o].type.indexOf("image")!==-1){var a=n[o].getAsFile(),i=new FileReader;i.onload=e,i.readAsDataURL(a)}}else setTimeout(r,100)}function o(){a(),window.Clipboard||(s=document.createElement("div"),s.id="screenshot-pastezone",s.contentEditable=!0,s.style.opacity=0,s.style.position="fixed",s.style.top=0,s.style.right=0,s.style.width=0,document.body.insertBefore(s,document.body.firstChild),s.focus(),document.addEventListener("click",i),document.getElementById("screenshot-zone").addEventListener("click",i)),window.addEventListener("paste",n,!1)}function a(){KB.exists("#screenshot-pastezone")&&KB.find("#screenshot-pastezone").remove(),document.removeEventListener("click",i),s=null}function i(){null!==s&&s.focus()}function r(){var t=s.childNodes[0];t&&"IMG"===t.tagName&&d(t.src),s.innerHTML=""}function d(t){var e=new Image;e.src=t,e.onload=function(){var e=t.split("base64,");l.value=e[1]};var n=document.getElementById("screenshot-zone");n.innerHTML="",n.className="screenshot-pasted",n.appendChild(e),a(),o()}var s=null,l=null;KB.on("modal.close",function(){a()}),this.render=function(){l=KB.dom("input").attr("type","hidden").attr("name","screenshot").build(),t.appendChild(l),o()}}),KB.component("select-dropdown-autocomplete",function(t,e){function n(){KB.dom(x).show(),KB.dom(C).hide()}function o(){KB.dom(x).hide(),KB.dom(C).show()}function a(){var t=KB.find("#select-dropdown-menu");if(t){var e=y.getBoundingClientRect();t.style("top",document.body.scrollTop+e.bottom+"px")}}function i(t){switch(KB.utils.getKey(t)){case"Escape":w.value="",b();break;case"ArrowUp":t.preventDefault(),t.stopImmediatePropagation(),f();break;case"ArrowDown":t.preventDefault(),t.stopImmediatePropagation(),m();break;case"Enter":t.preventDefault(),t.stopImmediatePropagation(),u()}}function r(){b(),K()}function d(t){KB.dom(t).hasClass("select-dropdown-menu-item")&&(KB.find(".select-dropdown-menu-item.active").removeClass("active"),KB.dom(t).addClass("active"))}function s(){u()}function l(e){t.contains(e.target)||(w.value="",b())}function c(){var t=KB.find("#select-dropdown-menu");null===t?K():b()}function u(){var t=KB.find(".select-dropdown-menu-item.active"),o=t.data("value");k.value=o,w.value=e.items[o],b(),e.redirect?window.location=e.redirect.url.replace(new RegExp(e.redirect.regex,"g"),o):e.replace&&(n(),KB.modal.replace(e.replace.url.replace(new RegExp(e.replace.regex,"g"),o)))}function p(){for(var t=document.querySelectorAll(".select-dropdown-menu-item"),e=0;e<t.length;e++)if(KB.dom(t[e]).hasClass("active")){KB.dom(t[e]).removeClass("active");break}return{items:t,index:e}}function f(){var t=p();t.index>0&&(t.index=t.index-1),KB.dom(t.items[t.index]).addClass("active")}function m(){var t=p();t.index<t.items.length-1&&t.index++,KB.dom(t.items[t.index]).addClass("active")}function h(t){var n=[];for(var o in t)t.hasOwnProperty(o)&&n.push({class:"select-dropdown-menu-item",text:t[o],"data-label":t[o],"data-value":o});return e.sortByKeys?n.sort(function(t,e){var n=t["data-value"].toLowerCase(),o=e["data-value"].toLowerCase();return n<o?-1:n>o?1:0}):n.sort(function(t,e){var n=t["data-label"].toLowerCase(),o=e["data-label"].toLowerCase();return n<o?-1:n>o?1:0}),n}function g(t,n){for(var o=[],a=!1,i=0;i<n.length;i++)if(0===t.length||0===n[i]["data-label"].toLowerCase().indexOf(t.toLowerCase())){var r=n[i];"undefined"!=typeof e.defaultValue&&String(e.defaultValue)===r["data-value"]&&(r.class+=" active",a=!0),o.push(r)}return!a&&o.length>0&&(o[0].class+=" active"),o}function v(){var t=g(w.value,h(e.items)),n=y.getBoundingClientRect();return 0===t.length?null:KB.dom("ul").attr("id","select-dropdown-menu").style("top",document.body.scrollTop+n.bottom+"px").style("left",n.left+"px").style("width",n.width+"px").style("maxHeight",window.innerHeight-n.bottom-20+"px").mouseover(d).click(s).for("li",t).build()}function b(){var t=KB.find("#select-dropdown-menu");null!==t&&t.remove(),document.removeEventListener("keydown",i,!1),document.removeEventListener("click",l,!1)}function K(){var t=v();null!==t&&document.body.appendChild(t),document.addEventListener("keydown",i,!1),document.addEventListener("click",l,!1)}function B(){return e.defaultValue&&e.defaultValue in e.items?e.items[e.defaultValue]:e.placeholder?e.placeholder:""}var y,w,k,C,x;this.render=function(){KB.on("select.dropdown.loading.start",n),KB.on("select.dropdown.loading.stop",o),KB.on("modal.close",function(){KB.removeListener("select.dropdown.loading.start",n),KB.removeListener("select.dropdown.loading.stop",o)}),C=KB.dom("i").attr("class","fa fa-chevron-down select-dropdown-chevron").click(c).build(),x=KB.dom("span").hide().addClass("select-loading-icon").add(KB.dom("i").attr("class","fa fa-spinner fa-pulse").build()).build(),k=KB.dom("input").attr("type","hidden").attr("name",e.name).attr("value",e.defaultValue||"").build(),w=KB.dom("input").attr("type","text").attr("placeholder",B()).addClass("select-dropdown-input").style("width",t.offsetWidth-30+"px").on("focus",c).on("input",r,!0).build(),y=KB.dom("div").addClass("select-dropdown-input-container").add(k).add(w).add(C).add(x).build(),t.appendChild(y),e.onFocus&&e.onFocus.forEach(function(t){KB.on(t,function(){w.focus()})}),window.addEventListener("scroll",a,!1)}}),KB.interval(60,function(){var t=KB.find("body").data("statusUrl"),e=KB.find("body").data("loginUrl");null===KB.find(".form-login")&&KB.http.get(t).error(function(){window.location=e})}),KB.component("submit-buttons",function(t,e){function n(){c=!0,KB.find("#modal-submit-button").replace(l()),KB.trigger("modal.submit");
+}function o(){KB.trigger("modal.close")}function a(){c=!1,KB.find("#modal-submit-button").replace(l())}function i(){c=!1,u=!0,KB.find("#modal-submit-button").replace(l())}function r(){c=!1,u=!1,KB.find("#modal-submit-button").replace(l())}function d(){KB.dom(f).hide()}function s(t){p=t.submitLabel,KB.find("#modal-submit-button").replace(l())}function l(){var t=KB.dom("button").attr("id","modal-submit-button").attr("type","submit").attr("class","btn btn-"+(e.color||"blue"));return KB.modal.isOpen()&&t.click(n),e.tabindex&&t.attr("tabindex",e.tabindex),c&&t.disable().add(KB.dom("i").attr("class","fa fa-spinner fa-pulse").build()).text(" "),u&&t.disable(),t.text(p).build()}var c=!1,u=e.disabled||!1,p=e.submitLabel,f=null;this.render=function(){KB.on("modal.stop",a),KB.on("modal.disable",i),KB.on("modal.enable",r),KB.on("modal.hide",d),KB.on("modal.submit.label",s),KB.on("modal.close",function(){KB.removeListener("modal.stop",a),KB.removeListener("modal.disable",i),KB.removeListener("modal.enable",r),KB.removeListener("modal.hide",d),KB.removeListener("modal.submit.label",s)});var n=KB.dom("div").attr("class","form-actions").add(l());KB.modal.isOpen()&&n.text(" "+e.orLabel+" ").add(KB.dom("a").attr("href","#").click(o).text(e.cancelLabel).build()),f=n.build(),t.appendChild(f)}}),KB.component("suggest-menu",function(t,e){function n(t){switch(KB.utils.getKey(t)){case"Escape":u();break;case"ArrowUp":t.preventDefault(),t.stopImmediatePropagation(),l();break;case"ArrowDown":t.preventDefault(),t.stopImmediatePropagation(),c();break;case"Enter":t.preventDefault(),t.stopImmediatePropagation(),i()}}function o(){i()}function a(t){KB.dom(t).hasClass("suggest-menu-item")&&(KB.find(".suggest-menu-item.active").removeClass("active"),KB.dom(t).addClass("active"))}function i(){t.focus();var e=KB.find(".suggest-menu-item.active"),n=e.data("value"),o=e.data("trigger"),a=t.value,i=r(t),d=o+n+" ",s=KB.utils.getSelectionPosition(t),l=a.substring(0,s.selectionStart-i.length),c=a.substring(s.selectionEnd),p=l.length+d.length;t.value=l+d+c,t.setSelectionRange(p,p),u()}function r(t){var e=t.value.substring(0,t.selectionEnd).split("\n"),n=e[e.length-1],o=n.split(" ");return o[o.length-1]}function d(){for(var t=["#modal-content form","#modal-content","body"],e=0;e<t.length;e++){var n=document.querySelector(t[e]);if(null!==n)return n}return null}function s(){for(var t=document.querySelectorAll(".suggest-menu-item"),e=0;e<t.length;e++)if(KB.dom(t[e]).hasClass("active")){KB.dom(t[e]).removeClass("active");break}return{items:t,index:e}}function l(){var t=s();t.index>0&&(t.index=t.index-1),KB.dom(t.items[t.index]).addClass("active")}function c(){var t=s();t.index<t.items.length-1&&t.index++,KB.dom(t.items[t.index]).addClass("active")}function u(){var t=KB.find("#suggest-menu");null!==t&&t.remove(),document.removeEventListener("keydown",n,!1)}function p(t){var n=r(t),o=f(n,e.triggers);u(),null!==o&&m(o,n.substring(o.length),e.triggers[o])}function f(t,e){for(var n in e)if(e.hasOwnProperty(n)&&0===t.indexOf(n))return n;return null}function m(t,e,n){if("string"==typeof n){var o=new RegExp("SEARCH_TERM","g"),a=n.replace(o,e);KB.http.get(a).success(function(n){h(t,e,n)})}else h(t,e,n)}function h(t,e,n){n=g(e,n),n.length>0&&b(v(t,n))}function g(t,e){var n=[];if(0===t.length)return e;for(var o=0;o<e.length;o++)0===e[o].value.toLowerCase().indexOf(t.toLowerCase())&&n.push(e[o]);return n}function v(t,e){for(var n=[],o=0;o<e.length;o++){var a="suggest-menu-item";0===o&&(a+=" active"),n.push({class:a,html:e[o].html,"data-value":e[o].value,"data-trigger":t})}return n}function b(e){var i=d(),r=getCaretCoordinates(t,t.selectionEnd),s=r.left+t.offsetLeft-t.scrollLeft,l=r.top+t.offsetTop-t.scrollTop+16;document.addEventListener("keydown",n,!1);var c=KB.dom("ul").attr("id","suggest-menu").click(o).mouseover(a).style("left",s+"px").style("top",l+"px").for("li",e).build();i.appendChild(c)}this.render=function(){t.addEventListener("input",function(){p(this)})}}),KB.component("task-move-position",function(t,e){function n(t){var e=KB.dom(document).find("#"+t);return e?parseInt(e.options[e.selectedIndex].value):null}function o(){var t=n("form-swimlanes");return null===t?e.board[0].id:t}function a(){var t=n("form-columns");return null===t?e.board[0].columns[0].id:t}function i(){var t=n("form-position");return null===t?1:t}function r(){var t=KB.find("input[name=positionChoice]:checked");return t?t.value:"before"}function d(){var t=KB.dom(document).find("#form-columns");KB.dom(t).replace(p());var e=KB.dom(document).find("#form-tasks");KB.dom(e).replace(f())}function s(){var t=KB.dom(document).find("#form-tasks");KB.dom(t).replace(f())}function l(t){KB.trigger("modal.stop"),KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").attr("class","alert alert-error").text(t).build())}function c(){var t=i(),n=r();"after"===n&&t++,KB.find("#message-container").replace(KB.dom("div").attr("id","message-container").build()),KB.http.postJson(e.saveUrl,{column_id:a(),swimlane_id:o(),position:t}).error(function(t){t&&l(t.message)})}function u(){var t=[];return e.board.forEach(function(e){t.push({value:e.id,text:e.name})}),KB.dom("select").attr("id","form-swimlanes").change(d).for("option",t).build()}function p(){var t=[],n=o();return e.board.forEach(function(e){n===e.id&&e.columns.forEach(function(e){t.push({value:e.id,text:e.title})})}),KB.dom("select").attr("id","form-columns").change(s).for("option",t).build()}function f(){var t=[],n=o(),i=a(),r=KB.dom("div").attr("id","form-tasks");return e.board.forEach(function(e){n===e.id&&e.columns.forEach(function(e){i===e.id&&e.tasks.forEach(function(e){t.push({value:e.position,text:"#"+e.id+" - "+e.title})})})}),t.length>0&&r.add(KB.html.label(e.positionLabel,"form-position")).add(KB.dom("select").attr("id","form-position").for("option",t).build()).add(KB.html.radio(e.beforeLabel,"positionChoice","before")).add(KB.html.radio(e.afterLabel,"positionChoice","after")),r.build()}this.render=function(){KB.on("modal.submit",c),KB.on("modal.close",function(){KB.removeListener("modal.submit",c)});var n=KB.dom("div").add(KB.dom("div").attr("id","message-container").build()).add(KB.html.label(e.swimlaneLabel,"form-swimlanes")).add(u()).add(KB.html.label(e.columnLabel,"form-columns")).add(p()).add(f()).build();t.appendChild(n)}}),KB.component("text-editor",function(t,e){function n(){var t=KB.dom("div").attr("class","text-editor-toolbar").for("a",[{href:"#",html:'<i class="fa fa-pencil-square-o fa-fw"></i> '+e.labelWrite,click:function(){a()}}]).build();return h=KB.dom("div").attr("class","text-editor-preview-area markdown").build(),KB.dom("div").attr("class","text-editor-view-mode").add(t).add(h).hide().build()}function o(){var t=KB.dom("div").attr("class","text-editor-toolbar").for("a",[{href:"#",html:'<i class="fa fa-eye fa-fw"></i> '+e.labelPreview,click:function(){a()}},{href:"#",html:'<i class="fa fa-bold fa-fw"></i>',click:function(){d("**")}},{href:"#",html:'<i class="fa fa-italic fa-fw"></i>',click:function(){d("_")}},{href:"#",html:'<i class="fa fa-strikethrough fa-fw"></i>',click:function(){d("~~")}},{href:"#",html:'<i class="fa fa-quote-right fa-fw"></i>',click:function(){l("> ")}},{href:"#",html:'<i class="fa fa-list-ul fa-fw"></i>',click:function(){l("* ")}},{href:"#",html:'<i class="fa fa-code fa-fw"></i>',click:function(){s("```")}}]).build(),n=KB.dom("textarea");return n.attr("name",e.name),e.tabindex&&n.attr("tabindex",e.tabindex),e.required&&n.attr("required","required"),n.text(e.text),e.placeholder&&n.attr("placeholder",e.placeholder),p=n.build(),e.suggestOptions&&KB.getComponent("suggest-menu",p,e.suggestOptions).render(),KB.dom("div").attr("class","text-editor-write-mode").add(t).add(p).build()}function a(){KB.dom(h).html(marked(p.value,{sanitize:!0})),KB.dom(f).toggle(),KB.dom(m).toggle()}function i(){return p.value.substring(p.selectionStart,p.selectionEnd)}function r(t,e,n,o){return t.substring(0,e)+o+t.substring(n)}function d(t){var e=i();c(t+e+t),u(t)}function s(t){var e=i();c("\n"+t+"\n"+e+"\n"+t),u(t,2)}function l(t){var e=i();if(e.indexOf("\n")===-1)c("\n"+t+e);else{for(var n=e.split("\n"),o=0;o<n.length;o++)n[o].indexOf(t)===-1&&(n[o]=t+n[o]);c(n.join("\n"))}u(t,1)}function c(t){p.focus();var e=!1,n=KB.utils.getSelectionPosition(p);if(g=n.selectionStart,v=n.selectionEnd,document.queryCommandSupported("insertText")&&(e=document.execCommand("insertText",!1,t)),!e){try{document.execCommand("ms-beginUndoUnit")}catch(t){}p.value=r(p.value,g,v,t);try{document.execCommand("ms-endUndoUnit")}catch(t){}}}function u(t,e){e=e||0;var n=v+t.length+e;p.setSelectionRange(n,n)}var p,f,m,h,g,v;this.render=function(){m=o(),f=n(),t.appendChild(KB.dom("div").attr("class","text-editor").add(f).add(m).build()),e.autofocus&&p.focus()}}),document.addEventListener("DOMContentLoaded",function(){KB.render(),KB.listen(),KB.keyboardShortcuts()});var Kanboard={};Kanboard.App=function(){this.controllers={}},Kanboard.App.prototype.get=function(t){return this.controllers[t]},Kanboard.App.prototype.execute=function(){for(var t in Kanboard)if("App"!==t){var e=new Kanboard[t](this);this.controllers[t]=e,"function"==typeof e.execute&&e.execute(),"function"==typeof e.listen&&e.listen(),"function"==typeof e.focus&&e.focus()}this.focus(),this.datePicker(),this.autoComplete(),this.tagAutoComplete()},Kanboard.App.prototype.focus=function(){$(document).on("focus",".auto-select",function(){$(this).select()}),$(document).on("mouseup",".auto-select",function(t){t.preventDefault()})},Kanboard.App.prototype.datePicker=function(){var t=$("body"),e=t.data("js-date-format"),n=t.data("js-time-format"),o=t.data("js-lang");$.datepicker.setDefaults($.datepicker.regional[o]),$.timepicker.setDefaults($.timepicker.regional[o]),$(".form-date").datepicker({showOtherMonths:!0,selectOtherMonths:!0,dateFormat:e,constrainInput:!1}),$(".form-datetime").datetimepicker({dateFormat:e,timeFormat:n,constrainInput:!1})},Kanboard.App.prototype.tagAutoComplete=function(){$(".tag-autocomplete").select2({tags:!0})},Kanboard.App.prototype.autoComplete=function(){$(".autocomplete").each(function(){var t=$(this),e=t.data("dst-field"),n=t.data("dst-extra-field");""===$("#form-"+e).val()&&t.parent().find("button[type=submit]").attr("disabled","disabled"),t.autocomplete({source:t.data("search-url"),minLength:1,select:function(o,a){$("input[name="+e+"]").val(a.item.id),n&&$("input[name="+n+"]").val(a.item[n]),t.parent().find("button[type=submit]").removeAttr("disabled")}})})},Kanboard.App.prototype.hasId=function(t){return!!document.getElementById(t)},Kanboard.App.prototype.showLoadingIcon=function(){$("body").append('<span id="app-loading-icon">&nbsp;<i class="fa fa-spinner fa-spin"></i></span>')},Kanboard.App.prototype.hideLoadingIcon=function(){$("#app-loading-icon").remove()},Kanboard.App.prototype.isVisible=function(){var t="";return"undefined"!=typeof document.hidden?t="visibilityState":"undefined"!=typeof document.mozHidden?t="mozVisibilityState":"undefined"!=typeof document.msHidden?t="msVisibilityState":"undefined"!=typeof document.webkitHidden&&(t="webkitVisibilityState"),""===t||"visible"==document[t]},Kanboard.BoardCollapsedMode=function(t){this.app=t},Kanboard.BoardCollapsedMode.prototype.toggle=function(){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$('.filter-display-mode:not([style="display: none;"]) a').attr("href"),success:function(e){$(".filter-display-mode").toggle(),t.app.get("BoardDragAndDrop").refresh(e)}})},Kanboard.BoardColumnView=function(t){this.app=t},Kanboard.BoardColumnView.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardColumnView.prototype.listen=function(){var t=this;$(document).on("click",".board-toggle-column-view",function(){t.toggle($(this).data("column-id"))})},Kanboard.BoardColumnView.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardColumnView.prototype.render=function(){var t=this;$(".board-column-header").each(function(){var e=$(this).data("column-id");localStorage.getItem("hidden_column_"+e)&&t.hideColumn(e)})},Kanboard.BoardColumnView.prototype.toggle=function(t){localStorage.getItem("hidden_column_"+t)?this.showColumn(t):this.hideColumn(t)},Kanboard.BoardColumnView.prototype.hideColumn=function(t){$(".board-column-"+t+" .board-column-expanded").hide(),$(".board-column-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t+" .board-column-expanded").hide(),$(".board-column-header-"+t+" .board-column-collapsed").show(),$(".board-column-header-"+t).each(function(){$(this).removeClass("board-column-compact"),$(this).addClass("board-column-header-collapsed")}),$(".board-column-"+t).each(function(){$(this).addClass("board-column-task-collapsed")}),$(".board-column-"+t+" .board-rotation").each(function(){$(this).css("width",$(".board-column-"+t).height())}),localStorage.setItem("hidden_column_"+t,1)},Kanboard.BoardColumnView.prototype.showColumn=function(t){$(".board-column-"+t+" .board-column-expanded").show(),$(".board-column-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t+" .board-column-expanded").show(),$(".board-column-header-"+t+" .board-column-collapsed").hide(),$(".board-column-header-"+t).removeClass("board-column-header-collapsed"),$(".board-column-"+t).removeClass("board-column-task-collapsed"),0==localStorage.getItem("horizontal_scroll")&&$(".board-column-header-"+t).addClass("board-column-compact"),localStorage.removeItem("hidden_column_"+t)},Kanboard.BoardHorizontalScrolling=function(t){this.app=t},Kanboard.BoardHorizontalScrolling.prototype.execute=function(){this.app.hasId("board")&&this.render()},Kanboard.BoardHorizontalScrolling.prototype.listen=function(){var t=this;$(document).on("click",".filter-toggle-scrolling",function(e){e.preventDefault(),t.toggle()})},Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered=function(){this.render()},Kanboard.BoardHorizontalScrolling.prototype.toggle=function(){var t=localStorage.getItem("horizontal_scroll")||1;localStorage.setItem("horizontal_scroll",0==t?1:0),this.render()},Kanboard.BoardHorizontalScrolling.prototype.render=function(){0==localStorage.getItem("horizontal_scroll")?($(".filter-wide").show(),$(".filter-compact").hide(),$("#board-container").addClass("board-container-compact"),$("#board th:not(.board-column-header-collapsed)").addClass("board-column-compact")):($(".filter-wide").hide(),$(".filter-compact").show(),$("#board-container").removeClass("board-container-compact"),$("#board th").removeClass("board-column-compact"))},Kanboard.BoardPolling=function(t){this.app=t},Kanboard.BoardPolling.prototype.execute=function(){if(this.app.hasId("board")){var t=parseInt($("#board").attr("data-check-interval"));t>0&&window.setInterval(this.check.bind(this),1e3*t)}},Kanboard.BoardPolling.prototype.check=function(){if(this.app.isVisible()&&!this.app.get("BoardDragAndDrop").savingInProgress){var t=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:$("#board").data("check-url"),statusCode:{200:function(e){t.app.get("BoardDragAndDrop").refresh(e)},304:function(){t.app.hideLoadingIcon()}}})}},Kanboard.BoardTask=function(t){this.app=t},Kanboard.BoardTask.prototype.listen=function(){$(document).on("click",".task-board-change-assignee",function(t){t.preventDefault(),t.stopPropagation(),KB.modal.open($(this).data("url"),"medium",!1)}),$(document).on("click",".task-board",function(t){"A"!=t.target.tagName&&"IMG"!=t.target.tagName&&(window.location=$(this).data("task-url"))})},Kanboard.Column=function(t){this.app=t},Kanboard.Column.prototype.listen=function(){this.dragAndDrop()},Kanboard.Column.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".columns-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,n){var o=n.item;o.removeClass("draggable-item-selected"),t.savePosition(o.data("column-id"),o.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Column.prototype.savePosition=function(t,e){var n=$(".columns-table").data("save-position-url"),o=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:n,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({column_id:t,position:e}),complete:function(){o.app.hideLoadingIcon()}})},Kanboard.Dropdown=function(t){this.app=t},Kanboard.Dropdown.prototype.listen=function(){var t=this;$(document).on("click",function(){t.close()}),$(document).on("click",".dropdown-menu",function(e){e.preventDefault(),e.stopImmediatePropagation(),t.close();var n=$(this).next("ul"),o=$(this).offset();$("body").append(jQuery("<div>",{id:"dropdown"})),n.clone().appendTo("#dropdown");var a=$("#dropdown ul");a.addClass("dropdown-submenu-open");var i=a.outerHeight(),r=a.outerWidth();o.top+i-$(window).scrollTop()<$(window).height()||$(window).scrollTop()+o.top<i?a.css("top",o.top+$(this).height()):a.css("top",o.top-i-5),o.left+r>$(window).width()?a.css("left",o.left-r+$(this).outerWidth()):a.css("left",o.left)}),$(document).on("click",".dropdown-submenu-open li",function(t){$(t.target).is("li")&&$(this).find("a:visible")[0].click()})},Kanboard.Dropdown.prototype.close=function(){$("#dropdown").remove()},Kanboard.Gantt=function(t){this.app=t,this.data=[],this.options={container:"#gantt-chart",showWeekends:!0,allowMoves:!0,allowResizes:!0,cellWidth:21,cellHeight:31,slideWidth:1e3,vHeaderWidth:200}},Kanboard.Gantt.prototype.execute=function(){this.app.hasId("gantt-chart")&&this.show()},Kanboard.Gantt.prototype.saveRecord=function(t){this.app.showLoadingIcon(),$.ajax({cache:!1,url:$(this.options.container).data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify(t),complete:this.app.hideLoadingIcon.bind(this)})},Kanboard.Gantt.prototype.show=function(){this.data=this.prepareData($(this.options.container).data("records"));var t=Math.floor(this.options.slideWidth/this.options.cellWidth+5),e=this.getDateRange(t),n=e[0],o=e[1],a=$(this.options.container),i=jQuery("<div>",{class:"ganttview"});i.append(this.renderVerticalHeader()),i.append(this.renderSlider(n,o)),a.append(i),jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child",a).addClass("last"),jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child",a).addClass("last"),$(this.options.container).data("readonly")?(this.options.allowResizes=!1,this.options.allowMoves=!1):(this.listenForBlockResize(n),this.listenForBlockMove(n))},Kanboard.Gantt.prototype.renderVerticalHeader=function(){for(var t=jQuery("<div>",{class:"ganttview-vtheader"}),e=jQuery("<div>",{class:"ganttview-vtheader-item"}),n=jQuery("<div>",{class:"ganttview-vtheader-series"}),o=0;o<this.data.length;o++){var a=jQuery("<span>").append(jQuery("<i>",{class:"fa fa-info-circle tooltip",title:this.getVerticalHeaderTooltip(this.data[o])})).append("&nbsp;");"task"==this.data[o].type?a.append(jQuery("<a>",{href:this.data[o].link,title:this.data[o].title}).append(this.data[o].title)):a.append(jQuery("<a>",{href:this.data[o].board_link,title:$(this.options.container).data("label-board-link")}).append('<i class="fa fa-th"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[o].gantt_link,title:$(this.options.container).data("label-gantt-link")}).append('<i class="fa fa-sliders"></i>')).append("&nbsp;").append(jQuery("<a>",{href:this.data[o].link}).append(this.data[o].title)),n.append(jQuery("<div>",{class:"ganttview-vtheader-series-name"}).append(a))}return e.append(n),t.append(e),t},Kanboard.Gantt.prototype.renderSlider=function(t,e){var n=jQuery("<div>",{class:"ganttview-slide-container"}),o=this.getDates(t,e);return n.append(this.renderHorizontalHeader(o)),n.append(this.renderGrid(o)),n.append(this.addBlockContainers()),this.addBlocks(n,t),n},Kanboard.Gantt.prototype.renderHorizontalHeader=function(t){var e=jQuery("<div>",{class:"ganttview-hzheader"}),n=jQuery("<div>",{class:"ganttview-hzheader-months"}),o=jQuery("<div>",{class:"ganttview-hzheader-days"}),a=0;for(var i in t)for(var r in t[i]){var d=t[i][r].length*this.options.cellWidth;a+=d,n.append(jQuery("<div>",{class:"ganttview-hzheader-month",css:{width:d-1+"px"}}).append($.datepicker.regional[$("body").data("js-lang")].monthNames[r]+" "+i));for(var s in t[i][r])o.append(jQuery("<div>",{class:"ganttview-hzheader-day"}).append(t[i][r][s].getDate()))}return n.css("width",a+"px"),o.css("width",a+"px"),e.append(n).append(o),e},Kanboard.Gantt.prototype.renderGrid=function(t){var e=jQuery("<div>",{class:"ganttview-grid"}),n=jQuery("<div>",{class:"ganttview-grid-row"});for(var o in t)for(var a in t[o])for(var i in t[o][a]){var r=jQuery("<div>",{class:"ganttview-grid-row-cell"});this.options.showWeekends&&this.isWeekend(t[o][a][i])&&r.addClass("ganttview-weekend"),n.append(r)}var d=jQuery("div.ganttview-grid-row-cell",n).length*this.options.cellWidth;n.css("width",d+"px"),e.css("width",d+"px");for(var s=0;s<this.data.length;s++)e.append(n.clone());return e},Kanboard.Gantt.prototype.addBlockContainers=function(){for(var t=jQuery("<div>",{class:"ganttview-blocks"}),e=0;e<this.data.length;e++)t.append(jQuery("<div>",{class:"ganttview-block-container"}));return t},Kanboard.Gantt.prototype.addBlocks=function(t,e){for(var n=jQuery("div.ganttview-blocks div.ganttview-block-container",t),o=0,a=0;a<this.data.length;a++){var i=this.data[a],r=this.daysBetween(i.start,i.end)+1,d=this.daysBetween(e,i.start),s=jQuery("<div>",{class:"ganttview-block-text"}),l=jQuery("<div>",{class:"ganttview-block tooltip"+(this.options.allowMoves?" ganttview-block-movable":""),title:this.getBarTooltip(i),css:{width:r*this.options.cellWidth-9+"px","margin-left":d*this.options.cellWidth+"px"}}).append(s);r>=2&&s.append(i.progress),l.data("record",i),this.setBarColor(l,i),jQuery(n[o]).append(l),o+=1}},Kanboard.Gantt.prototype.getVerticalHeaderTooltip=function(t){var e="";if("task"==t.type)e="<strong>"+t.column_title+"</strong> ("+t.progress+")<br/>"+t.title;else{var n=["project-manager","project-member"];for(var o in n){var a=n[o];if(!jQuery.isEmptyObject(t.users[a])){var i=jQuery("<ul>");for(var r in t.users[a])r&&i.append(jQuery("<li>").append(t.users[a][r]));e+="<p><strong>"+$(this.options.container).data("label-"+a)+"</strong></p>"+i[0].outerHTML}}}return e},Kanboard.Gantt.prototype.getBarTooltip=function(t){var e="";return t.not_defined?e=$(this.options.container).data("label-not-defined"):("task"==t.type&&(e="<strong>"+t.progress+"</strong><br/>"+$(this.options.container).data("label-assignee")+" "+(t.assignee?t.assignee:"")+"<br/>"),e+=$(this.options.container).data("label-start-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.start)+"<br/>",e+=$(this.options.container).data("label-end-date")+" "+$.datepicker.formatDate("yy-mm-dd",t.end)),e},Kanboard.Gantt.prototype.setBarColor=function(t,e){e.not_defined?t.addClass("ganttview-block-not-defined"):(t.css("background-color",e.color.background),t.css("border-color",e.color.border),"0%"!=e.progress&&t.append(jQuery("<div>",{css:{"z-index":0,position:"absolute",top:0,bottom:0,"background-color":e.color.border,width:e.progress,opacity:.4}})))},Kanboard.Gantt.prototype.listenForBlockResize=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).resizable({grid:this.options.cellWidth,handles:"e,w",delay:300,stop:function(){var n=jQuery(this);e.updateDataAndPosition(n,t),e.saveRecord(n.data("record"))}})},Kanboard.Gantt.prototype.listenForBlockMove=function(t){var e=this;jQuery("div.ganttview-block",this.options.container).draggable({axis:"x",delay:300,grid:[this.options.cellWidth,this.options.cellWidth],stop:function(){var n=jQuery(this);e.updateDataAndPosition(n,t),e.saveRecord(n.data("record"))}})},Kanboard.Gantt.prototype.updateDataAndPosition=function(t,e){var n=jQuery("div.ganttview-slide-container",this.options.container),o=n.scrollLeft(),a=t.offset().left-n.offset().left-1+o,i=t.data("record");i.not_defined=!1,this.setBarColor(t,i);var r=Math.round(a/this.options.cellWidth),d=this.addDays(this.cloneDate(e),r);i.start=d;var s=t.outerWidth(),l=Math.round(s/this.options.cellWidth)-1;i.end=this.addDays(this.cloneDate(d),l),"task"===i.type&&l>0&&jQuery("div.ganttview-block-text",t).text(i.progress),t.attr("title",this.getBarTooltip(i)),t.data("record",i),t.css("top","").css("left","").css("position","relative").css("margin-left",a+"px")},Kanboard.Gantt.prototype.getDates=function(t,e){var n=[];n[t.getFullYear()]=[],n[t.getFullYear()][t.getMonth()]=[t];for(var o=t;this.compareDate(o,e)==-1;){var a=this.addDays(this.cloneDate(o),1);n[a.getFullYear()]||(n[a.getFullYear()]=[]),n[a.getFullYear()][a.getMonth()]||(n[a.getFullYear()][a.getMonth()]=[]),n[a.getFullYear()][a.getMonth()].push(a),o=a}return n},Kanboard.Gantt.prototype.prepareData=function(t){for(var e=0;e<t.length;e++){var n=new Date(t[e].start[0],t[e].start[1]-1,t[e].start[2],0,0,0,0);t[e].start=n;var o=new Date(t[e].end[0],t[e].end[1]-1,t[e].end[2],0,0,0,0);t[e].end=o}return t},Kanboard.Gantt.prototype.getDateRange=function(t){for(var e=new Date,n=new Date,o=0;o<this.data.length;o++){var a=new Date;a.setTime(Date.parse(this.data[o].start));var i=new Date;i.setTime(Date.parse(this.data[o].end)),0==o&&(e=a,n=i),1==this.compareDate(e,a)&&(e=a),this.compareDate(n,i)==-1&&(n=i)}return this.daysBetween(e,n)<t&&(n=this.addDays(this.cloneDate(e),t)),e.setDate(e.getDate()-1),[e,n]},Kanboard.Gantt.prototype.daysBetween=function(t,e){if(!t||!e)return 0;for(var n=0,o=this.cloneDate(t);this.compareDate(o,e)==-1;)n+=1,this.addDays(o,1);return n},Kanboard.Gantt.prototype.isWeekend=function(t){return t.getDay()%6==0},Kanboard.Gantt.prototype.cloneDate=function(t){return new Date(t.getTime())},Kanboard.Gantt.prototype.addDays=function(t,e){return t.setDate(t.getDate()+1*e),t},Kanboard.Gantt.prototype.compareDate=function(t,e){if(isNaN(t)||isNaN(e))throw new Error(t+" - "+e);if(t instanceof Date&&e instanceof Date)return t<e?-1:t>e?1:0;throw new TypeError(t+" - "+e)},Kanboard.Search=function(t){this.app=t},Kanboard.Search.prototype.focus=function(){$(document).on("focus","#form-search",function(){var t=$("#form-search");if(t[0].setSelectionRange){var e=2*t.val().length;t[0].setSelectionRange(e,e)}})},Kanboard.Search.prototype.listen=function(){$(document).on("click",".filter-helper",function(t){t.preventDefault();var e=$(this).data("filter"),n=$(this).data("append-filter"),o=$(this).data("unique-filter"),a=$("#form-search");if(o){var i=o.substr(0,o.indexOf(":"));e=a.val().replace(new RegExp("("+i+":[#a-z0-9]+)","g"),""),e=e.replace(new RegExp("("+i+':"(.+)")',"g"),""),e=e.trim(),e+=" "+o}else n&&(e=a.val()+" "+n);a.val(e),$("form.search").submit()})},Kanboard.Subtask=function(t){this.app=t},Kanboard.Subtask.prototype.listen=function(){var t=this;this.dragAndDrop(),$(document).on("click",".subtask-toggle-status",function(e){var n=$(this);e.preventDefault(),$.ajax({cache:!1,url:n.attr("href"),success:function(e){n.hasClass("subtask-refresh-table")?$(".subtasks-table").replaceWith(e):n.replaceWith(e),t.dragAndDrop()}})}),$(document).on("click",".subtask-toggle-timer",function(e){var n=$(this);e.preventDefault(),$.ajax({cache:!1,url:n.attr("href"),success:function(e){$(".subtasks-table").replaceWith(e),t.dragAndDrop()}})})},Kanboard.Subtask.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".subtasks-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,n){var o=n.item;o.removeClass("draggable-item-selected"),t.savePosition(o.data("subtask-id"),o.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Subtask.prototype.savePosition=function(t,e){var n=$(".subtasks-table").data("save-position-url"),o=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:n,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({subtask_id:t,position:e}),complete:function(){o.app.hideLoadingIcon()}})},Kanboard.Swimlane=function(t){this.app=t},Kanboard.Swimlane.prototype.execute=function(){$(".swimlanes-table").length&&this.dragAndDrop()},Kanboard.Swimlane.prototype.listen=function(){var t=this;$(document).on("click",".board-swimlane-toggle",function(e){e.preventDefault();var n=$(this).data("swimlane-id");t.isCollapsed(n)?t.expand(n):t.collapse(n)})},Kanboard.Swimlane.prototype.onBoardRendered=function(){for(var t=this.getAllCollapsed(),e=0;e<t.length;e++)this.collapse(t[e])},Kanboard.Swimlane.prototype.getStorageKey=function(){return"hidden_swimlanes_"+$("#board").data("project-id")},Kanboard.Swimlane.prototype.expand=function(t){var e=this.getAllCollapsed(),n=e.indexOf(t);n>-1&&e.splice(n,1),localStorage.setItem(this.getStorageKey(),JSON.stringify(e)),$(".board-swimlane-columns-"+t).css("display","table-row"),$(".board-swimlane-tasks-"+t).css("display","table-row"),$(".hide-icon-swimlane-"+t).css("display","inline"),$(".show-icon-swimlane-"+t).css("display","none")},Kanboard.Swimlane.prototype.collapse=function(t){var e=this.getAllCollapsed();e.indexOf(t)<0&&(e.push(t),localStorage.setItem(this.getStorageKey(),JSON.stringify(e))),$(".board-swimlane-columns-"+t+":not(:first-child)").css("display","none"),$(".board-swimlane-tasks-"+t).css("display","none"),$(".hide-icon-swimlane-"+t).css("display","none"),$(".show-icon-swimlane-"+t).css("display","inline")},Kanboard.Swimlane.prototype.isCollapsed=function(t){return this.getAllCollapsed().indexOf(t)>-1},Kanboard.Swimlane.prototype.getAllCollapsed=function(){return JSON.parse(localStorage.getItem(this.getStorageKey()))||[]},Kanboard.Swimlane.prototype.dragAndDrop=function(){var t=this;$(".draggable-row-handle").mouseenter(function(){$(this).parent().parent().addClass("draggable-item-hover")}).mouseleave(function(){$(this).parent().parent().removeClass("draggable-item-hover")}),$(".swimlanes-table tbody").sortable({forcePlaceholderSize:!0,handle:"td:first i",helper:function(t,e){return e.children().each(function(){$(this).width($(this).width())}),e},stop:function(e,n){var o=n.item;o.removeClass("draggable-item-selected"),t.savePosition(o.data("swimlane-id"),o.index()+1)},start:function(t,e){e.item.addClass("draggable-item-selected")}}).disableSelection()},Kanboard.Swimlane.prototype.savePosition=function(t,e){var n=$(".swimlanes-table").data("save-position-url"),o=this;this.app.showLoadingIcon(),$.ajax({cache:!1,url:n,contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({swimlane_id:t,position:e}),complete:function(){o.app.hideLoadingIcon()}})},Kanboard.Task=function(t){this.app=t},Kanboard.Task.prototype.onPopoverOpened=function(){var t=this;t.renderColorPicker(),$(document).on("click",".assign-me",function(t){var e=$(this).data("current-id"),n="#"+$(this).data("target-id");t.preventDefault(),$(n+" option[value="+e+"]").length&&$(n).val(e)})},Kanboard.Task.prototype.renderColorPicker=function(){function t(t){return $('<div class="color-picker-option"><div class="color-picker-square color-'+t.id+'"></div><div class="color-picker-label">'+t.text+"</div></div>")}$(".color-picker").select2({minimumResultsForSearch:1/0,templateResult:t,templateSelection:t})},Kanboard.Tooltip=function(t){this.app=t},Kanboard.Tooltip.prototype.onBoardRendered=function(){this.execute()},Kanboard.Tooltip.prototype.execute=function(){$(".tooltip").tooltip({track:!1,show:!1,hide:!1,position:{my:"left-20 top",at:"center bottom+9",using:function(t,e){$(this).css(t);
+var n=e.target.left+e.target.width/2-e.element.left-20;$("<div>").addClass("tooltip-arrow").addClass(e.vertical).addClass(n<1?"align-left":"align-right").appendTo(this)}},content:function(){var t=this,e=$(this).attr("data-href");return e?($.get(e,function(e){var n=$(".ui-tooltip:visible");$(".ui-tooltip-content:visible").html(e),n.css({top:"",left:""}),n.children(".tooltip-arrow").remove();var o=$(t).tooltip("option","position");o.of=$(t),n.position(o)}),'<i class="fa fa-spinner fa-spin"></i>'):'<div class="markdown">'+$(this).attr("title")+"</div>"}}).on("mouseenter",function(){var t=this;$(this).tooltip("open"),$(".ui-tooltip").on("mouseleave",function(){$(t).tooltip("close")})}).on("mouseleave focusout",function(t){t.stopImmediatePropagation();var e=this;setTimeout(function(){$(".ui-tooltip:hover").length||$(e).tooltip("close")},100)})},Kanboard.BoardDragAndDrop=function(t){this.app=t,this.savingInProgress=!1},Kanboard.BoardDragAndDrop.prototype.execute=function(){this.app.hasId("board")&&(this.dragAndDrop(),this.executeListeners())},Kanboard.BoardDragAndDrop.prototype.dragAndDrop=function(){var t=this,e=$(".board-task-list"),n={forcePlaceholderSize:!0,tolerance:"pointer",connectWith:".sortable-column",placeholder:"draggable-placeholder",items:".draggable-item",stop:function(e,n){var o=n.item,a=o.attr("data-task-id"),i=o.attr("data-position"),r=o.attr("data-column-id"),d=o.attr("data-swimlane-id"),s=o.parent().attr("data-column-id"),l=o.parent().attr("data-swimlane-id"),c=o.index()+1;o.removeClass("draggable-item-selected"),s==r&&l==d&&c==i||(t.changeTaskState(a),t.save(a,r,s,c,l))},start:function(t,e){e.item.addClass("draggable-item-selected"),e.placeholder.height(e.item.height())}};isMobile.any&&($(".task-board-sort-handle").css("display","inline"),n.handle=".task-board-sort-handle"),e.each(function(){$(this).css("min-height",$(this).parent().height())}),e.sortable(n)},Kanboard.BoardDragAndDrop.prototype.changeTaskState=function(t){var e=$("div[data-task-id="+t+"]");e.addClass("task-board-saving-state"),e.find(".task-board-saving-icon").show()},Kanboard.BoardDragAndDrop.prototype.save=function(t,e,n,o,a){var i=this;i.app.showLoadingIcon(),i.savingInProgress=!0,$.ajax({cache:!1,url:$("#board").data("save-url"),contentType:"application/json",type:"POST",processData:!1,data:JSON.stringify({task_id:t,src_column_id:e,dst_column_id:n,swimlane_id:a,position:o}),success:function(t){i.refresh(t),i.savingInProgress=!1},error:function(){i.app.hideLoadingIcon(),i.savingInProgress=!1},statusCode:{403:function(t){window.alert(t.responseJSON.message),document.location.reload(!0)}}})},Kanboard.BoardDragAndDrop.prototype.refresh=function(t){$("#board-container").replaceWith(t),this.app.hideLoadingIcon(),this.dragAndDrop(),this.executeListeners()},Kanboard.BoardDragAndDrop.prototype.executeListeners=function(){for(var t in this.app.controllers){var e=this.app.get(t);"function"==typeof e.onBoardRendered&&e.onBoardRendered()}};var _KB=null;jQuery(document).ready(function(){_KB=new Kanboard.App,_KB.execute()}); \ No newline at end of file
diff --git a/assets/js/components/accordion.js b/assets/js/components/accordion.js
index 4588ccc6..2f617fb5 100644
--- a/assets/js/components/accordion.js
+++ b/assets/js/components/accordion.js
@@ -1,8 +1,7 @@
-KB.onClick('.accordion-toggle', function(e) {
- var section = KB.dom(e.target).parent('.accordion-section');
+KB.onClick('.accordion-toggle', function (e) {
+ var sectionElement = KB.dom(e.target).parent('.accordion-section');
- if (section) {
- KB.dom(section).toggleClass('accordion-collapsed');
- KB.dom(KB.dom(section).find('.accordion-content')).toggle();
+ if (sectionElement) {
+ KB.dom(sectionElement).toggleClass('accordion-collapsed');
}
});
diff --git a/assets/js/components/chart-task-time-column.js b/assets/js/components/chart-task-time-column.js
index 887d24d4..89709952 100644
--- a/assets/js/components/chart-task-time-column.js
+++ b/assets/js/components/chart-task-time-column.js
@@ -10,9 +10,10 @@ KB.component('chart-task-time-column', function (containerElement, options) {
categories.push(metrics[i].title);
}
- KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart').build());
+ KB.dom(containerElement).add(KB.dom('div').attr('id', 'chart-task-time-column').build());
c3.generate({
+ bindto: '#chart-task-time-column',
data: {
columns: [plots],
type: 'bar'
diff --git a/assets/js/components/submit-cancel.js b/assets/js/components/confirm-buttons.js
index ccb3c1d9..da31df55 100644
--- a/assets/js/components/submit-cancel.js
+++ b/assets/js/components/confirm-buttons.js
@@ -1,28 +1,27 @@
-KB.component('submit-cancel', function (containerElement, options) {
+KB.component('confirm-buttons', function (containerElement, options) {
var isLoading = false;
function onSubmit() {
isLoading = true;
- KB.find('#modal-submit-button').replace(buildButton());
- KB.trigger('modal.submit');
+ KB.find('#modal-confirm-button').replace(buildButton());
+ KB.http.get(options.url);
}
function onCancel() {
- KB.trigger('modal.cancel');
- _KB.get('Popover').close();
+ KB.trigger('modal.close');
}
function onStop() {
isLoading = false;
- KB.find('#modal-submit-button').replace(buildButton());
+ KB.find('#modal-confirm-button').replace(buildButton());
}
function buildButton() {
var button = KB.dom('button')
.click(onSubmit)
- .attr('id', 'modal-submit-button')
- .attr('type', 'submit')
- .attr('class', 'btn btn-blue');
+ .attr('id', 'modal-confirm-button')
+ .attr('type', 'button')
+ .attr('class', 'btn btn-red');
if (isLoading) {
button
@@ -32,6 +31,10 @@ KB.component('submit-cancel', function (containerElement, options) {
;
}
+ if (options.tabindex) {
+ button.attr('tabindex', options.tabindex);
+ }
+
return button
.text(options.submitLabel)
.build();
@@ -39,6 +42,9 @@ KB.component('submit-cancel', function (containerElement, options) {
this.render = function () {
KB.on('modal.stop', onStop);
+ KB.on('modal.close', function () {
+ KB.removeListener('modal.stop', onStop);
+ });
var element = KB.dom('div')
.attr('class', 'form-actions')
diff --git a/assets/js/components/file-upload.js b/assets/js/components/file-upload.js
new file mode 100644
index 00000000..f4445a44
--- /dev/null
+++ b/assets/js/components/file-upload.js
@@ -0,0 +1,195 @@
+KB.component('file-upload', function (containerElement, options) {
+ var inputFileElement = null;
+ var dropzoneElement = null;
+ var files = [];
+ var currentFileIndex = 0;
+
+ function onProgress(e) {
+ if (e.lengthComputable) {
+ var progress = e.loaded / e.total;
+ var percentage = Math.floor(progress * 100);
+
+ KB.find('#file-progress-' + currentFileIndex).attr('value', progress);
+ KB.find('#file-percentage-' + currentFileIndex).replaceText('(' + percentage + '%)');
+ }
+ }
+
+ function onError() {
+ var errorElement = KB.dom('div').addClass('file-error').text(options.labelUploadError).build();
+ KB.find('#file-item-' + currentFileIndex).add(errorElement);
+ }
+
+ function onComplete() {
+ currentFileIndex++;
+
+ if (currentFileIndex < files.length) {
+ KB.http.uploadFile(options.url, files[currentFileIndex], onProgress, onComplete, onError);
+ } else {
+ KB.trigger('modal.stop');
+ KB.trigger('modal.hide');
+
+ var alertElement = KB.dom('div')
+ .addClass('alert')
+ .addClass('alert-success')
+ .text(options.labelSuccess)
+ .build();
+
+ var buttonElement = KB.dom('button')
+ .attr('type', 'button')
+ .addClass('btn')
+ .addClass('btn-blue')
+ .click(onCloseWindow)
+ .text(options.labelCloseSuccess)
+ .build();
+
+ KB.dom(dropzoneElement).replace(KB.dom('div').add(alertElement).add(buttonElement).build());
+ }
+ }
+
+ function onCloseWindow() {
+ window.location.reload();
+ }
+
+ function onSubmit() {
+ currentFileIndex = 0;
+ uploadFiles();
+ }
+
+ function onFileChange() {
+ files = inputFileElement.files;
+ showFiles();
+ }
+
+ function onClickFileBrowser() {
+ files = [];
+ currentFileIndex = 0;
+ inputFileElement.click();
+ }
+
+ function onDragOver(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ function onDrop(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ files = e.dataTransfer.files;
+ showFiles();
+ }
+
+ function uploadFiles() {
+ if (files.length > 0) {
+ KB.http.uploadFile(options.url, files[currentFileIndex], onProgress, onComplete, onError);
+ }
+ }
+
+ function showFiles() {
+ if (files.length > 0) {
+ KB.trigger('modal.enable');
+
+ KB.dom(dropzoneElement)
+ .empty()
+ .add(buildFileListElement());
+ } else {
+ KB.trigger('modal.disable');
+
+ KB.dom(dropzoneElement)
+ .empty()
+ .add(buildInnerDropzoneElement());
+ }
+ }
+
+ function buildFileInputElement() {
+ return KB.dom('input')
+ .attr('id', 'file-input-element')
+ .attr('type', 'file')
+ .attr('name', 'files[]')
+ .attr('multiple', true)
+ .on('change', onFileChange)
+ .hide()
+ .build();
+ }
+
+ function buildInnerDropzoneElement() {
+ var dropzoneLinkElement = KB.dom('a')
+ .attr('href', '#')
+ .text(options.labelChooseFiles)
+ .click(onClickFileBrowser)
+ .build();
+
+ return KB.dom('div')
+ .attr('id', 'file-dropzone-inner')
+ .text(options.labelDropzone + ' ' + options.labelOr + ' ')
+ .add(dropzoneLinkElement)
+ .build();
+ }
+
+ function buildDropzoneElement() {
+ var dropzoneElement = KB.dom('div')
+ .attr('id', 'file-dropzone')
+ .add(buildInnerDropzoneElement())
+ .build();
+
+ dropzoneElement.ondragover = onDragOver;
+ dropzoneElement.ondrop = onDrop;
+ dropzoneElement.ondragover = onDragOver;
+
+ return dropzoneElement;
+ }
+
+ function buildFileListItem(index) {
+ var isOversize = false;
+ var progressElement = KB.dom('progress')
+ .attr('id', 'file-progress-' + index)
+ .attr('value', 0)
+ .build();
+
+ var percentageElement = KB.dom('span')
+ .attr('id', 'file-percentage-' + index)
+ .text('(0%)')
+ .build();
+
+ var itemElement = KB.dom('li')
+ .attr('id', 'file-item-' + index)
+ .add(progressElement)
+ .text(' ' + files[index].name + ' ')
+ .add(percentageElement);
+
+ if (files[index].size > options.maxSize) {
+ itemElement.add(KB.dom('div').addClass('file-error').text(options.labelOversize).build());
+ isOversize = true;
+ }
+
+ if (isOversize) {
+ KB.trigger('modal.disable');
+ }
+
+ return itemElement.build();
+ }
+
+ function buildFileListElement() {
+ var fileListElement = KB.dom('ul')
+ .attr('id', 'file-list')
+ .build();
+
+ for (var i = 0; i < files.length; i++) {
+ fileListElement.appendChild(buildFileListItem(i));
+ }
+
+ return fileListElement;
+ }
+
+ this.render = function () {
+ KB.on('modal.submit', onSubmit);
+ KB.on('modal.close', function () {
+ KB.removeListener('modal.submit', onSubmit);
+ });
+
+ inputFileElement = buildFileInputElement();
+ dropzoneElement = buildDropzoneElement();
+ containerElement.appendChild(inputFileElement);
+ containerElement.appendChild(dropzoneElement);
+ };
+});
diff --git a/assets/js/components/form-export.js b/assets/js/components/form-export.js
new file mode 100644
index 00000000..c46fede1
--- /dev/null
+++ b/assets/js/components/form-export.js
@@ -0,0 +1,9 @@
+KB.onClick('.js-form-export', function(e) {
+ var formElement = document.querySelector('#modal-content form');
+ var fromElement = formElement.querySelector('#form-from');
+ var toElement = formElement.querySelector('#form-to');
+
+ if (fromElement.value !== '' && toElement.value !== '') {
+ formElement.submit();
+ }
+});
diff --git a/assets/js/components/image-slideshow.js b/assets/js/components/image-slideshow.js
index 9d3fb0ad..9db72bb9 100644
--- a/assets/js/components/image-slideshow.js
+++ b/assets/js/components/image-slideshow.js
@@ -2,14 +2,14 @@ KB.component('image-slideshow', function (containerElement, options) {
var currentImage;
function onKeyDown(e) {
- switch (e.keyCode) {
- case 27:
+ switch (KB.utils.getKey(e)) {
+ case 'Escape':
destroySlide();
break;
- case 39:
+ case 'ArrowRight':
renderNextSlide();
break;
- case 37:
+ case 'ArrowLeft':
renderPreviousSlide();
break;
}
diff --git a/assets/js/components/keyboard-shortcuts.js b/assets/js/components/keyboard-shortcuts.js
index 49524a76..cffcd790 100644
--- a/assets/js/components/keyboard-shortcuts.js
+++ b/assets/js/components/keyboard-shortcuts.js
@@ -1,4 +1,131 @@
-// Open board selector: "b"
-KB.onKey(98, function () {
- KB.trigger('board.selector.open');
-});
+KB.keyboardShortcuts = function () {
+ function goToLink (selector) {
+ if (! KB.modal.isOpen()) {
+ var element = KB.find(selector);
+
+ if (element !== null) {
+ window.location = element.attr('href');
+ }
+ }
+ }
+
+ function submitForm() {
+ if (KB.modal.isOpen()) {
+ KB.modal.submitForm();
+ } else {
+ var forms = $("form");
+
+ if (forms.length == 1) {
+ forms.submit();
+ } else if (forms.length > 1) {
+ if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
+ $(document.activeElement).parents("form").submit();
+ }
+ }
+ }
+ }
+
+ KB.onKey('?', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('body').data('keyboardShortcutUrl'));
+ }
+ });
+
+ KB.onKey('Escape', function () {
+ if (! KB.exists('#suggest-menu')) {
+ KB.trigger('modal.close');
+ _KB.get("Dropdown").close();
+ }
+ });
+
+ KB.onKey('Enter', submitForm, true, true);
+ KB.onKey('Enter', submitForm, true, false, true);
+
+ KB.onKey('b', function () {
+ if (! KB.modal.isOpen()) {
+ KB.trigger('board.selector.open');
+ }
+ });
+
+ if (KB.exists('#board')) {
+ KB.onKey('c', function () {
+ if (! KB.modal.isOpen()) {
+ _KB.get('BoardHorizontalScrolling').toggle();
+ }
+ });
+
+ KB.onKey('s', function () {
+ if (! KB.modal.isOpen()) {
+ _KB.get('BoardCollapsedMode').toggle();
+ }
+ });
+
+ KB.onKey('n', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('#board').data('taskCreationUrl'), 'large', false);
+ }
+ });
+ }
+
+ if (KB.exists('#task-view')) {
+ KB.onKey('e', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('#task-view').data('editUrl'), 'large', false);
+ }
+ });
+
+ KB.onKey('c', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('#task-view').data('commentUrl'), 'medium', false);
+ }
+ });
+
+ KB.onKey('s', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('#task-view').data('subtaskUrl'), 'medium', false);
+ }
+ });
+
+ KB.onKey('l', function () {
+ if (! KB.modal.isOpen()) {
+ KB.modal.open(KB.find('#task-view').data('internalLinkUrl'), 'medium', false);
+ }
+ });
+ }
+
+ KB.onKey('f', function () {
+ if (! KB.modal.isOpen()) {
+ KB.focus('#form-search');
+ }
+ });
+
+ KB.onKey('r', function () {
+ if (! KB.modal.isOpen()) {
+ var reset = $(".filter-reset").data("filter");
+ var input = $("#form-search");
+
+ input.val(reset);
+ $("form.search").submit();
+ }
+ });
+
+ KB.onKey('v+o', function () {
+ goToLink('a.view-overview');
+ });
+
+ KB.onKey('v+b', function () {
+ goToLink('a.view-board');
+ });
+
+ KB.onKey('v+c', function () {
+ goToLink('a.view-calendar');
+ });
+
+ KB.onKey('v+l', function () {
+ goToLink('a.view-listing');
+ });
+
+ KB.onKey('v+g', function () {
+ goToLink('a.view-gantt');
+ });
+};
diff --git a/assets/js/components/modal.js b/assets/js/components/modal.js
new file mode 100644
index 00000000..ce6f34de
--- /dev/null
+++ b/assets/js/components/modal.js
@@ -0,0 +1,39 @@
+(function () {
+ function getLink(e) {
+ if (e.target.tagName === 'I') {
+ return e.target.parentNode.getAttribute('href');
+ }
+
+ return e.target.getAttribute('href');
+ }
+
+ KB.onClick('.js-modal-large', function (e) {
+ KB.modal.open(getLink(e), 'large', false);
+ });
+
+ KB.onClick('.js-modal-medium', function (e) {
+ KB.modal.open(getLink(e), 'medium', false);
+ });
+
+ KB.onClick('.js-modal-small', function (e) {
+ KB.modal.open(getLink(e), 'small', false);
+ });
+
+ KB.onClick('.js-modal-confirm', function (e) {
+ KB.modal.open(getLink(e), 'small');
+ });
+
+ KB.onClick('.js-modal-close', function () {
+ KB.modal.close();
+ });
+
+ KB.onClick('.js-modal-replace', function (e) {
+ var link = getLink(e);
+
+ if (KB.modal.isOpen()) {
+ KB.modal.replace(link);
+ } else {
+ window.location.href = link;
+ }
+ });
+}());
diff --git a/assets/js/components/screenshot.js b/assets/js/components/screenshot.js
new file mode 100644
index 00000000..a8acd64e
--- /dev/null
+++ b/assets/js/components/screenshot.js
@@ -0,0 +1,122 @@
+KB.component('screenshot', function (containerElement) {
+ var pasteCatcher = null;
+ var inputElement = null;
+
+ function onFileLoaded(e) {
+ createImage(e.target.result);
+ }
+
+ function onPaste(e) {
+ // Firefox doesn't have the property e.clipboardData.items (only Chrome)
+ if (e.clipboardData && e.clipboardData.items) {
+ var items = e.clipboardData.items;
+
+ if (items) {
+ for (var i = 0; i < items.length; i++) {
+ // Find an image in pasted elements
+ if (items[i].type.indexOf("image") !== -1) {
+ var blob = items[i].getAsFile();
+
+ // Get the image as base64 data
+ var reader = new FileReader();
+ reader.onload = onFileLoaded;
+ reader.readAsDataURL(blob);
+ }
+ }
+ }
+ } else {
+
+ // Handle Firefox
+ setTimeout(checkInput, 100);
+ }
+ }
+
+ function initialize() {
+ destroy();
+
+ if (! window.Clipboard) {
+ // Insert the content editable at the top to avoid scrolling down in the board view
+ pasteCatcher = document.createElement('div');
+ pasteCatcher.id = 'screenshot-pastezone';
+ pasteCatcher.contentEditable = true;
+ pasteCatcher.style.opacity = 0;
+ pasteCatcher.style.position = 'fixed';
+ pasteCatcher.style.top = 0;
+ pasteCatcher.style.right = 0;
+ pasteCatcher.style.width = 0;
+ document.body.insertBefore(pasteCatcher, document.body.firstChild);
+
+ pasteCatcher.focus();
+
+ // Set the focus when clicked anywhere in the document
+ document.addEventListener('click', setFocus);
+
+ // Set the focus when clicked in screenshot dropzone
+ document.getElementById('screenshot-zone').addEventListener('click', setFocus);
+ }
+
+ window.addEventListener('paste', onPaste, false);
+ }
+
+ function destroy() {
+ if (KB.exists('#screenshot-pastezone')) {
+ KB.find('#screenshot-pastezone').remove();
+ }
+
+ document.removeEventListener('click', setFocus);
+ pasteCatcher = null;
+ }
+
+ function setFocus() {
+ if (pasteCatcher !== null) {
+ pasteCatcher.focus();
+ }
+ }
+
+ function checkInput() {
+ var child = pasteCatcher.childNodes[0];
+
+ if (child) {
+ // If the user pastes an image, the src attribute
+ // will represent the image as a base64 encoded string.
+ if (child.tagName === 'IMG') {
+ createImage(child.src);
+ }
+ }
+
+ pasteCatcher.innerHTML = '';
+ }
+
+ function createImage(blob) {
+ var pastedImage = new Image();
+ pastedImage.src = blob;
+
+ // Send the image content to the form variable
+ pastedImage.onload = function() {
+ var sourceSplit = blob.split('base64,');
+ inputElement.value = sourceSplit[1];
+ };
+
+ var zone = document.getElementById('screenshot-zone');
+ zone.innerHTML = '';
+ zone.className = 'screenshot-pasted';
+ zone.appendChild(pastedImage);
+
+ destroy();
+ initialize();
+ }
+
+ KB.on('modal.close', function () {
+ destroy();
+ });
+
+ this.render = function () {
+ inputElement = KB.dom('input')
+ .attr('type', 'hidden')
+ .attr('name', 'screenshot')
+ .build();
+
+ containerElement.appendChild(inputElement);
+ initialize();
+ };
+});
diff --git a/assets/js/components/select-dropdown-autocomplete.js b/assets/js/components/select-dropdown-autocomplete.js
index 5ed7ab9c..c2c36f5b 100644
--- a/assets/js/components/select-dropdown-autocomplete.js
+++ b/assets/js/components/select-dropdown-autocomplete.js
@@ -1,23 +1,42 @@
KB.component('select-dropdown-autocomplete', function(containerElement, options) {
- var componentElement, inputElement, inputHiddenElement;
+ var componentElement, inputElement, inputHiddenElement, chevronIconElement, loadingIconElement;
+
+ function onLoadingStart() {
+ KB.dom(loadingIconElement).show();
+ KB.dom(chevronIconElement).hide();
+ }
+
+ function onLoadingStop() {
+ KB.dom(loadingIconElement).hide();
+ KB.dom(chevronIconElement).show();
+ }
+
+ function onScroll() {
+ var menuElement = KB.find('#select-dropdown-menu');
+
+ if (menuElement) {
+ var componentPosition = componentElement.getBoundingClientRect();
+ menuElement.style('top', (document.body.scrollTop + componentPosition.bottom) + 'px');
+ }
+ }
function onKeyDown(e) {
- switch (e.keyCode) {
- case 27:
+ switch (KB.utils.getKey(e)) {
+ case 'Escape':
inputElement.value = '';
destroyDropdownMenu();
break;
- case 38:
+ case 'ArrowUp':
e.preventDefault();
e.stopImmediatePropagation();
moveUp();
break;
- case 40:
+ case 'ArrowDown':
e.preventDefault();
e.stopImmediatePropagation();
moveDown();
break;
- case 13:
+ case 'Enter':
e.preventDefault();
e.stopImmediatePropagation();
insertSelectedItem();
@@ -66,8 +85,10 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
destroyDropdownMenu();
if (options.redirect) {
- var regex = new RegExp(options.redirect.regex, 'g');
- window.location = options.redirect.url.replace(regex, value);
+ window.location = options.redirect.url.replace(new RegExp(options.redirect.regex, 'g'), value);
+ } else if (options.replace) {
+ onLoadingStart();
+ KB.modal.replace(options.replace.url.replace(new RegExp(options.replace.regex, 'g'), value));
}
}
@@ -106,18 +127,29 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
function buildItems(items) {
var elements = [];
- var keys = Object.keys(items);
- if (options.sortByKeys) {
- keys.sort();
+ for (var key in items) {
+ if (items.hasOwnProperty(key)) {
+ elements.push({
+ 'class': 'select-dropdown-menu-item',
+ 'text': items[key],
+ 'data-label': items[key],
+ 'data-value': key
+ });
+ }
}
- for (var i = 0; i < keys.length; i++) {
- elements.push({
- 'class': 'select-dropdown-menu-item',
- 'text': items[keys[i]],
- 'data-label': items[keys[i]],
- 'data-value': keys[i]
+ if (options.sortByKeys) {
+ elements.sort(function (a, b) {
+ var value1 = a['data-value'].toLowerCase();
+ var value2 = b['data-value'].toLowerCase();
+ return value1 < value2 ? -1 : (value1 > value2 ? 1 : 0);
+ });
+ } else {
+ elements.sort(function (a, b) {
+ var value1 = a['data-label'].toLowerCase();
+ var value2 = b['data-label'].toLowerCase();
+ return value1 < value2 ? -1 : (value1 > value2 ? 1 : 0);
});
}
@@ -158,7 +190,7 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
return KB.dom('ul')
.attr('id', 'select-dropdown-menu')
- .style('top', componentPosition.bottom + 'px')
+ .style('top', (document.body.scrollTop + componentPosition.bottom) + 'px')
.style('left', componentPosition.left + 'px')
.style('width', componentPosition.width + 'px')
.style('maxHeight', (window.innerHeight - componentPosition.bottom - 20) + 'px')
@@ -203,11 +235,25 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
}
this.render = function () {
- var dropdownIconElement = KB.dom('i')
+ KB.on('select.dropdown.loading.start', onLoadingStart);
+ KB.on('select.dropdown.loading.stop', onLoadingStop);
+
+ KB.on('modal.close', function () {
+ KB.removeListener('select.dropdown.loading.start', onLoadingStart);
+ KB.removeListener('select.dropdown.loading.stop', onLoadingStop);
+ });
+
+ chevronIconElement = KB.dom('i')
.attr('class', 'fa fa-chevron-down select-dropdown-chevron')
.click(toggleDropdownMenu)
.build();
+ loadingIconElement = KB.dom('span')
+ .hide()
+ .addClass('select-loading-icon')
+ .add(KB.dom('i').attr('class', 'fa fa-spinner fa-pulse').build())
+ .build();
+
inputHiddenElement = KB.dom('input')
.attr('type', 'hidden')
.attr('name', options.name)
@@ -227,7 +273,8 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
.addClass('select-dropdown-input-container')
.add(inputHiddenElement)
.add(inputElement)
- .add(dropdownIconElement)
+ .add(chevronIconElement)
+ .add(loadingIconElement)
.build();
containerElement.appendChild(componentElement);
@@ -237,5 +284,7 @@ KB.component('select-dropdown-autocomplete', function(containerElement, options)
KB.on(eventName, function() { inputElement.focus(); });
});
}
+
+ window.addEventListener('scroll', onScroll, false);
};
});
diff --git a/assets/js/components/submit-buttons.js b/assets/js/components/submit-buttons.js
new file mode 100644
index 00000000..2745841a
--- /dev/null
+++ b/assets/js/components/submit-buttons.js
@@ -0,0 +1,102 @@
+KB.component('submit-buttons', function (containerElement, options) {
+ var isLoading = false;
+ var isDisabled = options.disabled || false;
+ var submitLabel = options.submitLabel;
+ var formActionElement = null;
+
+ function onSubmit() {
+ isLoading = true;
+ KB.find('#modal-submit-button').replace(buildButton());
+ KB.trigger('modal.submit');
+ }
+
+ function onCancel() {
+ KB.trigger('modal.close');
+ }
+
+ function onStop() {
+ isLoading = false;
+ KB.find('#modal-submit-button').replace(buildButton());
+ }
+
+ function onDisable() {
+ isLoading = false;
+ isDisabled = true;
+ KB.find('#modal-submit-button').replace(buildButton());
+ }
+
+ function onEnable() {
+ isLoading = false;
+ isDisabled = false;
+ KB.find('#modal-submit-button').replace(buildButton());
+ }
+
+ function onHide() {
+ KB.dom(formActionElement).hide();
+ }
+
+ function onUpdateSubmitLabel(eventData) {
+ submitLabel = eventData.submitLabel;
+ KB.find('#modal-submit-button').replace(buildButton());
+ }
+
+ function buildButton() {
+ var button = KB.dom('button')
+ .attr('id', 'modal-submit-button')
+ .attr('type', 'submit')
+ .attr('class', 'btn btn-' + (options.color || 'blue'));
+
+ if (KB.modal.isOpen()) {
+ button.click(onSubmit);
+ }
+
+ if (options.tabindex) {
+ button.attr('tabindex', options.tabindex);
+ }
+
+ if (isLoading) {
+ button
+ .disable()
+ .add(KB.dom('i').attr('class', 'fa fa-spinner fa-pulse').build())
+ .text(' ')
+ ;
+ }
+
+ if (isDisabled) {
+ button.disable();
+ }
+
+ return button
+ .text(submitLabel)
+ .build();
+ }
+
+ this.render = function () {
+ KB.on('modal.stop', onStop);
+ KB.on('modal.disable', onDisable);
+ KB.on('modal.enable', onEnable);
+ KB.on('modal.hide', onHide);
+ KB.on('modal.submit.label', onUpdateSubmitLabel);
+
+ KB.on('modal.close', function () {
+ KB.removeListener('modal.stop', onStop);
+ KB.removeListener('modal.disable', onDisable);
+ KB.removeListener('modal.enable', onEnable);
+ KB.removeListener('modal.hide', onHide);
+ KB.removeListener('modal.submit.label', onUpdateSubmitLabel);
+ });
+
+ var formActionElementBuilder = KB.dom('div')
+ .attr('class', 'form-actions')
+ .add(buildButton());
+
+ if (KB.modal.isOpen()) {
+ formActionElementBuilder
+ .text(' ' + options.orLabel + ' ')
+ .add(KB.dom('a').attr('href', '#').click(onCancel).text(options.cancelLabel).build());
+ }
+
+ formActionElement = formActionElementBuilder.build();
+ containerElement.appendChild(formActionElement);
+ };
+});
diff --git a/assets/js/components/suggest-menu.js b/assets/js/components/suggest-menu.js
index 07539d2c..7f3e6f62 100644
--- a/assets/js/components/suggest-menu.js
+++ b/assets/js/components/suggest-menu.js
@@ -1,21 +1,21 @@
KB.component('suggest-menu', function(containerElement, options) {
function onKeyDown(e) {
- switch (e.keyCode) {
- case 27:
+ switch (KB.utils.getKey(e)) {
+ case 'Escape':
destroy();
break;
- case 38:
+ case 'ArrowUp':
e.preventDefault();
e.stopImmediatePropagation();
moveUp();
break;
- case 40:
+ case 'ArrowDown':
e.preventDefault();
e.stopImmediatePropagation();
moveDown();
break;
- case 13:
+ case 'Enter':
e.preventDefault();
e.stopImmediatePropagation();
insertSelectedItem();
@@ -62,7 +62,7 @@ KB.component('suggest-menu', function(containerElement, options) {
}
function getParentElement() {
- var selectors = ['.popover-form', '#popover-content', 'body'];
+ var selectors = ['#modal-content form', '#modal-content', 'body'];
for (var i = 0; i < selectors.length; i++) {
var element = document.querySelector(selectors[i]);
diff --git a/assets/js/components/task-move-position.js b/assets/js/components/task-move-position.js
index e54c1324..e5a68b94 100644
--- a/assets/js/components/task-move-position.js
+++ b/assets/js/components/task-move-position.js
@@ -74,8 +74,6 @@ KB.component('task-move-position', function (containerElement, options) {
"column_id": getColumnId(),
"swimlane_id": getSwimlaneId(),
"position": position
- }).success(function () {
- window.location.reload(true);
}).error(function (response) {
if (response) {
onError(response.message);
@@ -148,9 +146,11 @@ KB.component('task-move-position', function (containerElement, options) {
this.render = function () {
KB.on('modal.submit', onSubmit);
+ KB.on('modal.close', function () {
+ KB.removeListener('modal.submit', onSubmit);
+ });
var form = KB.dom('div')
- .on('submit', onSubmit)
.add(KB.dom('div').attr('id', 'message-container').build())
.add(KB.html.label(options.swimlaneLabel, 'form-swimlanes'))
.add(buildSwimlaneSelect())
diff --git a/assets/js/core/base.js b/assets/js/core/base.js
index d304d8bd..6bfe22ba 100644
--- a/assets/js/core/base.js
+++ b/assets/js/core/base.js
@@ -6,7 +6,7 @@ var KB = {
listeners: {
clicks: {},
changes: {},
- keys: {},
+ keys: [],
internals: {}
}
};
@@ -22,8 +22,16 @@ KB.on = function (eventType, callback) {
KB.trigger = function (eventType, eventData) {
if (this.listeners.internals.hasOwnProperty(eventType)) {
for (var i = 0; i < this.listeners.internals[eventType].length; i++) {
- if (! this.listeners.internals[eventType][i](eventData)) {
- break;
+ this.listeners.internals[eventType][i](eventData);
+ }
+ }
+};
+
+KB.removeListener = function (eventType, callback) {
+ if (this.listeners.internals.hasOwnProperty(eventType)) {
+ for (var i = 0; i < this.listeners.internals[eventType].length; i++) {
+ if (this.listeners.internals[eventType][i] === callback) {
+ this.listeners.internals[eventType].splice(i, 1);
}
}
}
@@ -37,12 +45,19 @@ KB.onChange = function (selector, callback) {
this.listeners.changes[selector] = callback;
};
-KB.onKey = function (key, callback) {
- this.listeners.keys[key] = callback;
+KB.onKey = function (combination, callback, ignoreInputField, ctrlKey, metaKey) {
+ this.listeners.keys.push({
+ 'combination': combination,
+ 'callback': callback,
+ 'ignoreInputField': ignoreInputField || false,
+ 'ctrlKey': ctrlKey || false,
+ 'metaKey': metaKey || false
+ });
};
KB.listen = function () {
var self = this;
+ var keysQueue = [];
function onClick(e) {
for (var selector in self.listeners.clicks) {
@@ -61,28 +76,48 @@ KB.listen = function () {
}
}
- function onKeypress(e) {
- var key = (typeof e.which === 'number') ? e.which : e.keyCode;
- var element = e.target;
+ function onKeyPressed(e) {
+ var key = KB.utils.getKey(e);
+ var isInputField = KB.utils.isInputField(e);
- if (element.tagName === 'INPUT' ||
- element.tagName === 'SELECT' ||
- element.tagName === 'TEXTAREA' ||
- element.isContentEditable) {
- return;
+ if (! isInputField || ['Escape', 'Enter'].indexOf(key) !== -1) {
+ keysQueue.push(key);
}
- for (var keyMap in self.listeners.keys) {
- if (self.listeners.keys.hasOwnProperty(keyMap) && key === parseInt(keyMap)) {
- e.preventDefault();
- self.listeners.keys[key](e);
+ if (keysQueue.length > 0) {
+ var reset = true;
+
+ for (var i = 0; i < self.listeners.keys.length; i++) {
+ var params = self.listeners.keys[i];
+ var combination = params.combination;
+ var sequence = combination.split('+');
+
+ if (KB.utils.arraysIdentical(keysQueue, sequence) &&
+ e.ctrlKey === params.ctrlKey && e.metaKey === params.metaKey) {
+ if (isInputField && !params.ignoreInputField) {
+ keysQueue = [];
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+ keysQueue = [];
+ params.callback(e);
+ break;
+ } else if (KB.utils.arraysStartsWith(keysQueue, sequence) && keysQueue.length < sequence.length) {
+ reset = false;
+ }
+ }
+
+ if (reset) {
+ keysQueue = [];
}
}
}
document.addEventListener('click', onClick, false);
document.addEventListener('change', onChange, false);
- document.addEventListener('keypress', onKeypress, false);
+ window.addEventListener('keydown', onKeyPressed, false);
};
KB.component = function (name, object) {
diff --git a/assets/js/core/bootstrap.js b/assets/js/core/bootstrap.js
index 3af086f1..7baa9e76 100644
--- a/assets/js/core/bootstrap.js
+++ b/assets/js/core/bootstrap.js
@@ -2,4 +2,5 @@
document.addEventListener('DOMContentLoaded', function () {
KB.render();
KB.listen();
+ KB.keyboardShortcuts();
});
diff --git a/assets/js/core/dom.js b/assets/js/core/dom.js
index 2c44de58..250a1f78 100644
--- a/assets/js/core/dom.js
+++ b/assets/js/core/dom.js
@@ -4,10 +4,12 @@ KB.dom = function (tag) {
var element = typeof tag === 'string' ? document.createElement(tag) : tag;
this.attr = function (attribute, value) {
- if (value !== null) {
+ if (value !== null && typeof value !== 'undefined') {
element.setAttribute(attribute, value);
+ return this;
+ } else {
+ return element.getAttribute(attribute);
}
- return this;
};
this.data = function (attribute, value) {
@@ -86,6 +88,11 @@ KB.dom = function (tag) {
return this;
};
+ this.replaceText = function (text) {
+ element.textContent = text;
+ return this;
+ };
+
this.addClass = function (className) {
element.classList.add(className);
return this;
@@ -120,6 +127,13 @@ KB.dom = function (tag) {
return this;
};
+ this.empty = function () {
+ while (element.firstChild) {
+ element.removeChild(element.firstChild);
+ }
+ return this;
+ };
+
this.parent = function (selector) {
for (; element && element !== document; element = element.parentNode) {
if (element.matches(selector)) {
@@ -175,3 +189,15 @@ KB.find = function (selector) {
return null;
};
+
+KB.exists = function (selector) {
+ return !!document.querySelector(selector);
+};
+
+KB.focus = function (selector) {
+ var element = document.querySelector(selector);
+
+ if (element) {
+ return element.focus();
+ }
+};
diff --git a/assets/js/core/http.js b/assets/js/core/http.js
index b965ad23..745435cc 100644
--- a/assets/js/core/http.js
+++ b/assets/js/core/http.js
@@ -3,11 +3,24 @@ KB.http.request = function (method, url, headers, body) {
var errorCallback = function() {};
function parseResponse(request) {
- try {
- return JSON.parse(request.responseText);
- } catch (e) {
- return request.responseText;
+ var redirect = request.getResponseHeader('X-Ajax-Redirect');
+ var location = request.getResponseHeader('Location');
+
+ if (redirect === 'self') {
+ window.location.reload();
+ } else if (redirect && redirect.indexOf('#') > -1) {
+ window.location = redirect.split('#')[0];
+ } else if (redirect) {
+ window.location = redirect;
+ } else if (location) {
+ window.location = location;
+ } else if (request.getResponseHeader('Content-Type') === 'application/json') {
+ try {
+ return JSON.parse(request.responseText);
+ } catch (e) {}
}
+
+ return request.responseText;
}
this.execute = function () {
@@ -64,3 +77,20 @@ KB.http.postJson = function (url, body) {
return (new KB.http.request('POST', url, headers, JSON.stringify(body))).execute();
};
+
+KB.http.postForm = function (url, formElement) {
+ var formData = new FormData(formElement);
+ return (new KB.http.request('POST', url, {}, formData)).execute();
+};
+
+KB.http.uploadFile = function (url, file, onProgress, onComplete, onError) {
+ var fd = new FormData();
+ fd.append('files[]', file);
+
+ var xhr = new XMLHttpRequest();
+ xhr.upload.addEventListener('progress', onProgress);
+ xhr.upload.addEventListener('load', onComplete);
+ xhr.upload.addEventListener('error', onError);
+ xhr.open('POST', url, true);
+ xhr.send(fd);
+};
diff --git a/assets/js/core/modal.js b/assets/js/core/modal.js
new file mode 100644
index 00000000..0bbd975b
--- /dev/null
+++ b/assets/js/core/modal.js
@@ -0,0 +1,173 @@
+(function () {
+ var isOpen = false;
+
+ function onOverlayClick(e) {
+ if (e.target.matches('#modal-overlay')) {
+ e.stopPropagation();
+ e.preventDefault();
+ destroy();
+ }
+ }
+
+ function onCloseButtonClick() {
+ KB.trigger('modal.close');
+ }
+
+ function onFormSubmit() {
+ KB.trigger('modal.loading');
+ submitForm();
+ }
+
+ function getForm() {
+ return document.querySelector('#modal-content form:not(.js-modal-ignore-form)');
+ }
+
+ function submitForm() {
+ var form = getForm();
+
+ if (form) {
+ var url = form.getAttribute('action');
+
+ if (url) {
+ KB.http.postForm(url, form).success(function (response) {
+ KB.trigger('modal.stop');
+
+ if (response) {
+ replace(response);
+ } else {
+ destroy();
+ }
+ });
+ }
+ }
+ }
+
+ function afterRendering() {
+ var formElement = KB.find('#modal-content form');
+ if (formElement) {
+ formElement.on('submit', onFormSubmit, false);
+ }
+
+ var autoFocusElement = document.querySelector('#modal-content input[autofocus]');
+ if (autoFocusElement) {
+ autoFocusElement.focus();
+ }
+
+ KB.render();
+ _KB.datePicker();
+ _KB.autoComplete();
+ _KB.tagAutoComplete();
+ _KB.get('Task').onPopoverOpened();
+ }
+
+ function replace(html) {
+ var contentElement = KB.find('#modal-content');
+
+ if (contentElement) {
+ contentElement.replace(KB.dom('div')
+ .attr('id', 'modal-content')
+ .html(html)
+ .build()
+ );
+
+ afterRendering();
+ }
+ }
+
+ function create(html, width, overlayClickDestroy) {
+ var closeButtonElement = KB.dom('a')
+ .attr('href', '#')
+ .attr('id', 'modal-close-button')
+ .html('<i class="fa fa-times"></i>')
+ .click(onCloseButtonClick)
+ .build();
+
+ var headerElement = KB.dom('div')
+ .attr('id', 'modal-header')
+ .add(closeButtonElement)
+ .build();
+
+ var contentElement = KB.dom('div')
+ .attr('id', 'modal-content')
+ .html(html)
+ .build();
+
+ var boxElement = KB.dom('div')
+ .attr('id', 'modal-box')
+ .style('width', width)
+ .add(headerElement)
+ .add(contentElement)
+ .build();
+
+ var overlayElement = KB.dom('div')
+ .attr('id', 'modal-overlay')
+ .add(boxElement)
+ .build();
+
+ if (overlayClickDestroy) {
+ overlayElement.addEventListener('click', onOverlayClick, false);
+ }
+
+ document.body.appendChild(overlayElement);
+ afterRendering();
+ }
+
+ function destroy() {
+ isOpen = false;
+ var overlayElement = KB.find('#modal-overlay');
+
+ if (overlayElement) {
+ overlayElement.remove();
+ }
+ }
+
+ function getWidth(size) {
+ var viewport = KB.utils.getViewportSize();
+
+ switch (size) {
+ case 'large':
+ return viewport.width < 1350 ? '98%' : '1350px';
+ case 'medium':
+ return viewport.width < 1024 ? '70%' : '1024px';
+ }
+
+ return viewport.width < 800 ? '75%' : '800px';
+ }
+
+ KB.on('modal.close', function () {
+ destroy();
+ });
+
+ KB.on('modal.submit', function () {
+ submitForm();
+ });
+
+ KB.modal = {
+ open: function (url, size, overlayClickDestroy) {
+ _KB.get('Dropdown').close();
+ destroy();
+
+ if (typeof overlayClickDestroy === 'undefined') {
+ overlayClickDestroy = true;
+ }
+
+ KB.http.get(url).success(function (response) {
+ isOpen = true;
+ create(response, getWidth(size), overlayClickDestroy);
+ });
+ },
+ close: function () {
+ destroy();
+ },
+ isOpen: function () {
+ return isOpen;
+ },
+ replace: function (url) {
+ KB.http.get(url).success(function (response) {
+ replace(response);
+ });
+ },
+ getForm: getForm,
+ submitForm: submitForm
+ };
+}());
diff --git a/assets/js/core/utils.js b/assets/js/core/utils.js
index e8e74b17..a3683122 100644
--- a/assets/js/core/utils.js
+++ b/assets/js/core/utils.js
@@ -32,3 +32,65 @@ KB.utils.getSelectionPosition = function (element) {
selectionEnd: selectionEnd
};
};
+
+KB.utils.arraysIdentical = function (a, b) {
+ var i = a.length;
+
+ if (i !== b.length) {
+ return false;
+ }
+
+ while (i--) {
+ if (a[i] !== b[i]) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+KB.utils.arraysStartsWith = function (array1, array2) {
+ var length = Math.min(array1.length, array2.length);
+
+ for (var i = 0; i < length; i++) {
+ if (array1[i] !== array2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+KB.utils.isInputField = function (event) {
+ var element = event.target;
+
+ return !!(element.tagName === 'INPUT' ||
+ element.tagName === 'SELECT' ||
+ element.tagName === 'TEXTAREA' ||
+ element.isContentEditable);
+};
+
+KB.utils.getKey = function (e) {
+ var mapping = {
+ 'Esc': 'Escape',
+ 'Up': 'ArrowUp',
+ 'Down': 'ArrowDown',
+ 'Left': 'ArrowLeft',
+ 'Right': 'ArrowRight'
+ };
+
+ for (var key in mapping) {
+ if (mapping.hasOwnProperty(key) && key === e.key) {
+ return mapping[key];
+ }
+ }
+
+ return e.key;
+};
+
+KB.utils.getViewportSize = function () {
+ return {
+ width: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
+ height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
+ };
+};
diff --git a/assets/js/polyfills/event_key.js b/assets/js/polyfills/event_key.js
new file mode 100644
index 00000000..cd1191f5
--- /dev/null
+++ b/assets/js/polyfills/event_key.js
@@ -0,0 +1,113 @@
+(function () {
+
+ var keyboardeventKeyPolyfill = {
+ polyfill: polyfill,
+ keys: {
+ 3: 'Cancel',
+ 6: 'Help',
+ 8: 'Backspace',
+ 9: 'Tab',
+ 12: 'Clear',
+ 13: 'Enter',
+ 16: 'Shift',
+ 17: 'Control',
+ 18: 'Alt',
+ 19: 'Pause',
+ 20: 'CapsLock',
+ 27: 'Escape',
+ 28: 'Convert',
+ 29: 'NonConvert',
+ 30: 'Accept',
+ 31: 'ModeChange',
+ 32: ' ',
+ 33: 'PageUp',
+ 34: 'PageDown',
+ 35: 'End',
+ 36: 'Home',
+ 37: 'ArrowLeft',
+ 38: 'ArrowUp',
+ 39: 'ArrowRight',
+ 40: 'ArrowDown',
+ 41: 'Select',
+ 42: 'Print',
+ 43: 'Execute',
+ 44: 'PrintScreen',
+ 45: 'Insert',
+ 46: 'Delete',
+ 48: ['0', ')'],
+ 49: ['1', '!'],
+ 50: ['2', '@'],
+ 51: ['3', '#'],
+ 52: ['4', '$'],
+ 53: ['5', '%'],
+ 54: ['6', '^'],
+ 55: ['7', '&'],
+ 56: ['8', '*'],
+ 57: ['9', '('],
+ 91: 'OS',
+ 93: 'ContextMenu',
+ 144: 'NumLock',
+ 145: 'ScrollLock',
+ 181: 'VolumeMute',
+ 182: 'VolumeDown',
+ 183: 'VolumeUp',
+ 186: [';', ':'],
+ 187: ['=', '+'],
+ 188: [',', '<'],
+ 189: ['-', '_'],
+ 190: ['.', '>'],
+ 191: ['/', '?'],
+ 192: ['`', '~'],
+ 219: ['[', '{'],
+ 220: ['\\', '|'],
+ 221: [']', '}'],
+ 222: ["'", '"'],
+ 224: 'Meta',
+ 225: 'AltGraph',
+ 246: 'Attn',
+ 247: 'CrSel',
+ 248: 'ExSel',
+ 249: 'EraseEof',
+ 250: 'Play',
+ 251: 'ZoomOut'
+ }
+ };
+
+ // Function keys (F1-24).
+ var i;
+ for (i = 1; i < 25; i++) {
+ keyboardeventKeyPolyfill.keys[111 + i] = 'F' + i;
+ }
+
+ // Printable ASCII characters.
+ var letter = '';
+ for (i = 65; i < 91; i++) {
+ letter = String.fromCharCode(i);
+ keyboardeventKeyPolyfill.keys[i] = [letter.toLowerCase(), letter.toUpperCase()];
+ }
+
+ function polyfill() {
+ if (!('KeyboardEvent' in window) ||
+ 'key' in KeyboardEvent.prototype) {
+ return false;
+ }
+
+ // Polyfill `key` on `KeyboardEvent`.
+ var proto = {
+ get: function (x) {
+ var key = keyboardeventKeyPolyfill.keys[this.which || this.keyCode];
+
+ if (Array.isArray(key)) {
+ key = key[+this.shiftKey];
+ }
+
+ return key;
+ }
+ };
+ Object.defineProperty(KeyboardEvent.prototype, 'key', proto);
+ return proto;
+ }
+
+ keyboardeventKeyPolyfill.polyfill();
+
+})();
diff --git a/assets/js/src/App.js b/assets/js/src/App.js
index d4950fb3..9aa97061 100644
--- a/assets/js/src/App.js
+++ b/assets/js/src/App.js
@@ -23,52 +23,15 @@ Kanboard.App.prototype.execute = function() {
if (typeof controller.focus === "function") {
controller.focus();
}
-
- if (typeof controller.keyboardShortcuts === "function") {
- controller.keyboardShortcuts();
- }
}
}
this.focus();
- this.keyboardShortcuts();
this.datePicker();
this.autoComplete();
this.tagAutoComplete();
};
-Kanboard.App.prototype.keyboardShortcuts = function() {
- var self = this;
-
- // Submit form
- Mousetrap.bindGlobal("mod+enter", function() {
- var forms = $("form");
-
- if (forms.length == 1) {
- forms.submit();
- } else if (forms.length > 1) {
- if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
- $(document.activeElement).parents("form").submit();
- } else if (self.get("Popover").isOpen()) {
- $("#popover-container form").submit();
- }
- }
- });
-
- // Close popover and dropdown
- Mousetrap.bindGlobal("esc", function() {
- if (! document.getElementById('suggest-menu')) {
- self.get("Popover").close();
- self.get("Dropdown").close();
- }
- });
-
- // Show keyboard shortcut
- Mousetrap.bind("?", function() {
- self.get("Popover").open($("body").data("keyboard-shortcut-url"));
- });
-};
-
Kanboard.App.prototype.focus = function() {
// Auto-select input fields
$(document).on('focus', '.auto-select', function() {
diff --git a/assets/js/src/BoardCollapsedMode.js b/assets/js/src/BoardCollapsedMode.js
index 8365d3fb..1be7a150 100644
--- a/assets/js/src/BoardCollapsedMode.js
+++ b/assets/js/src/BoardCollapsedMode.js
@@ -2,16 +2,6 @@ Kanboard.BoardCollapsedMode = function(app) {
this.app = app;
};
-Kanboard.BoardCollapsedMode.prototype.keyboardShortcuts = function() {
- var self = this;
-
- if (self.app.hasId("board")) {
- Mousetrap.bind("s", function() {
- self.toggle();
- });
- }
-};
-
Kanboard.BoardCollapsedMode.prototype.toggle = function() {
var self = this;
this.app.showLoadingIcon();
diff --git a/assets/js/src/BoardHorizontalScrolling.js b/assets/js/src/BoardHorizontalScrolling.js
index d4c3aaf3..cd4d0d76 100644
--- a/assets/js/src/BoardHorizontalScrolling.js
+++ b/assets/js/src/BoardHorizontalScrolling.js
@@ -17,16 +17,6 @@ Kanboard.BoardHorizontalScrolling.prototype.listen = function() {
});
};
-Kanboard.BoardHorizontalScrolling.prototype.keyboardShortcuts = function() {
- var self = this;
-
- if (self.app.hasId("board")) {
- Mousetrap.bind("c", function () {
- self.toggle();
- });
- }
-};
-
Kanboard.BoardHorizontalScrolling.prototype.onBoardRendered = function() {
this.render();
};
diff --git a/assets/js/src/BoardTask.js b/assets/js/src/BoardTask.js
index 2b8ac132..8a0577d9 100644
--- a/assets/js/src/BoardTask.js
+++ b/assets/js/src/BoardTask.js
@@ -2,13 +2,14 @@ Kanboard.BoardTask = function(app) {
this.app = app;
};
+// TODO: rewrite this code
Kanboard.BoardTask.prototype.listen = function() {
var self = this;
$(document).on("click", ".task-board-change-assignee", function(e) {
e.preventDefault();
e.stopPropagation();
- self.app.get("Popover").open($(this).data('url'));
+ KB.modal.open($(this).data("url"), "medium", false);
});
$(document).on("click", ".task-board", function(e) {
@@ -17,13 +18,3 @@ Kanboard.BoardTask.prototype.listen = function() {
}
});
};
-
-Kanboard.BoardTask.prototype.keyboardShortcuts = function() {
- var self = this;
-
- if (self.app.hasId("board")) {
- Mousetrap.bind("n", function () {
- self.app.get("Popover").open($("#board").data("task-creation-url"));
- });
- }
-};
diff --git a/assets/js/src/Dropdown.js b/assets/js/src/Dropdown.js
index d97b925e..ec033b3e 100644
--- a/assets/js/src/Dropdown.js
+++ b/assets/js/src/Dropdown.js
@@ -2,6 +2,7 @@ Kanboard.Dropdown = function(app) {
this.app = app;
};
+// TODO: rewrite this code
Kanboard.Dropdown.prototype.listen = function() {
var self = this;
@@ -9,10 +10,6 @@ Kanboard.Dropdown.prototype.listen = function() {
self.close();
});
- $(document).on('click', '#popover-content', function() {
- self.close();
- });
-
$(document).on('click', '.dropdown-menu', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
@@ -56,7 +53,3 @@ Kanboard.Dropdown.prototype.listen = function() {
Kanboard.Dropdown.prototype.close = function() {
$("#dropdown").remove();
};
-
-Kanboard.Dropdown.prototype.onPopoverOpened = function() {
- this.close();
-};
diff --git a/assets/js/src/FileUpload.js b/assets/js/src/FileUpload.js
deleted file mode 100644
index f53b9bf8..00000000
--- a/assets/js/src/FileUpload.js
+++ /dev/null
@@ -1,125 +0,0 @@
-Kanboard.FileUpload = function(app) {
- this.app = app;
- this.files = [];
- this.currentFile = 0;
-};
-
-Kanboard.FileUpload.prototype.onPopoverOpened = function() {
- var dropzone = document.getElementById("file-dropzone");
- var self = this;
-
- if (dropzone) {
- dropzone.ondragover = dropzone.ondragenter = function(e) {
- e.stopPropagation();
- e.preventDefault();
- };
-
- dropzone.ondrop = function(e) {
- e.stopPropagation();
- e.preventDefault();
- self.files = e.dataTransfer.files;
- self.show();
- $("#file-error-max-size").hide();
- };
-
- $(document).on("click", "#file-browser", function(e) {
- e.preventDefault();
- $("#file-form-element").get(0).click();
- });
-
- $(document).on("click", "#file-upload-button", function(e) {
- e.preventDefault();
- self.currentFile = 0;
- self.checkFiles();
- });
-
- $("#file-form-element").change(function() {
- self.files = document.getElementById("file-form-element").files;
- self.show();
- $("#file-error-max-size").hide();
- });
- }
-};
-
-Kanboard.FileUpload.prototype.show = function() {
- $("#file-list").remove();
-
- if (this.files.length > 0) {
- $("#file-upload-button").prop("disabled", false);
- $("#file-dropzone-inner").hide();
-
- var ul = jQuery("<ul>", {"id": "file-list"});
-
- for (var i = 0; i < this.files.length; i++) {
- var percentage = jQuery("<span>", {"id": "file-percentage-" + i}).append("(0%)");
- var progress = jQuery("<progress>", {"id": "file-progress-" + i, "value": 0});
- var li = jQuery("<li>", {"id": "file-label-" + i})
- .append(progress)
- .append("&nbsp;")
- .append(this.files[i].name)
- .append("&nbsp;")
- .append(percentage);
-
- ul.append(li);
- }
-
- $("#file-dropzone").append(ul);
- } else {
- $("#file-dropzone-inner").show();
- }
-};
-
-Kanboard.FileUpload.prototype.checkFiles = function() {
- var max = parseInt($("#file-dropzone").data("max-size"));
-
- for (var i = 0; i < this.files.length; i++) {
- if (this.files[i].size > max) {
- $("#file-error-max-size").show();
- $("#file-label-" + i).addClass("file-error");
- $("#file-upload-button").prop("disabled", true);
- return;
- }
- }
-
- this.uploadFiles();
-};
-
-Kanboard.FileUpload.prototype.uploadFiles = function() {
- if (this.files.length > 0) {
- this.uploadFile(this.files[this.currentFile]);
- }
-};
-
-Kanboard.FileUpload.prototype.uploadFile = function(file) {
- var dropzone = document.getElementById("file-dropzone");
- var url = dropzone.dataset.url;
- var xhr = new XMLHttpRequest();
- var fd = new FormData();
-
- xhr.upload.addEventListener("progress", this.updateProgress.bind(this));
- xhr.upload.addEventListener("load", this.transferComplete.bind(this));
-
- xhr.open("POST", url, true);
- fd.append('files[]', file);
- xhr.send(fd);
-};
-
-Kanboard.FileUpload.prototype.updateProgress = function(e) {
- if (e.lengthComputable) {
- $("#file-progress-" + this.currentFile).val(e.loaded / e.total);
- $("#file-percentage-" + this.currentFile).text('(' + Math.floor((e.loaded / e.total) * 100) + '%)');
- }
-};
-
-Kanboard.FileUpload.prototype.transferComplete = function() {
- this.currentFile++;
-
- if (this.currentFile < this.files.length) {
- this.uploadFile(this.files[this.currentFile]);
- } else {
- var uploadButton = $("#file-upload-button");
- uploadButton.prop("disabled", true);
- uploadButton.parent().hide();
- $("#file-done").show();
- }
-};
diff --git a/assets/js/src/Popover.js b/assets/js/src/Popover.js
deleted file mode 100644
index ab71505a..00000000
--- a/assets/js/src/Popover.js
+++ /dev/null
@@ -1,161 +0,0 @@
-Kanboard.Popover = function(app) {
- this.app = app;
-};
-
-Kanboard.Popover.prototype.listen = function() {
- var self = this;
-
- $(document).on("click", ".popover", function(e) {
- self.onClick(e);
- });
-
- $(document).on("click", ".close-popover", function(e) {
- self.close(e);
- });
-
- $(document).on("click", "#popover-close-button", function(e) {
- self.close(e);
- });
-
- $(document).on("click", "#popover-content", function(e) {
- e.stopPropagation();
- });
-};
-
-Kanboard.Popover.prototype.onClick = function(e) {
- e.preventDefault();
- e.stopPropagation();
-
- var target = e.currentTarget || e.target;
- var link = target.getAttribute("href");
-
- if (! link) {
- link = target.getAttribute("data-href");
- }
-
- if (link) {
- this.open(link);
- }
-};
-
-Kanboard.Popover.prototype.isOpen = function() {
- return $('#popover-container').size() > 0;
-};
-
-Kanboard.Popover.prototype.open = function(link) {
- var self = this;
-
- if (!self.isOpen()) {
- $.get(link, function(content) {
- $("body").prepend(
- '<div id="popover-container">' +
- '<div id="popover-content">' +
- '<div id="popover-content-header"><a href="#" id="popover-close-button"><i class="fa fa-times"></i></a></div>' +
- content +
- '</div>' +
- '</div>'
- );
-
- self.executeOnOpenedListeners();
- });
- }
-};
-
-Kanboard.Popover.prototype.close = function(e) {
- if (this.isOpen()) {
- if (e) {
- e.preventDefault();
- }
-
- $("#popover-container").remove();
- this.executeOnClosedListeners();
- }
-};
-
-Kanboard.Popover.prototype.ajaxReload = function(data, request, self) {
- var redirect = request.getResponseHeader("X-Ajax-Redirect");
-
- if (redirect === 'self') {
- window.location.reload();
- } else if (redirect && redirect.indexOf('#') > -1) {
- window.location = redirect.split('#')[0];
- } else if (redirect) {
- window.location = redirect;
- } else {
- $("#popover-content").html(data);
- $("#popover-content input[autofocus]").focus();
- self.executeOnOpenedListeners();
- }
-};
-
-Kanboard.Popover.prototype.executeOnOpenedListeners = function() {
- for (var className in this.app.controllers) {
- var controller = this.app.get(className);
-
- if (typeof controller.onPopoverOpened === "function") {
- controller.onPopoverOpened();
- }
- }
-
- this.afterOpen();
-};
-
-Kanboard.Popover.prototype.executeOnClosedListeners = function() {
- for (var className in this.app.controllers) {
- var controller = this.app.get(className);
-
- if (typeof controller.onPopoverClosed === "function") {
- controller.onPopoverClosed();
- }
- }
-};
-
-Kanboard.Popover.prototype.afterOpen = function() {
- var self = this;
- var popoverForm = $("#popover-content .popover-form");
-
- // Submit forms with Ajax request
- if (popoverForm) {
- popoverForm.on("submit", function(e) {
- e.preventDefault();
-
- $.ajax({
- type: "POST",
- url: popoverForm.attr("action"),
- data: popoverForm.serialize(),
- success: function(data, textStatus, request) {
- self.ajaxReload(data, request, self);
- },
- beforeSend: function() {
- var button = $('.popover-form button[type="submit"]');
- button.html('<i class="fa fa-spinner fa-pulse"></i> ' + button.html());
- button.attr("disabled", true);
- }
- });
- });
- }
-
- // Submit link with Ajax request
- $(document).on("click", ".popover-link", function(e) {
- e.preventDefault();
-
- $.ajax({
- type: "GET",
- url: $(this).attr("href"),
- success: function(data, textStatus, request) {
- self.ajaxReload(data, request, self);
- }
- });
- });
-
- // Autofocus fields (html5 autofocus works only with page onload)
- $("#popover-content input[autofocus]").each(function() {
- $(this).focus();
- });
-
- this.app.datePicker();
- this.app.autoComplete();
- this.app.tagAutoComplete();
-
- KB.render();
-};
diff --git a/assets/js/src/Screenshot.js b/assets/js/src/Screenshot.js
deleted file mode 100644
index 4f69e9c3..00000000
--- a/assets/js/src/Screenshot.js
+++ /dev/null
@@ -1,134 +0,0 @@
-Kanboard.Screenshot = function(app) {
- this.app = app;
- this.pasteCatcher = null;
-};
-
-Kanboard.Screenshot.prototype.onPopoverOpened = function() {
- if (this.app.hasId("screenshot-zone")) {
- this.initialize();
- }
-};
-
-// Setup event listener and workarounds
-Kanboard.Screenshot.prototype.initialize = function() {
- this.destroy();
-
- if (! window.Clipboard) {
-
- // Create a contenteditable element
- this.pasteCatcher = document.createElement("div");
- this.pasteCatcher.id = "screenshot-pastezone";
- this.pasteCatcher.contentEditable = "true";
-
- // Insert the content editable at the top to avoid scrolling down in the board view
- this.pasteCatcher.style.opacity = 0;
- this.pasteCatcher.style.position = "fixed";
- this.pasteCatcher.style.top = 0;
- this.pasteCatcher.style.right = 0;
- this.pasteCatcher.style.width = 0;
-
- document.body.insertBefore(this.pasteCatcher, document.body.firstChild);
-
- // Set focus on the contenteditable element
- this.pasteCatcher.focus();
-
- // Set the focus when clicked anywhere in the document
- document.addEventListener("click", this.setFocus.bind(this));
-
- // Set the focus when clicked in screenshot dropzone (popover)
- document.getElementById("screenshot-zone").addEventListener("click", this.setFocus.bind(this));
- }
-
- window.addEventListener("paste", this.pasteHandler.bind(this));
-};
-
-// Destroy contentEditable element
-Kanboard.Screenshot.prototype.destroy = function() {
- if (this.pasteCatcher !== null) {
- document.body.removeChild(this.pasteCatcher);
- }
- else if (document.getElementById("screenshot-pastezone")) {
- document.body.removeChild(document.getElementById("screenshot-pastezone"));
- }
-
- document.removeEventListener("click", this.setFocus.bind(this));
- this.pasteCatcher = null;
-};
-
-// Set focus on contentEditable element
-Kanboard.Screenshot.prototype.setFocus = function() {
- if (this.pasteCatcher !== null) {
- this.pasteCatcher.focus();
- }
-};
-
-// Paste event callback
-Kanboard.Screenshot.prototype.pasteHandler = function(e) {
- // Firefox doesn't have the property e.clipboardData.items (only Chrome)
- if (e.clipboardData && e.clipboardData.items) {
-
- var items = e.clipboardData.items;
-
- if (items) {
-
- for (var i = 0; i < items.length; i++) {
-
- // Find an image in pasted elements
- if (items[i].type.indexOf("image") !== -1) {
-
- var blob = items[i].getAsFile();
-
- // Get the image as base64 data
- var reader = new FileReader();
- var self = this;
- reader.onload = function(event) {
- self.createImage(event.target.result);
- };
-
- reader.readAsDataURL(blob);
- }
- }
- }
- }
- else {
-
- // Handle Firefox
- setTimeout(this.checkInput.bind(this), 100);
- }
-};
-
-// Parse the input in the paste catcher element
-Kanboard.Screenshot.prototype.checkInput = function() {
- var child = this.pasteCatcher.childNodes[0];
-
- if (child) {
- // If the user pastes an image, the src attribute
- // will represent the image as a base64 encoded string.
- if (child.tagName === "IMG") {
- this.createImage(child.src);
- }
- }
-
- this.pasteCatcher.innerHTML = "";
-};
-
-// Creates a new image from a given source
-Kanboard.Screenshot.prototype.createImage = function(blob) {
- var pastedImage = new Image();
- pastedImage.src = blob;
-
- // Send the image content to the form variable
- pastedImage.onload = function() {
- var sourceSplit = blob.split("base64,");
- var sourceString = sourceSplit[1];
- $("input[name=screenshot]").val(sourceString);
- };
-
- var zone = document.getElementById("screenshot-zone");
- zone.innerHTML = "";
- zone.className = "screenshot-pasted";
- zone.appendChild(pastedImage);
-
- this.destroy();
- this.initialize();
-};
diff --git a/assets/js/src/Search.js b/assets/js/src/Search.js
index f6409f54..b61710a4 100644
--- a/assets/js/src/Search.js
+++ b/assets/js/src/Search.js
@@ -15,6 +15,7 @@ Kanboard.Search.prototype.focus = function() {
});
};
+// TODO: rewrite this code
Kanboard.Search.prototype.listen = function() {
$(document).on("click", ".filter-helper", function (e) {
e.preventDefault();
@@ -38,60 +39,3 @@ Kanboard.Search.prototype.listen = function() {
$("form.search").submit();
});
};
-
-Kanboard.Search.prototype.goToView = function(label) {
- var link = $(label);
-
- if (link.length) {
- window.location = link.attr('href');
- }
-};
-
-Kanboard.Search.prototype.keyboardShortcuts = function() {
- var self = this;
-
- // Switch view mode for projects: go to the overview page
- Mousetrap.bind("v o", function() {
- self.goToView(".view-overview");
- });
-
- // Switch view mode for projects: go to the board
- Mousetrap.bind("v b", function() {
- self.goToView(".view-board");
- });
-
- // Switch view mode for projects: go to the calendar
- Mousetrap.bind("v c", function() {
- self.goToView(".view-calendar");
- });
-
- // Switch view mode for projects: go to the listing
- Mousetrap.bind("v l", function() {
- self.goToView(".view-listing");
- });
-
- // Switch view mode for projects: go to the gantt chart
- Mousetrap.bind("v g", function() {
- self.goToView(".view-gantt");
- });
-
- // Focus to the search field
- Mousetrap.bind("f", function(e) {
- e.preventDefault();
- var input = document.getElementById("form-search");
-
- if (input) {
- input.focus();
- }
- });
-
- // Reset to the search field
- Mousetrap.bind("r", function(e) {
- e.preventDefault();
- var reset = $(".filter-reset").data("filter");
- var input = $("#form-search");
-
- input.val(reset);
- $("form.search").submit();
- });
-};
diff --git a/assets/js/src/Task.js b/assets/js/src/Task.js
index 06419207..19cf39e8 100644
--- a/assets/js/src/Task.js
+++ b/assets/js/src/Task.js
@@ -2,32 +2,9 @@ Kanboard.Task = function(app) {
this.app = app;
};
-Kanboard.Task.prototype.keyboardShortcuts = function() {
- var taskView = $("#task-view");
- var self = this;
-
- if (this.app.hasId("task-view")) {
- Mousetrap.bind("e", function() {
- self.app.get("Popover").open(taskView.data("edit-url"));
- });
-
- Mousetrap.bind("c", function() {
- self.app.get("Popover").open(taskView.data("comment-url"));
- });
-
- Mousetrap.bind("s", function() {
- self.app.get("Popover").open(taskView.data("subtask-url"));
- });
-
- Mousetrap.bind("l", function() {
- self.app.get("Popover").open(taskView.data("internal-link-url"));
- });
- }
-};
-
+// TODO: rewrite this code
Kanboard.Task.prototype.onPopoverOpened = function() {
var self = this;
- var reloadingProjectId = 0;
self.renderColorPicker();
@@ -42,29 +19,6 @@ Kanboard.Task.prototype.onPopoverOpened = function() {
$(dropdownId).val(currentId);
}
});
-
- // Reload page when a destination project is changed
- $(document).on("change", "select.task-reload-project-destination", function() {
- if (reloadingProjectId > 0) {
- $(this).val(reloadingProjectId);
- }
- else {
- reloadingProjectId = $(this).val();
- var url = $(this).data("redirect").replace(/PROJECT_ID/g, reloadingProjectId);
-
- $(".loading-icon").show();
-
- $.ajax({
- type: "GET",
- url: url,
- success: function(data, textStatus, request) {
- reloadingProjectId = 0;
- $(".loading-icon").hide();
- self.app.get("Popover").ajaxReload(data, request, self.app.get("Popover"));
- }
- });
- }
- });
};
Kanboard.Task.prototype.renderColorPicker = function() {
diff --git a/assets/js/vendor.min.js b/assets/js/vendor.min.js
index ae214e7f..77d5776e 100644
--- a/assets/js/vendor.min.js
+++ b/assets/js/vendor.min.js
@@ -604,20 +604,6 @@ dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("en-au","en-AU",{clos
monthNamesShort:["Sij","Velj","Ožu","Tra","Svi","Lip","Srp","Kol","Ruj","Lis","Stu","Pro"],dayNames:["Nedjelja","Ponedjeljak","Utorak","Srijeda","Četvrtak","Petak","Subota"],dayNamesShort:["Ned","Pon","Uto","Sri","Čet","Pet","Sub"],dayNamesMin:["Ne","Po","Ut","Sr","Če","Pe","Su"],weekHeader:"Tje",dateFormat:"dd.mm.yy.",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("hr",{buttonText:{month:"Mjesec",week:"Tjedan",day:"Dan",list:"Raspored"},allDayText:"Cijeli dan",eventLimitText:function(e){return"+ još "+e},noEventsMessage:"Nema događaja za prikaz"})}(),function(){!function(){function e(e,a,t,n){var r=e;switch(t){case"s":return n||a?"néhány másodperc":"néhány másodperce";case"m":return"egy"+(n||a?" perc":" perce");case"mm":return r+(n||a?" perc":" perce");case"h":return"egy"+(n||a?" óra":" órája");case"hh":return r+(n||a?" óra":" órája");case"d":return"egy"+(n||a?" nap":" napja");case"dd":return r+(n||a?" nap":" napja");case"M":return"egy"+(n||a?" hónap":" hónapja");case"MM":return r+(n||a?" hónap":" hónapja");case"y":return"egy"+(n||a?" év":" éve");case"yy":return r+(n||a?" év":" éve")}return""}function t(e){return(e?"":"[múlt] ")+"["+n[this.day()]+"] LT[-kor]"}var n="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" "),r=a.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec".split("_"),weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,a,t){return e<12?t===!0?"de":"DE":t===!0?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return t.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return t.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:e,m:e,mm:e,h:e,hh:e,d:e,dd:e,M:e,MM:e,y:e,yy:e},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return r}(),e.fullCalendar.datepickerLocale("hu","hu",{closeText:"bezár",prevText:"vissza",nextText:"előre",currentText:"ma",monthNames:["Január","Február","Március","Április","Május","Június","Július","Augusztus","Szeptember","Október","November","December"],monthNamesShort:["Jan","Feb","Már","Ápr","Máj","Jún","Júl","Aug","Szep","Okt","Nov","Dec"],dayNames:["Vasárnap","Hétfő","Kedd","Szerda","Csütörtök","Péntek","Szombat"],dayNamesShort:["Vas","Hét","Ked","Sze","Csü","Pén","Szo"],dayNamesMin:["V","H","K","Sze","Cs","P","Szo"],weekHeader:"Hét",dateFormat:"yy.mm.dd.",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:""}),e.fullCalendar.locale("hu",{buttonText:{month:"Hónap",week:"Hét",day:"Nap",list:"Napló"},allDayText:"Egész nap",eventLimitText:"további",noEventsMessage:"Nincs megjeleníthető események"})}(),function(){!function(){var e=a.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"siang"===a?e>=11?e:e+12:"sore"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}});return e}(),e.fullCalendar.datepickerLocale("id","id",{closeText:"Tutup",prevText:"&#x3C;mundur",nextText:"maju&#x3E;",currentText:"hari ini",monthNames:["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember"],monthNamesShort:["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agus","Sep","Okt","Nop","Des"],dayNames:["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"],dayNamesShort:["Min","Sen","Sel","Rab","kam","Jum","Sab"],dayNamesMin:["Mg","Sn","Sl","Rb","Km","jm","Sb"],weekHeader:"Mg",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("id",{buttonText:{month:"Bulan",week:"Minggu",day:"Hari",list:"Agenda"},allDayHtml:"Sehari<br/>penuh",eventLimitText:"lebih",noEventsMessage:"Tidak ada acara untuk ditampilkan"})}(),function(){!function(){function e(e){return e%100===11||e%10!==1}function t(a,t,n,r){var s=a+" ";switch(n){case"s":return t||r?"nokkrar sekúndur":"nokkrum sekúndum";case"m":return t?"mínúta":"mínútu";case"mm":return e(a)?s+(t||r?"mínútur":"mínútum"):t?s+"mínúta":s+"mínútu";case"hh":return e(a)?s+(t||r?"klukkustundir":"klukkustundum"):s+"klukkustund";case"d":return t?"dagur":r?"dag":"degi";case"dd":return e(a)?t?s+"dagar":s+(r?"daga":"dögum"):t?s+"dagur":s+(r?"dag":"degi");case"M":return t?"mánuður":r?"mánuð":"mánuði";case"MM":return e(a)?t?s+"mánuðir":s+(r?"mánuði":"mánuðum"):t?s+"mánuður":s+(r?"mánuð":"mánuði");case"y":return t||r?"ár":"ári";case"yy":return e(a)?s+(t||r?"ár":"árum"):s+(t||r?"ár":"ári")}}var n=a.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:t,m:t,mm:t,h:"klukkustund",hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return n}(),e.fullCalendar.datepickerLocale("is","is",{closeText:"Loka",prevText:"&#x3C; Fyrri",nextText:"Næsti &#x3E;",currentText:"Í dag",monthNames:["Janúar","Febrúar","Mars","Apríl","Maí","Júní","Júlí","Ágúst","September","Október","Nóvember","Desember"],monthNamesShort:["Jan","Feb","Mar","Apr","Maí","Jún","Júl","Ágú","Sep","Okt","Nóv","Des"],dayNames:["Sunnudagur","Mánudagur","Þriðjudagur","Miðvikudagur","Fimmtudagur","Föstudagur","Laugardagur"],dayNamesShort:["Sun","Mán","Þri","Mið","Fim","Fös","Lau"],dayNamesMin:["Su","Má","Þr","Mi","Fi","Fö","La"],weekHeader:"Vika",dateFormat:"dd.mm.yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("is",{buttonText:{month:"Mánuður",week:"Vika",day:"Dagur",list:"Dagskrá"},allDayHtml:"Allan<br/>daginn",eventLimitText:"meira",noEventsMessage:"Engir viðburðir til að sýna"})}(),function(){!function(){var e=a.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato".split("_"),weekdaysShort:"Dom_Lun_Mar_Mer_Gio_Ven_Sab".split("_"),weekdaysMin:"Do_Lu_Ma_Me_Gi_Ve_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){switch(this.day()){case 0:return"[la scorsa] dddd [alle] LT";default:return"[lo scorso] dddd [alle] LT"}},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("it","it",{closeText:"Chiudi",prevText:"&#x3C;Prec",nextText:"Succ&#x3E;",currentText:"Oggi",monthNames:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],monthNamesShort:["Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dic"],dayNames:["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato"],dayNamesShort:["Dom","Lun","Mar","Mer","Gio","Ven","Sab"],dayNamesMin:["Do","Lu","Ma","Me","Gi","Ve","Sa"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("it",{buttonText:{month:"Mese",week:"Settimana",day:"Giorno",list:"Agenda"},allDayHtml:"Tutto il<br/>giorno",eventLimitText:function(e){return"+altri "+e},noEventsMessage:"Non ci sono eventi da visualizzare"})}(),function(){!function(){var e=a.defineLocale("ja",{months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"Ah時m分",LTS:"Ah時m分s秒",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah時m分",LLLL:"YYYY年M月D日Ah時m分 dddd"},meridiemParse:/午前|午後/i,isPM:function(e){return"午後"===e},meridiem:function(e,a,t){return e<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:"[来週]dddd LT",lastDay:"[昨日] LT",lastWeek:"[前週]dddd LT",sameElse:"L"},ordinalParse:/\d{1,2}日/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}});return e}(),e.fullCalendar.datepickerLocale("ja","ja",{closeText:"閉じる",prevText:"&#x3C;前",nextText:"次&#x3E;",currentText:"今日",monthNames:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthNamesShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayNames:["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],dayNamesShort:["日","月","火","水","木","金","土"],dayNamesMin:["日","月","火","水","木","金","土"],weekHeader:"週",dateFormat:"yy/mm/dd",firstDay:0,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"年"}),e.fullCalendar.locale("ja",{buttonText:{month:"月",week:"週",day:"日",list:"予定リスト"},allDayText:"終日",eventLimitText:function(e){return"他 "+e+" 件"},noEventsMessage:"イベントが表示されないように"})}(),function(){!function(){var e={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"},t=a.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},ordinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(a){var t=a%10,n=a>=100?100:null;return a+(e[a]||e[t]||e[n])},week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("kk","kk",{closeText:"Жабу",prevText:"&#x3C;Алдыңғы",nextText:"Келесі&#x3E;",currentText:"Бүгін",monthNames:["Қаңтар","Ақпан","Наурыз","Сәуір","Мамыр","Маусым","Шілде","Тамыз","Қыркүйек","Қазан","Қараша","Желтоқсан"],monthNamesShort:["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел"],dayNames:["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"],dayNamesShort:["жкс","дсн","ссн","срс","бсн","жма","снб"],dayNamesMin:["Жк","Дс","Сс","Ср","Бс","Жм","Сн"],weekHeader:"Не",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("kk",{buttonText:{month:"Ай",week:"Апта",day:"Күн",list:"Күн тәртібі"},allDayText:"Күні бойы",eventLimitText:function(e){return"+ тағы "+e},noEventsMessage:"Көрсету үшін оқиғалар жоқ"})}(),function(){!function(){var e=a.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h시 m분",LTS:"A h시 m분 s초",L:"YYYY.MM.DD",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h시 m분",LLLL:"YYYY년 MMMM D일 dddd A h시 m분"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"일분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},ordinalParse:/\d{1,2}일/,ordinal:"%d일",meridiemParse:/오전|오후/,isPM:function(e){return"오후"===e},meridiem:function(e,a,t){return e<12?"오전":"오후"}});return e}(),e.fullCalendar.datepickerLocale("ko","ko",{closeText:"닫기",prevText:"이전달",nextText:"다음달",currentText:"오늘",monthNames:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],monthNamesShort:["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월"],dayNames:["일요일","월요일","화요일","수요일","목요일","금요일","토요일"],dayNamesShort:["일","월","화","수","목","금","토"],dayNamesMin:["일","월","화","수","목","금","토"],weekHeader:"주",dateFormat:"yy. m. d.",firstDay:0,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"년"}),e.fullCalendar.locale("ko",{buttonText:{month:"월",week:"주",day:"일",list:"일정목록"},allDayText:"종일",eventLimitText:"개",noEventsMessage:"일정이 표시 없습니다"})}(),function(){!function(){function e(e,a,t,n){var r={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return a?r[t][0]:r[t][1]}function t(e){var a=e.substr(0,e.indexOf(" "));return r(a)?"a "+e:"an "+e}function n(e){var a=e.substr(0,e.indexOf(" "));return r(a)?"viru "+e:"virun "+e}function r(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return 4<=e&&e<=7;if(e<100){var a=e%10,t=e/10;return r(0===a?t:a)}if(e<1e4){for(;e>=10;)e/=10;return r(e)}return e/=1e3,r(e)}var s=a.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:t,past:n,s:"e puer Sekonnen",m:e,mm:"%d Minutten",h:e,hh:"%d Stonnen",d:e,dd:"%d Deeg",M:e,MM:"%d Méint",y:e,yy:"%d Joer"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return s}(),e.fullCalendar.datepickerLocale("lb","lb",{closeText:"Fäerdeg",prevText:"Zréck",nextText:"Weider",currentText:"Haut",monthNames:["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember"],monthNamesShort:["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],dayNames:["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"],dayNamesShort:["Son","Méi","Dën","Mët","Don","Fre","Sam"],dayNamesMin:["So","Mé","Dë","Më","Do","Fr","Sa"],weekHeader:"W",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("lb",{buttonText:{month:"Mount",week:"Woch",day:"Dag",list:"Terminiwwersiicht"},allDayText:"Ganzen Dag",eventLimitText:"méi",noEventsMessage:"Nee Evenementer ze affichéieren"})}(),function(){!function(){function e(e,a,t,n){return a?"kelios sekundės":n?"kelių sekundžių":"kelias sekundes"}function t(e,a,t,n){return a?r(t)[0]:n?r(t)[1]:r(t)[2]}function n(e){return e%10===0||e>10&&e<20}function r(e){return d[e].split("_")}function s(e,a,s,d){var i=e+" ";return 1===e?i+t(e,a,s[0],d):a?i+(n(e)?r(s)[1]:r(s)[0]):d?i+r(s)[1]:i+(n(e)?r(s)[1]:r(s)[2])}var d={m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"},i=a.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:e,m:t,mm:s,h:t,hh:s,d:t,dd:s,M:t,MM:s,y:t,yy:s},ordinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}});return i}(),e.fullCalendar.datepickerLocale("lt","lt",{closeText:"Uždaryti",prevText:"&#x3C;Atgal",nextText:"Pirmyn&#x3E;",currentText:"Šiandien",monthNames:["Sausis","Vasaris","Kovas","Balandis","Gegužė","Birželis","Liepa","Rugpjūtis","Rugsėjis","Spalis","Lapkritis","Gruodis"],monthNamesShort:["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rugp","Rugs","Spa","Lap","Gru"],dayNames:["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"],dayNamesShort:["sek","pir","ant","tre","ket","pen","šeš"],dayNamesMin:["Se","Pr","An","Tr","Ke","Pe","Še"],weekHeader:"SAV",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:""}),e.fullCalendar.locale("lt",{buttonText:{month:"Mėnuo",week:"Savaitė",day:"Diena",list:"Darbotvarkė"},allDayText:"Visą dieną",eventLimitText:"daugiau",noEventsMessage:"Nėra įvykių rodyti"})}(),function(){!function(){function e(e,a,t){return t?a%10===1&&a%100!==11?e[2]:e[3]:a%10===1&&a%100!==11?e[0]:e[1]}function t(a,t,n){return a+" "+e(s[n],a,t)}function n(a,t,n){return e(s[n],a,t)}function r(e,a){return a?"dažas sekundes":"dažām sekundēm"}var s={m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")},d=a.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:r,m:n,mm:t,h:n,hh:t,d:n,dd:t,M:n,MM:t,y:n,yy:t},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return d}(),e.fullCalendar.datepickerLocale("lv","lv",{closeText:"Aizvērt",prevText:"Iepr.",nextText:"Nāk.",currentText:"Šodien",monthNames:["Janvāris","Februāris","Marts","Aprīlis","Maijs","Jūnijs","Jūlijs","Augusts","Septembris","Oktobris","Novembris","Decembris"],monthNamesShort:["Jan","Feb","Mar","Apr","Mai","Jūn","Jūl","Aug","Sep","Okt","Nov","Dec"],dayNames:["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"],dayNamesShort:["svt","prm","otr","tre","ctr","pkt","sst"],dayNamesMin:["Sv","Pr","Ot","Tr","Ct","Pk","Ss"],weekHeader:"Ned.",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("lv",{buttonText:{month:"Mēnesis",week:"Nedēļa",day:"Diena",list:"Dienas kārtība"},allDayText:"Visu dienu",eventLimitText:function(e){return"+vēl "+e},noEventsMessage:"Nav notikumu, lai parādītu"})}(),function(){!function(){var e=a.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"после %s",past:"пред %s",s:"неколку секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",M:"месец",MM:"%d месеци",y:"година",yy:"%d години"},ordinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var a=e%10,t=e%100;return 0===e?e+"-ев":0===t?e+"-ен":t>10&&t<20?e+"-ти":1===a?e+"-ви":2===a?e+"-ри":7===a||8===a?e+"-ми":e+"-ти"},week:{dow:1,doy:7}});return e}(),e.fullCalendar.datepickerLocale("mk","mk",{closeText:"Затвори",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Денес",monthNames:["Јануари","Февруари","Март","Април","Мај","Јуни","Јули","Август","Септември","Октомври","Ноември","Декември"],monthNamesShort:["Јан","Фев","Мар","Апр","Мај","Јун","Јул","Авг","Сеп","Окт","Ное","Дек"],dayNames:["Недела","Понеделник","Вторник","Среда","Четврток","Петок","Сабота"],dayNamesShort:["Нед","Пон","Вто","Сре","Чет","Пет","Саб"],dayNamesMin:["Не","По","Вт","Ср","Че","Пе","Са"],weekHeader:"Сед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("mk",{buttonText:{month:"Месец",week:"Недела",day:"Ден",list:"График"},allDayText:"Цел ден",eventLimitText:function(e){return"+повеќе "+e},noEventsMessage:"Нема настани за прикажување"})}(),function(){!function(){var e=a.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}});return e}(),e.fullCalendar.datepickerLocale("ms","ms",{closeText:"Tutup",prevText:"&#x3C;Sebelum",nextText:"Selepas&#x3E;",currentText:"hari ini",monthNames:["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember"],monthNamesShort:["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogo","Sep","Okt","Nov","Dis"],dayNames:["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"],dayNamesShort:["Aha","Isn","Sel","Rab","kha","Jum","Sab"],dayNamesMin:["Ah","Is","Se","Ra","Kh","Ju","Sa"],weekHeader:"Mg",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("ms",{buttonText:{month:"Bulan",week:"Minggu",day:"Hari",list:"Agenda"},allDayText:"Sepanjang hari",eventLimitText:function(e){return"masih ada "+e+" acara"},noEventsMessage:"Tiada peristiwa untuk dipaparkan"})}(),function(){!function(){var e=a.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,a){return 12===e&&(e=0),"pagi"===a?e:"tengahari"===a?e>=11?e:e+12:"petang"===a||"malam"===a?e+12:void 0},meridiem:function(e,a,t){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}});return e}(),e.fullCalendar.datepickerLocale("ms-my","ms",{closeText:"Tutup",prevText:"&#x3C;Sebelum",nextText:"Selepas&#x3E;",currentText:"hari ini",monthNames:["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember"],monthNamesShort:["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogo","Sep","Okt","Nov","Dis"],dayNames:["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"],dayNamesShort:["Aha","Isn","Sel","Rab","kha","Jum","Sab"],dayNamesMin:["Ah","Is","Se","Ra","Kh","Ju","Sa"],weekHeader:"Mg",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("ms-my",{buttonText:{month:"Bulan",week:"Minggu",day:"Hari",list:"Agenda"},allDayText:"Sepanjang hari",eventLimitText:function(e){return"masih ada "+e+" acara"},noEventsMessage:"Tiada peristiwa untuk dipaparkan"})}(),function(){!function(){var e=a.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",M:"en måned",MM:"%d måneder",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("nb","nb",{closeText:"Lukk",prevText:"&#xAB;Forrige",nextText:"Neste&#xBB;",currentText:"I dag",monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthNamesShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],dayNamesShort:["søn","man","tir","ons","tor","fre","lør"],dayNames:["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],dayNamesMin:["sø","ma","ti","on","to","fr","lø"],weekHeader:"Uke",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("nb",{buttonText:{month:"Måned",week:"Uke",day:"Dag",list:"Agenda"},allDayText:"Hele dagen",eventLimitText:"til",noEventsMessage:"Ingen hendelser å vise"})}(),function(){!function(){var e="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),n=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],r=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,s=a.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,n){return/-MMM-/.test(n)?t[a.month()]:e[a.month()]},monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",
lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}});return s}(),e.fullCalendar.datepickerLocale("nl","nl",{closeText:"Sluiten",prevText:"←",nextText:"→",currentText:"Vandaag",monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],monthNamesShort:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],dayNamesShort:["zon","maa","din","woe","don","vri","zat"],dayNamesMin:["zo","ma","di","wo","do","vr","za"],weekHeader:"Wk",dateFormat:"dd-mm-yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("nl",{buttonText:{month:"Maand",week:"Week",day:"Dag",list:"Agenda"},allDayText:"Hele dag",eventLimitText:"extra",noEventsMessage:"Geen evenementen om te laten zien"})}(),function(){!function(){var e="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),t="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),n=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],r=/^(januari|februari|maart|april|mei|april|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,s=a.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(a,n){return/-MMM-/.test(n)?t[a.month()]:e[a.month()]},monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(januari|februari|maart|mei|ju[nl]i|april|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"Zo_Ma_Di_Wo_Do_Vr_Za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},ordinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}});return s}(),e.fullCalendar.datepickerLocale("nl-be","nl-BE",{closeText:"Sluiten",prevText:"←",nextText:"→",currentText:"Vandaag",monthNames:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],monthNamesShort:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],dayNames:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"],dayNamesShort:["zon","maa","din","woe","don","vri","zat"],dayNamesMin:["zo","ma","di","wo","do","vr","za"],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("nl-be",{buttonText:{month:"Maand",week:"Week",day:"Dag",list:"Agenda"},allDayText:"Hele dag",eventLimitText:"extra",noEventsMessage:"Geen evenementen om te laten zien"})}(),function(){!function(){var e=a.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"sun_mån_tys_ons_tor_fre_lau".split("_"),weekdaysMin:"su_må_ty_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("nn","nn",{closeText:"Lukk",prevText:"&#xAB;Førre",nextText:"Neste&#xBB;",currentText:"I dag",monthNames:["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],monthNamesShort:["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des"],dayNamesShort:["sun","mån","tys","ons","tor","fre","lau"],dayNames:["sundag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"],dayNamesMin:["su","må","ty","on","to","fr","la"],weekHeader:"Veke",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("nn",{buttonText:{month:"Månad",week:"Veke",day:"Dag",list:"Agenda"},allDayText:"Heile dagen",eventLimitText:"til",noEventsMessage:"Ingen hendelser å vise"})}(),function(){!function(){function e(e){return e%10<5&&e%10>1&&~~(e/10)%10!==1}function t(a,t,n){var r=a+" ";switch(n){case"m":return t?"minuta":"minutę";case"mm":return r+(e(a)?"minuty":"minut");case"h":return t?"godzina":"godzinę";case"hh":return r+(e(a)?"godziny":"godzin");case"MM":return r+(e(a)?"miesiące":"miesięcy");case"yy":return r+(e(a)?"lata":"lat")}}var n="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),r="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"),s=a.defineLocale("pl",{months:function(e,a){return""===a?"("+r[e.month()]+"|"+n[e.month()]+")":/D MMMM/.test(a)?r[e.month()]:n[e.month()]},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:"[W] dddd [o] LT",lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",m:t,mm:t,h:t,hh:t,d:"1 dzień",dd:"%d dni",M:"miesiąc",MM:t,y:"rok",yy:t},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return s}(),e.fullCalendar.datepickerLocale("pl","pl",{closeText:"Zamknij",prevText:"&#x3C;Poprzedni",nextText:"Następny&#x3E;",currentText:"Dziś",monthNames:["Styczeń","Luty","Marzec","Kwiecień","Maj","Czerwiec","Lipiec","Sierpień","Wrzesień","Październik","Listopad","Grudzień"],monthNamesShort:["Sty","Lu","Mar","Kw","Maj","Cze","Lip","Sie","Wrz","Pa","Lis","Gru"],dayNames:["Niedziela","Poniedziałek","Wtorek","Środa","Czwartek","Piątek","Sobota"],dayNamesShort:["Nie","Pn","Wt","Śr","Czw","Pt","So"],dayNamesMin:["N","Pn","Wt","Śr","Cz","Pt","So"],weekHeader:"Tydz",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("pl",{buttonText:{month:"Miesiąc",week:"Tydzień",day:"Dzień",list:"Plan dnia"},allDayText:"Cały dzień",eventLimitText:"więcej",noEventsMessage:"Brak wydarzeń do wyświetlenia"})}(),function(){!function(){var e=a.defineLocale("pt",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("pt","pt",{closeText:"Fechar",prevText:"Anterior",nextText:"Seguinte",currentText:"Hoje",monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],dayNamesMin:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],weekHeader:"Sem",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("pt",{buttonText:{month:"Mês",week:"Semana",day:"Dia",list:"Agenda"},allDayText:"Todo o dia",eventLimitText:"mais",noEventsMessage:"Não há eventos para mostrar"})}(),function(){!function(){var e=a.defineLocale("pt-br",{months:"Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"%s atrás",s:"poucos segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},ordinalParse:/\d{1,2}º/,ordinal:"%dº"});return e}(),e.fullCalendar.datepickerLocale("pt-br","pt-BR",{closeText:"Fechar",prevText:"&#x3C;Anterior",nextText:"Próximo&#x3E;",currentText:"Hoje",monthNames:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthNamesShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],dayNames:["Domingo","Segunda-feira","Terça-feira","Quarta-feira","Quinta-feira","Sexta-feira","Sábado"],dayNamesShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],dayNamesMin:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb"],weekHeader:"Sm",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("pt-br",{buttonText:{month:"Mês",week:"Semana",day:"Dia",list:"Compromissos"},allDayText:"dia inteiro",eventLimitText:function(e){return"mais +"+e},noEventsMessage:"Não há eventos para mostrar"})}(),function(){!function(){function e(e,a,t){var n={mm:"minute",hh:"ore",dd:"zile",MM:"luni",yy:"ani"},r=" ";return(e%100>=20||e>=100&&e%100===0)&&(r=" de "),e+r+n[t]}var t=a.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",m:"un minut",mm:e,h:"o oră",hh:e,d:"o zi",dd:e,M:"o lună",MM:e,y:"un an",yy:e},week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("ro","ro",{closeText:"Închide",prevText:"&#xAB; Luna precedentă",nextText:"Luna următoare &#xBB;",currentText:"Azi",monthNames:["Ianuarie","Februarie","Martie","Aprilie","Mai","Iunie","Iulie","August","Septembrie","Octombrie","Noiembrie","Decembrie"],monthNamesShort:["Ian","Feb","Mar","Apr","Mai","Iun","Iul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Duminică","Luni","Marţi","Miercuri","Joi","Vineri","Sâmbătă"],dayNamesShort:["Dum","Lun","Mar","Mie","Joi","Vin","Sâm"],dayNamesMin:["Du","Lu","Ma","Mi","Jo","Vi","Sâ"],weekHeader:"Săpt",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("ro",{buttonText:{prev:"precedentă",next:"următoare",month:"Lună",week:"Săptămână",day:"Zi",list:"Agendă"},allDayText:"Toată ziua",eventLimitText:function(e){return"+alte "+e},noEventsMessage:"Nu există evenimente de afișat"})}(),function(){!function(){function e(e,a){var t=e.split("_");return a%10===1&&a%100!==11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(a,t,n){var r={mm:t?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",MM:"месяц_месяца_месяцев",yy:"год_года_лет"};return"m"===n?t?"минута":"минуту":a+" "+e(r[n],+a)}var n=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i],r=a.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:n,longMonthsParse:n,shortMonthsParse:n,monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сегодня в] LT",nextDay:"[Завтра в] LT",lastDay:"[Вчера в] LT",nextWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В следующее] dddd [в] LT";case 1:case 2:case 4:return"[В следующий] dddd [в] LT";case 3:case 5:case 6:return"[В следующую] dddd [в] LT"}},lastWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd [в] LT":"[В] dddd [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",m:t,mm:t,h:"час",hh:t,d:"день",dd:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(e){return/^(дня|вечера)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночи":e<12?"утра":e<17?"дня":"вечера"},ordinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":return e+"-й";case"D":return e+"-го";case"w":case"W":return e+"-я";default:return e}},week:{dow:1,doy:7}});return r}(),e.fullCalendar.datepickerLocale("ru","ru",{closeText:"Закрыть",prevText:"&#x3C;Пред",nextText:"След&#x3E;",currentText:"Сегодня",monthNames:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],monthNamesShort:["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"],dayNames:["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"],dayNamesShort:["вск","пнд","втр","срд","чтв","птн","сбт"],dayNamesMin:["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],weekHeader:"Нед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("ru",{buttonText:{month:"Месяц",week:"Неделя",day:"День",list:"Повестка дня"},allDayText:"Весь день",eventLimitText:function(e){return"+ ещё "+e},noEventsMessage:"Нет событий для отображения"})}(),function(){!function(){function e(e){return e>1&&e<5}function t(a,t,n,r){var s=a+" ";switch(n){case"s":return t||r?"pár sekúnd":"pár sekundami";case"m":return t?"minúta":r?"minútu":"minútou";case"mm":return t||r?s+(e(a)?"minúty":"minút"):s+"minútami";case"h":return t?"hodina":r?"hodinu":"hodinou";case"hh":return t||r?s+(e(a)?"hodiny":"hodín"):s+"hodinami";case"d":return t||r?"deň":"dňom";case"dd":return t||r?s+(e(a)?"dni":"dní"):s+"dňami";case"M":return t||r?"mesiac":"mesiacom";case"MM":return t||r?s+(e(a)?"mesiace":"mesiacov"):s+"mesiacmi";case"y":return t||r?"rok":"rokom";case"yy":return t||r?s+(e(a)?"roky":"rokov"):s+"rokmi"}}var n="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),r="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_"),s=a.defineLocale("sk",{months:n,monthsShort:r,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 4:case 5:return"[minulý] dddd [o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}});return s}(),e.fullCalendar.datepickerLocale("sk","sk",{closeText:"Zavrieť",prevText:"&#x3C;Predchádzajúci",nextText:"Nasledujúci&#x3E;",currentText:"Dnes",monthNames:["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december"],monthNamesShort:["Jan","Feb","Mar","Apr","Máj","Jún","Júl","Aug","Sep","Okt","Nov","Dec"],dayNames:["nedeľa","pondelok","utorok","streda","štvrtok","piatok","sobota"],dayNamesShort:["Ned","Pon","Uto","Str","Štv","Pia","Sob"],dayNamesMin:["Ne","Po","Ut","St","Št","Pia","So"],weekHeader:"Ty",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("sk",{buttonText:{month:"Mesiac",week:"Týždeň",day:"Deň",list:"Rozvrh"},allDayText:"Celý deň",eventLimitText:function(e){return"+ďalšie: "+e},noEventsMessage:"Žiadne akcie na zobrazenie"})}(),function(){!function(){function e(e,a,t,n){var r=e+" ";switch(t){case"s":return a||n?"nekaj sekund":"nekaj sekundami";case"m":return a?"ena minuta":"eno minuto";case"mm":return r+=1===e?a?"minuta":"minuto":2===e?a||n?"minuti":"minutama":e<5?a||n?"minute":"minutami":a||n?"minut":"minutami";case"h":return a?"ena ura":"eno uro";case"hh":return r+=1===e?a?"ura":"uro":2===e?a||n?"uri":"urama":e<5?a||n?"ure":"urami":a||n?"ur":"urami";case"d":return a||n?"en dan":"enim dnem";case"dd":return r+=1===e?a||n?"dan":"dnem":2===e?a||n?"dni":"dnevoma":a||n?"dni":"dnevi";case"M":return a||n?"en mesec":"enim mesecem";case"MM":return r+=1===e?a||n?"mesec":"mesecem":2===e?a||n?"meseca":"mesecema":e<5?a||n?"mesece":"meseci":a||n?"mesecev":"meseci";case"y":return a||n?"eno leto":"enim letom";case"yy":return r+=1===e?a||n?"leto":"letom":2===e?a||n?"leti":"letoma":e<5?a||n?"leta":"leti":a||n?"let":"leti"}}var t=a.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:e,m:e,mm:e,h:e,hh:e,d:e,dd:e,M:e,MM:e,y:e,yy:e},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("sl","sl",{closeText:"Zapri",prevText:"&#x3C;Prejšnji",nextText:"Naslednji&#x3E;",currentText:"Trenutni",monthNames:["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Avg","Sep","Okt","Nov","Dec"],dayNames:["Nedelja","Ponedeljek","Torek","Sreda","Četrtek","Petek","Sobota"],dayNamesShort:["Ned","Pon","Tor","Sre","Čet","Pet","Sob"],dayNamesMin:["Ne","Po","To","Sr","Če","Pe","So"],weekHeader:"Teden",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("sl",{buttonText:{month:"Mesec",week:"Teden",day:"Dan",list:"Dnevni red"},allDayText:"Ves dan",eventLimitText:"več",noEventsMessage:"Ni dogodkov za prikaz"})}(),function(){!function(){var e={words:{m:["jedan minut","jedne minute"],mm:["minut","minute","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mesec","meseca","meseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,a){return 1===e?a[0]:e>=2&&e<=4?a[1]:a[2]},translate:function(a,t,n){var r=e.words[n];return 1===n.length?t?r[0]:r[1]:a+" "+e.correctGrammaticalCase(a,r)}},t=a.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){var e=["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"];return e[this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",m:e.translate,mm:e.translate,h:e.translate,hh:e.translate,d:"dan",dd:e.translate,M:"mesec",MM:e.translate,y:"godinu",yy:e.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("sr","sr",{closeText:"Затвори",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Данас",monthNames:["Јануар","Фебруар","Март","Април","Мај","Јун","Јул","Август","Септембар","Октобар","Новембар","Децембар"],monthNamesShort:["Јан","Феб","Мар","Апр","Мај","Јун","Јул","Авг","Сеп","Окт","Нов","Дец"],dayNames:["Недеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"],dayNamesShort:["Нед","Пон","Уто","Сре","Чет","Пет","Суб"],dayNamesMin:["Не","По","Ут","Ср","Че","Пе","Су"],weekHeader:"Сед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("sr",{buttonText:{month:"Месец",week:"Недеља",day:"Дан",list:"Планер"},allDayText:"Цео дан",eventLimitText:function(e){return"+ још "+e},noEventsMessage:"Нема догађаја за приказ"})}(),function(){!function(){var e={words:{m:["један минут","једне минуте"],mm:["минут","минуте","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],dd:["дан","дана","дана"],MM:["месец","месеца","месеци"],yy:["година","године","година"]},correctGrammaticalCase:function(e,a){return 1===e?a[0]:e>=2&&e<=4?a[1]:a[2]},translate:function(a,t,n){var r=e.words[n];return 1===n.length?t?r[0]:r[1]:a+" "+e.correctGrammaticalCase(a,r)}},t=a.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){var e=["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"];return e[this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",m:e.translate,mm:e.translate,h:e.translate,hh:e.translate,d:"дан",dd:e.translate,M:"месец",MM:e.translate,y:"годину",yy:e.translate},ordinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("sr-cyrl","sr",{closeText:"Затвори",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Данас",monthNames:["Јануар","Фебруар","Март","Април","Мај","Јун","Јул","Август","Септембар","Октобар","Новембар","Децембар"],monthNamesShort:["Јан","Феб","Мар","Апр","Мај","Јун","Јул","Авг","Сеп","Окт","Нов","Дец"],dayNames:["Недеља","Понедељак","Уторак","Среда","Четвртак","Петак","Субота"],dayNamesShort:["Нед","Пон","Уто","Сре","Чет","Пет","Суб"],dayNamesMin:["Не","По","Ут","Ср","Че","Пе","Су"],weekHeader:"Сед",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("sr-cyrl",{buttonText:{month:"Месец",week:"Недеља",day:"Дан",list:"Планер"},allDayText:"Цео дан",eventLimitText:function(e){return"+ још "+e},noEventsMessage:"Нема догађаја за приказ"})}(),function(){!function(){var e=a.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},ordinalParse:/\d{1,2}(e|a)/,ordinal:function(e){var a=e%10,t=1===~~(e%100/10)?"e":1===a?"a":2===a?"a":"e";return e+t},week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("sv","sv",{closeText:"Stäng",prevText:"&#xAB;Förra",nextText:"Nästa&#xBB;",currentText:"Idag",monthNames:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],dayNamesShort:["Sön","Mån","Tis","Ons","Tor","Fre","Lör"],dayNames:["Söndag","Måndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag"],dayNamesMin:["Sö","Må","Ti","On","To","Fr","Lö"],weekHeader:"Ve",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("sv",{buttonText:{month:"Månad",week:"Vecka",day:"Dag",list:"Program"},allDayText:"Heldag",eventLimitText:"till",noEventsMessage:"Inga händelser att visa"})}(),function(){!function(){var e=a.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY/MM/DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(e){return"หลังเที่ยง"===e},meridiem:function(e,a,t){return e<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"
}});return e}(),e.fullCalendar.datepickerLocale("th","th",{closeText:"ปิด",prevText:"&#xAB;&#xA0;ย้อน",nextText:"ถัดไป&#xA0;&#xBB;",currentText:"วันนี้",monthNames:["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม"],monthNamesShort:["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."],dayNames:["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"],dayNamesShort:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],dayNamesMin:["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."],weekHeader:"Wk",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("th",{buttonText:{month:"เดือน",week:"สัปดาห์",day:"วัน",list:"แผนงาน"},allDayText:"ตลอดวัน",eventLimitText:"เพิ่มเติม",noEventsMessage:"ไม่มีกิจกรรมที่จะแสดง"})}(),function(){!function(){var e={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"},t=a.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pts_Sal_Çar_Per_Cum_Cts".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[haftaya] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen hafta] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinalParse:/\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,ordinal:function(a){if(0===a)return a+"'ıncı";var t=a%10,n=a%100-t,r=a>=100?100:null;return a+(e[t]||e[n]||e[r])},week:{dow:1,doy:7}});return t}(),e.fullCalendar.datepickerLocale("tr","tr",{closeText:"kapat",prevText:"&#x3C;geri",nextText:"ileri&#x3e",currentText:"bugün",monthNames:["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık"],monthNamesShort:["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara"],dayNames:["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"],dayNamesShort:["Pz","Pt","Sa","Ça","Pe","Cu","Ct"],dayNamesMin:["Pz","Pt","Sa","Ça","Pe","Cu","Ct"],weekHeader:"Hf",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("tr",{buttonText:{next:"ileri",month:"Ay",week:"Hafta",day:"Gün",list:"Ajanda"},allDayText:"Tüm gün",eventLimitText:"daha fazla",noEventsMessage:"Herhangi bir etkinlik görüntülemek için"})}(),function(){!function(){function e(e,a){var t=e.split("_");return a%10===1&&a%100!==11?t[0]:a%10>=2&&a%10<=4&&(a%100<10||a%100>=20)?t[1]:t[2]}function t(a,t,n){var r={mm:t?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:t?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"};return"m"===n?t?"хвилина":"хвилину":"h"===n?t?"година":"годину":a+" "+e(r[n],+a)}function n(e,a){var t={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")},n=/(\[[ВвУу]\]) ?dddd/.test(a)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(a)?"genitive":"nominative";return t[n][e.day()]}function r(e){return function(){return e+"о"+(11===this.hours()?"б":"")+"] LT"}}var s=a.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:n,weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:r("[Сьогодні "),nextDay:r("[Завтра "),lastDay:r("[Вчора "),nextWeek:r("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return r("[Минулої] dddd [").call(this);case 1:case 2:case 4:return r("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",m:t,mm:t,h:"годину",hh:t,d:"день",dd:t,M:"місяць",MM:t,y:"рік",yy:t},meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(e){return/^(дня|вечора)$/.test(e)},meridiem:function(e,a,t){return e<4?"ночі":e<12?"ранку":e<17?"дня":"вечора"},ordinalParse:/\d{1,2}-(й|го)/,ordinal:function(e,a){switch(a){case"M":case"d":case"DDD":case"w":case"W":return e+"-й";case"D":return e+"-го";default:return e}},week:{dow:1,doy:7}});return s}(),e.fullCalendar.datepickerLocale("uk","uk",{closeText:"Закрити",prevText:"&#x3C;",nextText:"&#x3E;",currentText:"Сьогодні",monthNames:["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень"],monthNamesShort:["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","Лис","Гру"],dayNames:["неділя","понеділок","вівторок","середа","четвер","п’ятниця","субота"],dayNamesShort:["нед","пнд","вів","срд","чтв","птн","сбт"],dayNamesMin:["Нд","Пн","Вт","Ср","Чт","Пт","Сб"],weekHeader:"Тиж",dateFormat:"dd.mm.yy",firstDay:1,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("uk",{buttonText:{month:"Місяць",week:"Тиждень",day:"День",list:"Порядок денний"},allDayText:"Увесь день",eventLimitText:function(e){return"+ще "+e+"..."},noEventsMessage:"Немає подій для відображення"})}(),function(){!function(){var e=a.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,a,t){return e<12?t?"sa":"SA":t?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần rồi lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},ordinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("vi","vi",{closeText:"Đóng",prevText:"&#x3C;Trước",nextText:"Tiếp&#x3E;",currentText:"Hôm nay",monthNames:["Tháng Một","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mười","Tháng Mười Một","Tháng Mười Hai"],monthNamesShort:["Tháng 1","Tháng 2","Tháng 3","Tháng 4","Tháng 5","Tháng 6","Tháng 7","Tháng 8","Tháng 9","Tháng 10","Tháng 11","Tháng 12"],dayNames:["Chủ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"],dayNamesShort:["CN","T2","T3","T4","T5","T6","T7"],dayNamesMin:["CN","T2","T3","T4","T5","T6","T7"],weekHeader:"Tu",dateFormat:"dd/mm/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""}),e.fullCalendar.locale("vi",{buttonText:{month:"Tháng",week:"Tuần",day:"Ngày",list:"Lịch biểu"},allDayText:"Cả ngày",eventLimitText:function(e){return"+ thêm "+e},noEventsMessage:"Không có sự kiện để hiển thị"})}(),function(){!function(){var e=a.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah点mm分",LTS:"Ah点m分s秒",L:"YYYY-MM-DD",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah点mm分",LLLL:"YYYY年MMMD日ddddAh点mm分",l:"YYYY-MM-DD",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah点mm分",llll:"YYYY年MMMD日ddddAh点mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"下午"===a||"晚上"===a?e+12:e>=11?e:e+12},meridiem:function(e,a,t){var n=100*e+a;return n<600?"凌晨":n<900?"早上":n<1130?"上午":n<1230?"中午":n<1800?"下午":"晚上"},calendar:{sameDay:function(){return 0===this.minutes()?"[今天]Ah[点整]":"[今天]LT"},nextDay:function(){return 0===this.minutes()?"[明天]Ah[点整]":"[明天]LT"},lastDay:function(){return 0===this.minutes()?"[昨天]Ah[点整]":"[昨天]LT"},nextWeek:function(){var e,t;return e=a().startOf("week"),t=this.diff(e,"days")>=7?"[下]":"[本]",0===this.minutes()?t+"dddAh点整":t+"dddAh点mm"},lastWeek:function(){var e,t;return e=a().startOf("week"),t=this.unix()<e.unix()?"[上]":"[本]",0===this.minutes()?t+"dddAh点整":t+"dddAh点mm"},sameElse:"LL"},ordinalParse:/\d{1,2}(日|月|周)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"周";default:return e}},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}});return e}(),e.fullCalendar.datepickerLocale("zh-cn","zh-CN",{closeText:"关闭",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],dayNamesMin:["日","一","二","三","四","五","六"],weekHeader:"周",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"年"}),e.fullCalendar.locale("zh-cn",{buttonText:{month:"月",week:"周",day:"日",list:"日程"},allDayText:"全天",eventLimitText:function(e){return"另外 "+e+" 个"},noEventsMessage:"没有事件显示"})}(),function(){!function(){var e=a.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,a){return 12===e&&(e=0),"凌晨"===a||"早上"===a||"上午"===a?e:"中午"===a?e>=11?e:e+12:"下午"===a||"晚上"===a?e+12:void 0},meridiem:function(e,a,t){var n=100*e+a;return n<600?"凌晨":n<900?"早上":n<1130?"上午":n<1230?"中午":n<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,a){switch(a){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}});return e}(),e.fullCalendar.datepickerLocale("zh-tw","zh-TW",{closeText:"關閉",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthNamesShort:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["周日","周一","周二","周三","周四","周五","周六"],dayNamesMin:["日","一","二","三","四","五","六"],weekHeader:"周",dateFormat:"yy/mm/dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"年"}),e.fullCalendar.locale("zh-tw",{buttonText:{month:"月",week:"週",day:"天",list:"待辦事項"},allDayText:"全天",eventLimitText:"更多",noEventsMessage:"没有事件显示"})}(),a.locale("en"),e.fullCalendar.locale("en"),e.datepicker&&e.datepicker.setDefaults(e.datepicker.regional[""])});
-/* mousetrap v1.6.0 craig.is/killing/mice */
-(function(r,t,g){function u(a,b,h){a.addEventListener?a.addEventListener(b,h,!1):a.attachEvent("on"+b,h)}function y(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return k[a.which]?k[a.which]:p[a.which]?p[a.which]:String.fromCharCode(a.which).toLowerCase()}function D(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function v(a){return"shift"==a||"ctrl"==a||"alt"==a||
-"meta"==a}function z(a,b){var h,c,e,g=[];h=a;"+"===h?h=["+"]:(h=h.replace(/\+{2}/g,"+plus"),h=h.split("+"));for(e=0;e<h.length;++e)c=h[e],A[c]&&(c=A[c]),b&&"keypress"!=b&&B[c]&&(c=B[c],g.push("shift")),v(c)&&g.push(c);h=c;e=b;if(!e){if(!n){n={};for(var l in k)95<l&&112>l||k.hasOwnProperty(l)&&(n[k[l]]=l)}e=n[h]?"keydown":"keypress"}"keypress"==e&&g.length&&(e="keydown");return{key:c,modifiers:g,action:e}}function C(a,b){return null===a||a===t?!1:a===b?!0:C(a.parentNode,b)}function c(a){function b(a){a=
-a||{};var b=!1,m;for(m in n)a[m]?b=!0:n[m]=0;b||(w=!1)}function h(a,b,m,f,c,h){var g,e,k=[],l=m.type;if(!d._callbacks[a])return[];"keyup"==l&&v(a)&&(b=[a]);for(g=0;g<d._callbacks[a].length;++g)if(e=d._callbacks[a][g],(f||!e.seq||n[e.seq]==e.level)&&l==e.action){var q;(q="keypress"==l&&!m.metaKey&&!m.ctrlKey)||(q=e.modifiers,q=b.sort().join(",")===q.sort().join(","));q&&(q=f&&e.seq==f&&e.level==h,(!f&&e.combo==c||q)&&d._callbacks[a].splice(g,1),k.push(e))}return k}function g(a,b,m,f){d.stopCallback(b,
-b.target||b.srcElement,m,f)||!1!==a(b,m)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=y(a);b&&("keyup"==a.type&&x===b?x=!1:d.handleKey(b,D(a),a))}function k(a,c,m,f){function e(c){return function(){w=c;++n[a];clearTimeout(r);r=setTimeout(b,1E3)}}function h(c){g(m,c,a);"keyup"!==f&&(x=y(c));setTimeout(b,10)}for(var d=n[a]=0;d<c.length;++d){var p=d+1===c.length?h:e(f||
-z(c[d+1]).action);l(c[d],p,f,a,d)}}function l(a,b,c,f,e){d._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var g=a.split(" ");1<g.length?k(a,g,b,c):(c=z(a,c),d._callbacks[c.key]=d._callbacks[c.key]||[],h(c.key,c.modifiers,{type:c.action},f,a,e),d._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:e,combo:a}))}var d=this;a=a||t;if(!(d instanceof c))return new c(a);d.target=a;d._callbacks={};d._directMap={};var n={},r,x=!1,p=!1,w=!1;d._handleKey=function(a,
-c,e){var f=h(a,c,e),d;c={};var k=0,l=!1;for(d=0;d<f.length;++d)f[d].seq&&(k=Math.max(k,f[d].level));for(d=0;d<f.length;++d)f[d].seq?f[d].level==k&&(l=!0,c[f[d].seq]=1,g(f[d].callback,e,f[d].combo,f[d].seq)):l||g(f[d].callback,e,f[d].combo);f="keypress"==e.type&&p;e.type!=w||v(a)||f||b(c);p=l&&"keydown"==e.type};d._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)l(a[d],b,c)};u(a,"keypress",e);u(a,"keydown",e);u(a,"keyup",e)}if(r){var k={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",
-18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},p={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},B={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},A={option:"alt",command:"meta","return":"enter",
-escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},n;for(g=1;20>g;++g)k[111+g]="f"+g;for(g=0;9>=g;++g)k[g+96]=g;c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={};this._directMap=
-{};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||C(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(k[b]=a[b]);n=null};c.init=function(){var a=c(t),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};
-c.init();r.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=c);"function"===typeof define&&define.amd&&define(function(){return c})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null);
-
-(function(a){var c={},d=a.prototype.stopCallback;a.prototype.stopCallback=function(e,b,a,f){return this.paused?!0:c[a]||c[f]?!1:d.call(this,e,b,a)};a.prototype.bindGlobal=function(a,b,d){this.bind(a,b,d);if(a instanceof Array)for(b=0;b<a.length;b++)c[a[b]]=!0;else c[a]=!0};a.init()})(Mousetrap);
-
!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:NaN}function r(n){return null===n?NaN:+n}function i(n){return!isNaN(n)}function u(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)<0?r=u+1:i=u}return r},right:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n(t[u],e)>0?i=u:r=u+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function l(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function c(){this._=Object.create(null)}function f(n){return(n+="")===bo||n[0]===_o?_o+n:n}function s(n){return(n+="")[0]===_o?n.slice(1):n}function h(n){return f(n)in this._}function p(n){return(n=f(n))in this._&&delete this._[n]}function g(){var n=[];for(var t in this._)n.push(s(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function y(){this._=Object.create(null)}function m(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=wo.length;r>e;++e){var i=wo[e]+t;if(i in n)return i}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,i=-1,u=r.length;++i<u;)(t=r[i].on)&&t.apply(this,arguments);return n}var e=[],r=new c;return t.on=function(t,i){var u,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,u=e.indexOf(o)).concat(e.slice(u+1)),r.remove(t)),i&&e.push(r.set(t,{on:i})),n)},t}function S(){ao.event.preventDefault()}function k(){for(var n,t=ao.event;n=t.sourceEvent;)t=n;return t}function N(n){for(var t=new _,e=0,r=arguments.length;++e<r;)t[arguments[e]]=w(t);return t.of=function(e,r){return function(i){try{var u=i.sourceEvent=ao.event;i.target=n,ao.event=i,t[i.type].apply(e,r)}finally{ao.event=u}}},t}function E(n){return ko(n,Co),n}function A(n){return"function"==typeof n?n:function(){return No(n,this)}}function C(n){return"function"==typeof n?n:function(){return Eo(n,this)}}function z(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function i(){this.setAttribute(n,t)}function u(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=ao.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?u:i}function L(n){return n.trim().replace(/\s+/g," ")}function q(n){return new RegExp("(?:^|\\s+)"+ao.requote(n)+"(?:\\s+|$)","g")}function T(n){return(n+"").trim().split(/^|\s+/)}function R(n,t){function e(){for(var e=-1;++e<i;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<i;)n[e](this,r)}n=T(n).map(D);var i=n.length;return"function"==typeof t?r:e}function D(n){var t=q(n);return function(e,r){if(i=e.classList)return r?i.add(n):i.remove(n);var i=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(i)||e.setAttribute("class",L(i+" "+n))):e.setAttribute("class",L(i.replace(t," ")))}}function P(n,t,e){function r(){this.style.removeProperty(n)}function i(){this.style.setProperty(n,t,e)}function u(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?u:i}function U(n,t){function e(){delete this[n]}function r(){this[n]=t}function i(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?i:r}function j(n){function t(){var t=this.ownerDocument,e=this.namespaceURI;return e===zo&&t.documentElement.namespaceURI===zo?t.createElement(n):t.createElementNS(e,n)}function e(){return this.ownerDocument.createElementNS(n.space,n.local)}return"function"==typeof n?n:(n=ao.ns.qualify(n)).local?e:t}function F(){var n=this.parentNode;n&&n.removeChild(this)}function H(n){return{__data__:n}}function O(n){return function(){return Ao(this,n)}}function I(n){return arguments.length||(n=e),function(t,e){return t&&e?n(t.__data__,e.__data__):!t-!e}}function Y(n,t){for(var e=0,r=n.length;r>e;e++)for(var i,u=n[e],o=0,a=u.length;a>o;o++)(i=u[o])&&t(i,o,e);return n}function Z(n){return ko(n,qo),n}function V(n){var t,e;return function(r,i,u){var o,a=n[u].update,l=a.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(o=a[t])&&++t<l;);return o}}function X(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function i(){var i=l(t,co(arguments));r.call(this),this.addEventListener(n,this[o]=i,i.$=e),i._=t}function u(){var t,e=new RegExp("^__on([^.]+)"+ao.requote(n)+"$");for(var r in this)if(t=r.match(e)){var i=this[r];this.removeEventListener(t[1],i,i.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),l=$;a>0&&(n=n.slice(0,a));var c=To.get(n);return c&&(n=c,l=B),a?t?i:r:t?b:u}function $(n,t){return function(e){var r=ao.event;ao.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ao.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Do,i="click"+r,u=ao.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ro&&(Ro="onselectstart"in e?!1:x(e.style,"userSelect")),Ro){var o=n(e).style,a=o[Ro];o[Ro]="none"}return function(n){if(u.on(r,null),Ro&&(o[Ro]=a),n){var t=function(){u.on(i,null)};u.on(i,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var i=r.createSVGPoint();if(0>Po){var u=t(n);if(u.scrollX||u.scrollY){r=ao.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Po=!(o.f||o.e),r.remove()}}return Po?(i.x=e.pageX,i.y=e.pageY):(i.x=e.clientX,i.y=e.clientY),i=i.matrixTransform(n.getScreenCTM().inverse()),[i.x,i.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ao.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nn(n){return n>1?0:-1>n?Fo:Math.acos(n)}function tn(n){return n>1?Io:-1>n?-Io:Math.asin(n)}function en(n){return((n=Math.exp(n))-1/n)/2}function rn(n){return((n=Math.exp(n))+1/n)/2}function un(n){return((n=Math.exp(2*n))-1)/(n+1)}function on(n){return(n=Math.sin(n/2))*n}function an(){}function ln(n,t,e){return this instanceof ln?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ln?new ln(n.h,n.s,n.l):_n(""+n,wn,ln):new ln(n,t,e)}function cn(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(o-u)*n/60:180>n?o:240>n?u+(o-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,u=2*e-o,new mn(i(n+120),i(n),i(n-120))}function fn(n,t,e){return this instanceof fn?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof fn?new fn(n.h,n.c,n.l):n instanceof hn?gn(n.l,n.a,n.b):gn((n=Sn((n=ao.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new fn(n,t,e)}function sn(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new hn(e,Math.cos(n*=Yo)*t,Math.sin(n)*t)}function hn(n,t,e){return this instanceof hn?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof hn?new hn(n.l,n.a,n.b):n instanceof fn?sn(n.h,n.c,n.l):Sn((n=mn(n)).r,n.g,n.b):new hn(n,t,e)}function pn(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=vn(i)*na,r=vn(r)*ta,u=vn(u)*ea,new mn(yn(3.2404542*i-1.5371385*r-.4985314*u),yn(-.969266*i+1.8760108*r+.041556*u),yn(.0556434*i-.2040259*r+1.0572252*u))}function gn(n,t,e){return n>0?new fn(Math.atan2(e,t)*Zo,Math.sqrt(t*t+e*e),n):new fn(NaN,NaN,n)}function vn(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function dn(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function yn(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mn(n,t,e){return this instanceof mn?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mn?new mn(n.r,n.g,n.b):_n(""+n,mn,cn):new mn(n,t,e)}function Mn(n){return new mn(n>>16,n>>8&255,255&n)}function xn(n){return Mn(n)+""}function bn(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function _n(n,t,e){var r,i,u,o=0,a=0,l=0;if(r=/([a-z]+)\((.*)\)/.exec(n=n.toLowerCase()))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(Nn(i[0]),Nn(i[1]),Nn(i[2]))}return(u=ua.get(n))?t(u.r,u.g,u.b):(null==n||"#"!==n.charAt(0)||isNaN(u=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&u)>>4,o=o>>4|o,a=240&u,a=a>>4|a,l=15&u,l=l<<4|l):7===n.length&&(o=(16711680&u)>>16,a=(65280&u)>>8,l=255&u)),t(o,a,l))}function wn(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-u,l=(o+u)/2;return a?(i=.5>l?a/(o+u):a/(2-o-u),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=NaN,i=l>0&&1>l?0:r),new ln(r,i,l)}function Sn(n,t,e){n=kn(n),t=kn(t),e=kn(e);var r=dn((.4124564*n+.3575761*t+.1804375*e)/na),i=dn((.2126729*n+.7151522*t+.072175*e)/ta),u=dn((.0193339*n+.119192*t+.9503041*e)/ea);return hn(116*i-16,500*(r-i),200*(i-u))}function kn(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Nn(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function En(n){return"function"==typeof n?n:function(){return n}}function An(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Cn(t,e,n,r)}}function Cn(n,t,e,r){function i(){var n,t=l.status;if(!t&&Ln(l)||t>=200&&300>t||304===t){try{n=e.call(u,l)}catch(r){return void o.error.call(u,r)}o.load.call(u,n)}else o.error.call(u,l)}var u={},o=ao.dispatch("beforesend","progress","load","error"),a={},l=new XMLHttpRequest,c=null;return!this.XDomainRequest||"withCredentials"in l||!/^(http(s)?:)?\/\//.test(n)||(l=new XDomainRequest),"onload"in l?l.onload=l.onerror=i:l.onreadystatechange=function(){l.readyState>3&&i()},l.onprogress=function(n){var t=ao.event;ao.event=n;try{o.progress.call(u,l)}finally{ao.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(c=n,u):c},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(co(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),l.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),l.setRequestHeader)for(var f in a)l.setRequestHeader(f,a[f]);return null!=t&&l.overrideMimeType&&l.overrideMimeType(t),null!=c&&(l.responseType=c),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),o.beforesend.call(u,l),l.send(null==r?null:r),u},u.abort=function(){return l.abort(),u},ao.rebind(u,o,"on"),null==r?u:u.get(zn(r))}function zn(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Ln(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qn(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={c:n,t:i,n:null};return aa?aa.n=u:oa=u,aa=u,la||(ca=clearTimeout(ca),la=1,fa(Tn)),u}function Tn(){var n=Rn(),t=Dn()-n;t>24?(isFinite(t)&&(clearTimeout(ca),ca=setTimeout(Tn,t)),la=0):(la=1,fa(Tn))}function Rn(){for(var n=Date.now(),t=oa;t;)n>=t.t&&t.c(n-t.t)&&(t.c=null),t=t.n;return n}function Dn(){for(var n,t=oa,e=1/0;t;)t.c?(t.t<e&&(e=t.t),t=(n=t).n):t=n?n.n=t.n:oa=t.n;return aa=n,e}function Pn(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Un(n,t){var e=Math.pow(10,3*xo(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function jn(n){var t=n.decimal,e=n.thousands,r=n.grouping,i=n.currency,u=r&&e?function(n,t){for(var i=n.length,u=[],o=0,a=r[0],l=0;i>0&&a>0&&(l+a+1>t&&(a=Math.max(1,t-l)),u.push(n.substring(i-=a,i+a)),!((l+=a+1)>t));)a=r[o=(o+1)%r.length];return u.reverse().join(e)}:m;return function(n){var e=ha.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",l=e[4]||"",c=e[5],f=+e[6],s=e[7],h=e[8],p=e[9],g=1,v="",d="",y=!1,m=!0;switch(h&&(h=+h.substring(1)),(c||"0"===r&&"="===o)&&(c=r="0",o="="),p){case"n":s=!0,p="g";break;case"%":g=100,d="%",p="f";break;case"p":g=100,d="%",p="r";break;case"b":case"o":case"x":case"X":"#"===l&&(v="0"+p.toLowerCase());case"c":m=!1;case"d":y=!0,h=0;break;case"s":g=-1,p="r"}"$"===l&&(v=i[0],d=i[1]),"r"!=p||h||(p="g"),null!=h&&("g"==p?h=Math.max(1,Math.min(21,h)):"e"!=p&&"f"!=p||(h=Math.max(0,Math.min(20,h)))),p=pa.get(p)||Fn;var M=c&&s;return function(n){var e=d;if(y&&n%1)return"";var i=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>g){var l=ao.formatPrefix(n,h);n=l.scale(n),e=l.symbol+d}else n*=g;n=p(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=m?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!c&&s&&(x=u(x,1/0));var S=v.length+x.length+b.length+(M?0:i.length),k=f>S?new Array(S=f-S+1).join(r):"";return M&&(x=u(k+x,k.length?f-b.length:1/0)),i+=v,n=x+b,("<"===o?i+n+k:">"===o?k+i+n:"^"===o?k.substring(0,S>>=1)+i+n+k.substring(S):i+(M?n:k+n))+e}}}function Fn(n){return n+""}function Hn(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function On(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new va(e-1)),1),e}function u(n,e){return t(n=new va(+n),e),n}function o(n,r,u){var o=i(n),a=[];if(u>1)for(;r>o;)e(o)%u||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{va=Hn;var r=new Hn;return r._=n,o(r,t,e)}finally{va=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=o;var l=n.utc=In(n);return l.floor=l,l.round=In(r),l.ceil=In(i),l.offset=In(u),l.range=a,n}function In(n){return function(t,e){try{va=Hn;var r=new Hn;return r._=t,n(r,e)._}finally{va=Date}}}function Yn(n){function t(n){function t(t){for(var e,i,u,o=[],a=-1,l=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(l,a)),null!=(i=ya[e=n.charAt(++a)])&&(e=n.charAt(++a)),(u=A[e])&&(e=u(t,null==i?"e"===e?" ":"0":i)),o.push(e),l=a+1);return o.push(n.slice(l,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},i=e(r,n,t,0);if(i!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var u=null!=r.Z&&va!==Hn,o=new(u?Hn:va);return"j"in r?o.setFullYear(r.y,0,r.j):"W"in r||"U"in r?("w"in r||(r.w="W"in r?1:0),o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(r.Z/100|0),r.M+r.Z%100,r.S,r.L),u?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var i,u,o,a=0,l=t.length,c=e.length;l>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(o=t.charAt(a++),u=C[o in ya?t.charAt(a++):o],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){N.lastIndex=0;var r=N.exec(t.slice(e));return r?(n.m=E.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,A.c.toString(),t,r)}function l(n,t,r){return e(n,A.x.toString(),t,r)}function c(n,t,r){return e(n,A.X.toString(),t,r)}function f(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var s=n.dateTime,h=n.date,p=n.time,g=n.periods,v=n.days,d=n.shortDays,y=n.months,m=n.shortMonths;t.utc=function(n){function e(n){try{va=Hn;var t=new va;return t._=n,r(t)}finally{va=Date}}var r=t(n);return e.parse=function(n){try{va=Hn;var t=r.parse(n);return t&&t._}finally{va=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ct;var M=ao.map(),x=Vn(v),b=Xn(v),_=Vn(d),w=Xn(d),S=Vn(y),k=Xn(y),N=Vn(m),E=Xn(m);g.forEach(function(n,t){M.set(n.toLowerCase(),t)});var A={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return m[n.getMonth()]},B:function(n){return y[n.getMonth()]},c:t(s),d:function(n,t){return Zn(n.getDate(),t,2)},e:function(n,t){return Zn(n.getDate(),t,2)},H:function(n,t){return Zn(n.getHours(),t,2)},I:function(n,t){return Zn(n.getHours()%12||12,t,2)},j:function(n,t){return Zn(1+ga.dayOfYear(n),t,3)},L:function(n,t){return Zn(n.getMilliseconds(),t,3)},m:function(n,t){return Zn(n.getMonth()+1,t,2)},M:function(n,t){return Zn(n.getMinutes(),t,2)},p:function(n){return g[+(n.getHours()>=12)]},S:function(n,t){return Zn(n.getSeconds(),t,2)},U:function(n,t){return Zn(ga.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Zn(ga.mondayOfYear(n),t,2)},x:t(h),X:t(p),y:function(n,t){return Zn(n.getFullYear()%100,t,2)},Y:function(n,t){return Zn(n.getFullYear()%1e4,t,4)},Z:at,"%":function(){return"%"}},C={a:r,A:i,b:u,B:o,c:a,d:tt,e:tt,H:rt,I:rt,j:et,L:ot,m:nt,M:it,p:f,S:ut,U:Bn,w:$n,W:Wn,x:l,X:c,y:Gn,Y:Jn,Z:Kn,"%":lt};return t}function Zn(n,t,e){var r=0>n?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Vn(n){return new RegExp("^(?:"+n.map(ao.requote).join("|")+")","i")}function Xn(n){for(var t=new c,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function $n(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Bn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function Wn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Jn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Gn(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.y=Qn(+r[0]),e+r[0].length):-1}function Kn(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Qn(n){return n+(n>68?1900:2e3)}function nt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function tt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function et(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function rt(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function it(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ut(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ot(n,t,e){ma.lastIndex=0;var r=ma.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function at(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=xo(t)/60|0,i=xo(t)%60;return e+Zn(r,"0",2)+Zn(i,"0",2)}function lt(n,t,e){Ma.lastIndex=0;var r=Ma.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ct(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ft(){}function st(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function ht(n,t){n&&wa.hasOwnProperty(n.type)&&wa[n.type](n,t)}function pt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++i<u;)r=n[i],t.point(r[0],r[1],r[2]);t.lineEnd()}function gt(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)pt(n[e],t,1);t.polygonEnd()}function vt(){function n(n,t){n*=Yo,t=t*Yo/2+Fo/4;var e=n-r,o=e>=0?1:-1,a=o*e,l=Math.cos(t),c=Math.sin(t),f=u*c,s=i*l+f*Math.cos(a),h=f*o*Math.sin(a);ka.add(Math.atan2(h,s)),r=n,i=l,u=c}var t,e,r,i,u;Na.point=function(o,a){Na.point=n,r=(t=o)*Yo,i=Math.cos(a=(e=a)*Yo/2+Fo/4),u=Math.sin(a)},Na.lineEnd=function(){n(t,e)}}function dt(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function yt(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function mt(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function Mt(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function xt(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function bt(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function _t(n){return[Math.atan2(n[1],n[0]),tn(n[2])]}function wt(n,t){return xo(n[0]-t[0])<Uo&&xo(n[1]-t[1])<Uo}function St(n,t){n*=Yo;var e=Math.cos(t*=Yo);kt(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function kt(n,t,e){++Ea,Ca+=(n-Ca)/Ea,za+=(t-za)/Ea,La+=(e-La)/Ea}function Nt(){function n(n,i){n*=Yo;var u=Math.cos(i*=Yo),o=u*Math.cos(n),a=u*Math.sin(n),l=Math.sin(i),c=Math.atan2(Math.sqrt((c=e*l-r*a)*c+(c=r*o-t*l)*c+(c=t*a-e*o)*c),t*o+e*a+r*l);Aa+=c,qa+=c*(t+(t=o)),Ta+=c*(e+(e=a)),Ra+=c*(r+(r=l)),kt(t,e,r)}var t,e,r;ja.point=function(i,u){i*=Yo;var o=Math.cos(u*=Yo);t=o*Math.cos(i),e=o*Math.sin(i),r=Math.sin(u),ja.point=n,kt(t,e,r)}}function Et(){ja.point=St}function At(){function n(n,t){n*=Yo;var e=Math.cos(t*=Yo),o=e*Math.cos(n),a=e*Math.sin(n),l=Math.sin(t),c=i*l-u*a,f=u*o-r*l,s=r*a-i*o,h=Math.sqrt(c*c+f*f+s*s),p=r*o+i*a+u*l,g=h&&-nn(p)/h,v=Math.atan2(h,p);Da+=g*c,Pa+=g*f,Ua+=g*s,Aa+=v,qa+=v*(r+(r=o)),Ta+=v*(i+(i=a)),Ra+=v*(u+(u=l)),kt(r,i,u)}var t,e,r,i,u;ja.point=function(o,a){t=o,e=a,ja.point=n,o*=Yo;var l=Math.cos(a*=Yo);r=l*Math.cos(o),i=l*Math.sin(o),u=Math.sin(a),kt(r,i,u)},ja.lineEnd=function(){n(t,e),ja.lineEnd=Et,ja.point=St}}function Ct(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function zt(){return!0}function Lt(n,t,e,r,i){var u=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(wt(e,r)){i.lineStart();for(var a=0;t>a;++a)i.point((e=n[a])[0],e[1]);return void i.lineEnd()}var l=new Tt(e,n,null,!0),c=new Tt(e,null,l,!1);l.o=c,u.push(l),o.push(c),l=new Tt(r,n,null,!1),c=new Tt(r,null,l,!0),l.o=c,u.push(l),o.push(c)}}),o.sort(t),qt(u),qt(o),u.length){for(var a=0,l=e,c=o.length;c>a;++a)o[a].e=l=!l;for(var f,s,h=u[0];;){for(var p=h,g=!0;p.v;)if((p=p.n)===h)return;f=p.z,i.lineStart();do{if(p.v=p.o.v=!0,p.e){if(g)for(var a=0,c=f.length;c>a;++a)i.point((s=f[a])[0],s[1]);else r(p.x,p.n.x,1,i);p=p.n}else{if(g){f=p.p.z;for(var a=f.length-1;a>=0;--a)i.point((s=f[a])[0],s[1])}else r(p.x,p.p.x,-1,i);p=p.p}p=p.o,f=p.z,g=!g}while(!p.v);i.lineEnd()}}}function qt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r<t;)i.n=e=n[r],e.p=i,i=e;i.n=e=n[0],e.p=i}}function Tt(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Rt(n,t,e,r){return function(i,u){function o(t,e){var r=i(t,e);n(t=r[0],e=r[1])&&u.point(t,e)}function a(n,t){var e=i(n,t);d.point(e[0],e[1])}function l(){m.point=a,d.lineStart()}function c(){m.point=o,d.lineEnd()}function f(n,t){v.push([n,t]);var e=i(n,t);x.point(e[0],e[1])}function s(){x.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),x.lineEnd();var n,t=x.clean(),e=M.buffer(),r=e.length;if(v.pop(),g.push(v),v=null,r)if(1&t){n=e[0];var i,r=n.length-1,o=-1;if(r>0){for(b||(u.polygonStart(),b=!0),u.lineStart();++o<r;)u.point((i=n[o])[0],i[1]);u.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),p.push(e.filter(Dt))}var p,g,v,d=t(u),y=i.invert(r[0],r[1]),m={point:o,lineStart:l,lineEnd:c,polygonStart:function(){m.point=f,m.lineStart=s,m.lineEnd=h,p=[],g=[]},polygonEnd:function(){m.point=o,m.lineStart=l,m.lineEnd=c,p=ao.merge(p);var n=Ot(y,g);p.length?(b||(u.polygonStart(),b=!0),Lt(p,Ut,n,e,u)):n&&(b||(u.polygonStart(),b=!0),u.lineStart(),e(null,null,1,u),u.lineEnd()),b&&(u.polygonEnd(),b=!1),p=g=null},sphere:function(){u.polygonStart(),u.lineStart(),e(null,null,1,u),u.lineEnd(),u.polygonEnd()}},M=Pt(),x=t(M),b=!1;return m}}function Dt(n){return n.length>1}function Pt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ut(n,t){return((n=n.x)[0]<0?n[1]-Io-Uo:Io-n[1])-((t=t.x)[0]<0?t[1]-Io-Uo:Io-t[1])}function jt(n){var t,e=NaN,r=NaN,i=NaN;return{lineStart:function(){n.lineStart(),t=1},point:function(u,o){var a=u>0?Fo:-Fo,l=xo(u-e);xo(l-Fo)<Uo?(n.point(e,r=(r+o)/2>0?Io:-Io),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(u,r),t=0):i!==a&&l>=Fo&&(xo(e-i)<Uo&&(e-=i*Uo),xo(u-a)<Uo&&(u-=a*Uo),r=Ft(e,r,u,o),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=u,r=o),i=a},lineEnd:function(){n.lineEnd(),e=r=NaN},clean:function(){return 2-t}}}function Ft(n,t,e,r){var i,u,o=Math.sin(n-e);return xo(o)>Uo?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*o)):(t+r)/2}function Ht(n,t,e,r){var i;if(null==n)i=e*Io,r.point(-Fo,i),r.point(0,i),r.point(Fo,i),r.point(Fo,0),r.point(Fo,-i),r.point(0,-i),r.point(-Fo,-i),r.point(-Fo,0),r.point(-Fo,i);else if(xo(n[0]-t[0])>Uo){var u=n[0]<t[0]?Fo:-Fo;i=e*u/2,r.point(-u,i),r.point(0,i),r.point(u,i)}else r.point(t[0],t[1])}function Ot(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,o=0;ka.reset();for(var a=0,l=t.length;l>a;++a){var c=t[a],f=c.length;if(f)for(var s=c[0],h=s[0],p=s[1]/2+Fo/4,g=Math.sin(p),v=Math.cos(p),d=1;;){d===f&&(d=0),n=c[d];var y=n[0],m=n[1]/2+Fo/4,M=Math.sin(m),x=Math.cos(m),b=y-h,_=b>=0?1:-1,w=_*b,S=w>Fo,k=g*M;if(ka.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),u+=S?b+_*Ho:b,S^h>=e^y>=e){var N=mt(dt(s),dt(n));bt(N);var E=mt(i,N);bt(E);var A=(S^b>=0?-1:1)*tn(E[2]);(r>A||r===A&&(N[0]||N[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=y,g=M,v=x,s=n}}return(-Uo>u||Uo>u&&-Uo>ka)^1&o}function It(n){function t(n,t){return Math.cos(n)*Math.cos(t)>u}function e(n){var e,u,l,c,f;return{lineStart:function(){c=l=!1,f=1},point:function(s,h){var p,g=[s,h],v=t(s,h),d=o?v?0:i(s,h):v?i(s+(0>s?Fo:-Fo),h):0;if(!e&&(c=l=v)&&n.lineStart(),v!==l&&(p=r(e,g),(wt(e,p)||wt(g,p))&&(g[0]+=Uo,g[1]+=Uo,v=t(g[0],g[1]))),v!==l)f=0,v?(n.lineStart(),p=r(g,e),n.point(p[0],p[1])):(p=r(e,g),n.point(p[0],p[1]),n.lineEnd()),e=p;else if(a&&e&&o^v){var y;d&u||!(y=r(g,e,!0))||(f=0,o?(n.lineStart(),n.point(y[0][0],y[0][1]),n.point(y[1][0],y[1][1]),n.lineEnd()):(n.point(y[1][0],y[1][1]),n.lineEnd(),n.lineStart(),n.point(y[0][0],y[0][1])))}!v||e&&wt(e,g)||n.point(g[0],g[1]),e=g,l=v,u=d},lineEnd:function(){l&&n.lineEnd(),e=null},clean:function(){return f|(c&&l)<<1}}}function r(n,t,e){var r=dt(n),i=dt(t),o=[1,0,0],a=mt(r,i),l=yt(a,a),c=a[0],f=l-c*c;if(!f)return!e&&n;var s=u*l/f,h=-u*c/f,p=mt(o,a),g=xt(o,s),v=xt(a,h);Mt(g,v);var d=p,y=yt(g,d),m=yt(d,d),M=y*y-m*(yt(g,g)-1);if(!(0>M)){var x=Math.sqrt(M),b=xt(d,(-y-x)/m);if(Mt(b,g),b=_t(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],N=t[1];w>S&&(_=w,w=S,S=_);var E=S-w,A=xo(E-Fo)<Uo,C=A||Uo>E;if(!A&&k>N&&(_=k,k=N,N=_),C?A?k+N>0^b[1]<(xo(b[0]-w)<Uo?k:N):k<=b[1]&&b[1]<=N:E>Fo^(w<=b[0]&&b[0]<=S)){var z=xt(d,(-y+x)/m);return Mt(z,g),[b,_t(z)]}}}function i(t,e){var r=o?n:Fo-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}var u=Math.cos(n),o=u>0,a=xo(u)>Uo,l=ve(n,6*Yo);return Rt(t,e,l,o?[0,-n]:[-Fo,n-Fo])}function Yt(n,t,e,r){return function(i){var u,o=i.a,a=i.b,l=o.x,c=o.y,f=a.x,s=a.y,h=0,p=1,g=f-l,v=s-c;if(u=n-l,g||!(u>0)){if(u/=g,0>g){if(h>u)return;p>u&&(p=u)}else if(g>0){if(u>p)return;u>h&&(h=u)}if(u=e-l,g||!(0>u)){if(u/=g,0>g){if(u>p)return;u>h&&(h=u)}else if(g>0){if(h>u)return;p>u&&(p=u)}if(u=t-c,v||!(u>0)){if(u/=v,0>v){if(h>u)return;p>u&&(p=u)}else if(v>0){if(u>p)return;u>h&&(h=u)}if(u=r-c,v||!(0>u)){if(u/=v,0>v){if(u>p)return;u>h&&(h=u)}else if(v>0){if(h>u)return;p>u&&(p=u)}return h>0&&(i.a={x:l+h*g,y:c+h*v}),1>p&&(i.b={x:l+p*g,y:c+p*v}),i}}}}}}function Zt(n,t,e,r){function i(r,i){return xo(r[0]-n)<Uo?i>0?0:3:xo(r[0]-e)<Uo?i>0?2:1:xo(r[1]-t)<Uo?i>0?1:0:i>0?3:2}function u(n,t){return o(n.x,t.x)}function o(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function l(n){for(var t=0,e=d.length,r=n[1],i=0;e>i;++i)for(var u,o=1,a=d[i],l=a.length,c=a[0];l>o;++o)u=a[o],c[1]<=r?u[1]>r&&Q(c,u,n)>0&&++t:u[1]<=r&&Q(c,u,n)<0&&--t,c=u;return 0!==t}function c(u,a,l,c){var f=0,s=0;if(null==u||(f=i(u,l))!==(s=i(a,l))||o(u,a)<0^l>0){do c.point(0===f||3===f?n:e,f>1?r:t);while((f=(f+l+4)%4)!==s)}else c.point(a[0],a[1])}function f(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function s(n,t){f(n,t)&&a.point(n,t)}function h(){C.point=g,d&&d.push(y=[]),S=!0,w=!1,b=_=NaN}function p(){v&&(g(m,M),x&&w&&E.rejoin(),v.push(E.buffer())),C.point=s,w&&a.lineEnd()}function g(n,t){n=Math.max(-Ha,Math.min(Ha,n)),t=Math.max(-Ha,Math.min(Ha,t));var e=f(n,t);if(d&&y.push([n,t]),S)m=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};A(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,y,m,M,x,b,_,w,S,k,N=a,E=Pt(),A=Yt(n,t,e,r),C={point:s,lineStart:h,lineEnd:p,polygonStart:function(){a=E,v=[],d=[],k=!0},polygonEnd:function(){a=N,v=ao.merge(v);var t=l([n,r]),e=k&&t,i=v.length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),c(null,null,1,a),a.lineEnd()),i&&Lt(v,u,t,c,a),a.polygonEnd()),v=d=y=null}};return C}}function Vt(n){var t=0,e=Fo/3,r=ae(n),i=r(t,e);return i.parallels=function(n){return arguments.length?r(t=n[0]*Fo/180,e=n[1]*Fo/180):[t/Fo*180,e/Fo*180]},i}function Xt(n,t){function e(n,t){var e=Math.sqrt(u-2*i*Math.sin(t))/i;return[e*Math.sin(n*=i),o-e*Math.cos(n)]}var r=Math.sin(n),i=(r+Math.sin(t))/2,u=1+r*(2*i-r),o=Math.sqrt(u)/i;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/i,tn((u-(n*n+e*e)*i*i)/(2*i))]},e}function $t(){function n(n,t){Ia+=i*n-r*t,r=n,i=t}var t,e,r,i;$a.point=function(u,o){$a.point=n,t=r=u,e=i=o},$a.lineEnd=function(){n(t,e)}}function Bt(n,t){Ya>n&&(Ya=n),n>Va&&(Va=n),Za>t&&(Za=t),t>Xa&&(Xa=t)}function Wt(){function n(n,t){o.push("M",n,",",t,u)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function i(){o.push("Z")}var u=Jt(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return u=Jt(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Jt(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Gt(n,t){Ca+=n,za+=t,++La}function Kt(){function n(n,r){var i=n-t,u=r-e,o=Math.sqrt(i*i+u*u);qa+=o*(t+n)/2,Ta+=o*(e+r)/2,Ra+=o,Gt(t=n,e=r)}var t,e;Wa.point=function(r,i){Wa.point=n,Gt(t=r,e=i)}}function Qt(){Wa.point=Gt}function ne(){function n(n,t){var e=n-r,u=t-i,o=Math.sqrt(e*e+u*u);qa+=o*(r+n)/2,Ta+=o*(i+t)/2,Ra+=o,o=i*n-r*t,Da+=o*(r+n),Pa+=o*(i+t),Ua+=3*o,Gt(r=n,i=t)}var t,e,r,i;Wa.point=function(u,o){Wa.point=n,Gt(t=r=u,e=i=o)},Wa.lineEnd=function(){n(t,e)}}function te(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,Ho)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function i(){a.point=t}function u(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:i,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=i,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function ee(n){function t(n){return(a?r:e)(n)}function e(t){return ue(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=NaN,S.point=u,t.lineStart()}function u(e,r){var u=dt([e,r]),o=n(e,r);i(M,x,m,b,_,w,M=o[0],x=o[1],m=e,b=u[0],_=u[1],w=u[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function l(){
r(),S.point=c,S.lineEnd=f}function c(n,t){u(s=n,h=t),p=M,g=x,v=b,d=_,y=w,S.point=u}function f(){i(M,x,m,b,_,w,p,g,s,v,d,y,a,t),S.lineEnd=o,o()}var s,h,p,g,v,d,y,m,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=l},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function i(t,e,r,a,l,c,f,s,h,p,g,v,d,y){var m=f-t,M=s-e,x=m*m+M*M;if(x>4*u&&d--){var b=a+p,_=l+g,w=c+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),N=xo(xo(w)-1)<Uo||xo(r-h)<Uo?(r+h)/2:Math.atan2(_,b),E=n(N,k),A=E[0],C=E[1],z=A-t,L=C-e,q=M*z-m*L;(q*q/x>u||xo((m*z+M*L)/x-.5)>.3||o>a*p+l*g+c*v)&&(i(t,e,r,a,l,c,A,C,N,b/=S,_/=S,w,d,y),y.point(A,C),i(A,C,N,b,_,w,f,s,h,p,g,v,d,y))}}var u=.5,o=Math.cos(30*Yo),a=16;return t.precision=function(n){return arguments.length?(a=(u=n*n)>0&&16,t):Math.sqrt(u)},t}function re(n){var t=ee(function(t,e){return n([t*Zo,e*Zo])});return function(n){return le(t(n))}}function ie(n){this.stream=n}function ue(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function oe(n){return ae(function(){return n})()}function ae(n){function t(n){return n=a(n[0]*Yo,n[1]*Yo),[n[0]*h+l,c-n[1]*h]}function e(n){return n=a.invert((n[0]-l)/h,(c-n[1])/h),n&&[n[0]*Zo,n[1]*Zo]}function r(){a=Ct(o=se(y,M,x),u);var n=u(v,d);return l=p-n[0]*h,c=g+n[1]*h,i()}function i(){return f&&(f.valid=!1,f=null),t}var u,o,a,l,c,f,s=ee(function(n,t){return n=u(n,t),[n[0]*h+l,c-n[1]*h]}),h=150,p=480,g=250,v=0,d=0,y=0,M=0,x=0,b=Fa,_=m,w=null,S=null;return t.stream=function(n){return f&&(f.valid=!1),f=le(b(o,s(_(n)))),f.valid=!0,f},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Fa):It((w=+n)*Yo),i()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Zt(n[0][0],n[0][1],n[1][0],n[1][1]):m,i()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(p=+n[0],g=+n[1],r()):[p,g]},t.center=function(n){return arguments.length?(v=n[0]%360*Yo,d=n[1]%360*Yo,r()):[v*Zo,d*Zo]},t.rotate=function(n){return arguments.length?(y=n[0]%360*Yo,M=n[1]%360*Yo,x=n.length>2?n[2]%360*Yo:0,r()):[y*Zo,M*Zo,x*Zo]},ao.rebind(t,s,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function le(n){return ue(n,function(t,e){n.point(t*Yo,e*Yo)})}function ce(n,t){return[n,t]}function fe(n,t){return[n>Fo?n-Ho:-Fo>n?n+Ho:n,t]}function se(n,t,e){return n?t||e?Ct(pe(n),ge(t,e)):pe(n):t||e?ge(t,e):fe}function he(n){return function(t,e){return t+=n,[t>Fo?t-Ho:-Fo>t?t+Ho:t,e]}}function pe(n){var t=he(n);return t.invert=he(-n),t}function ge(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*r+a*i;return[Math.atan2(l*u-f*o,a*r-c*i),tn(f*u+l*o)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,l=Math.sin(n)*e,c=Math.sin(t),f=c*u-l*o;return[Math.atan2(l*u+c*o,a*r+f*i),tn(f*r-a*i)]},e}function ve(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,o,a){var l=o*t;null!=i?(i=de(e,i),u=de(e,u),(o>0?u>i:i>u)&&(i+=o*Ho)):(i=n+o*Ho,u=n-.5*l);for(var c,f=i;o>0?f>u:u>f;f-=l)a.point((c=_t([e,-r*Math.cos(f),-r*Math.sin(f)]))[0],c[1])}}function de(n,t){var e=dt(t);e[0]-=n,bt(e);var r=nn(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Uo)%(2*Math.PI)}function ye(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function me(n,t,e){var r=ao.range(n,t-Uo,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function Me(n){return n.source}function xe(n){return n.target}function be(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),o=Math.cos(r),a=Math.sin(r),l=i*Math.cos(n),c=i*Math.sin(n),f=o*Math.cos(e),s=o*Math.sin(e),h=2*Math.asin(Math.sqrt(on(r-t)+i*o*on(e-n))),p=1/Math.sin(h),g=h?function(n){var t=Math.sin(n*=h)*p,e=Math.sin(h-n)*p,r=e*l+t*f,i=e*c+t*s,o=e*u+t*a;return[Math.atan2(i,r)*Zo,Math.atan2(o,Math.sqrt(r*r+i*i))*Zo]}:function(){return[n*Zo,t*Zo]};return g.distance=h,g}function _e(){function n(n,i){var u=Math.sin(i*=Yo),o=Math.cos(i),a=xo((n*=Yo)-t),l=Math.cos(a);Ja+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*u-e*o*l)*a),e*u+r*o*l),t=n,e=u,r=o}var t,e,r;Ga.point=function(i,u){t=i*Yo,e=Math.sin(u*=Yo),r=Math.cos(u),Ga.point=n},Ga.lineEnd=function(){Ga.point=Ga.lineEnd=b}}function we(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),o=Math.cos(i);return[Math.atan2(n*u,r*o),Math.asin(r&&e*u/r)]},e}function Se(n,t){function e(n,t){o>0?-Io+Uo>t&&(t=-Io+Uo):t>Io-Uo&&(t=Io-Uo);var e=o/Math.pow(i(t),u);return[e*Math.sin(u*n),o-e*Math.cos(u*n)]}var r=Math.cos(n),i=function(n){return Math.tan(Fo/4+n/2)},u=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(i(t)/i(n)),o=r*Math.pow(i(n),u)/u;return u?(e.invert=function(n,t){var e=o-t,r=K(u)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/u,2*Math.atan(Math.pow(o/r,1/u))-Io]},e):Ne}function ke(n,t){function e(n,t){var e=u-t;return[e*Math.sin(i*n),u-e*Math.cos(i*n)]}var r=Math.cos(n),i=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),u=r/i+n;return xo(i)<Uo?ce:(e.invert=function(n,t){var e=u-t;return[Math.atan2(n,e)/i,u-K(i)*Math.sqrt(n*n+e*e)]},e)}function Ne(n,t){return[n,Math.log(Math.tan(Fo/4+t/2))]}function Ee(n){var t,e=oe(n),r=e.scale,i=e.translate,u=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=i.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=u.apply(e,arguments);if(o===e){if(t=null==n){var a=Fo*r(),l=i();u([[l[0]-a,l[1]-a],[l[0]+a,l[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Ae(n,t){return[Math.log(Math.tan(Fo/4+t/2)),-n]}function Ce(n){return n[0]}function ze(n){return n[1]}function Le(n){for(var t=n.length,e=[0,1],r=2,i=2;t>i;i++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function qe(n,t){return n[0]-t[0]||n[1]-t[1]}function Te(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Re(n,t,e,r){var i=n[0],u=e[0],o=t[0]-i,a=r[0]-u,l=n[1],c=e[1],f=t[1]-l,s=r[1]-c,h=(a*(l-c)-s*(i-u))/(s*o-a*f);return[i+h*o,l+h*f]}function De(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Pe(){rr(this),this.edge=this.site=this.circle=null}function Ue(n){var t=cl.pop()||new Pe;return t.site=n,t}function je(n){Be(n),ol.remove(n),cl.push(n),rr(n)}function Fe(n){var t=n.circle,e=t.x,r=t.cy,i={x:e,y:r},u=n.P,o=n.N,a=[n];je(n);for(var l=u;l.circle&&xo(e-l.circle.x)<Uo&&xo(r-l.circle.cy)<Uo;)u=l.P,a.unshift(l),je(l),l=u;a.unshift(l),Be(l);for(var c=o;c.circle&&xo(e-c.circle.x)<Uo&&xo(r-c.circle.cy)<Uo;)o=c.N,a.push(c),je(c),c=o;a.push(c),Be(c);var f,s=a.length;for(f=1;s>f;++f)c=a[f],l=a[f-1],nr(c.edge,l.site,c.site,i);l=a[0],c=a[s-1],c.edge=Ke(l.site,c.site,null,i),$e(l),$e(c)}function He(n){for(var t,e,r,i,u=n.x,o=n.y,a=ol._;a;)if(r=Oe(a,o)-u,r>Uo)a=a.L;else{if(i=u-Ie(a,o),!(i>Uo)){r>-Uo?(t=a.P,e=a):i>-Uo?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var l=Ue(n);if(ol.insert(t,l),t||e){if(t===e)return Be(t),e=Ue(t.site),ol.insert(l,e),l.edge=e.edge=Ke(t.site,l.site),$e(t),void $e(e);if(!e)return void(l.edge=Ke(t.site,l.site));Be(t),Be(e);var c=t.site,f=c.x,s=c.y,h=n.x-f,p=n.y-s,g=e.site,v=g.x-f,d=g.y-s,y=2*(h*d-p*v),m=h*h+p*p,M=v*v+d*d,x={x:(d*m-p*M)/y+f,y:(h*M-v*m)/y+s};nr(e.edge,c,g,x),l.edge=Ke(c,n,null,x),e.edge=Ke(n,g,null,x),$e(t),$e(e)}}function Oe(n,t){var e=n.site,r=e.x,i=e.y,u=i-t;if(!u)return r;var o=n.P;if(!o)return-(1/0);e=o.site;var a=e.x,l=e.y,c=l-t;if(!c)return a;var f=a-r,s=1/u-1/c,h=f/c;return s?(-h+Math.sqrt(h*h-2*s*(f*f/(-2*c)-l+c/2+i-u/2)))/s+r:(r+a)/2}function Ie(n,t){var e=n.N;if(e)return Oe(e,t);var r=n.site;return r.y===t?r.x:1/0}function Ye(n){this.site=n,this.edges=[]}function Ze(n){for(var t,e,r,i,u,o,a,l,c,f,s=n[0][0],h=n[1][0],p=n[0][1],g=n[1][1],v=ul,d=v.length;d--;)if(u=v[d],u&&u.prepare())for(a=u.edges,l=a.length,o=0;l>o;)f=a[o].end(),r=f.x,i=f.y,c=a[++o%l].start(),t=c.x,e=c.y,(xo(r-t)>Uo||xo(i-e)>Uo)&&(a.splice(o,0,new tr(Qe(u.site,f,xo(r-s)<Uo&&g-i>Uo?{x:s,y:xo(t-s)<Uo?e:g}:xo(i-g)<Uo&&h-r>Uo?{x:xo(e-g)<Uo?t:h,y:g}:xo(r-h)<Uo&&i-p>Uo?{x:h,y:xo(t-h)<Uo?e:p}:xo(i-p)<Uo&&r-s>Uo?{x:xo(e-p)<Uo?t:s,y:p}:null),u.site,null)),++l)}function Ve(n,t){return t.angle-n.angle}function Xe(){rr(this),this.x=this.y=this.arc=this.site=this.cy=null}function $e(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,i=n.site,u=e.site;if(r!==u){var o=i.x,a=i.y,l=r.x-o,c=r.y-a,f=u.x-o,s=u.y-a,h=2*(l*s-c*f);if(!(h>=-jo)){var p=l*l+c*c,g=f*f+s*s,v=(s*p-c*g)/h,d=(l*g-f*p)/h,s=d+a,y=fl.pop()||new Xe;y.arc=n,y.site=i,y.x=v+o,y.y=s+Math.sqrt(v*v+d*d),y.cy=s,n.circle=y;for(var m=null,M=ll._;M;)if(y.y<M.y||y.y===M.y&&y.x<=M.x){if(!M.L){m=M.P;break}M=M.L}else{if(!M.R){m=M;break}M=M.R}ll.insert(m,y),m||(al=y)}}}}function Be(n){var t=n.circle;t&&(t.P||(al=t.N),ll.remove(t),fl.push(t),rr(t),n.circle=null)}function We(n){for(var t,e=il,r=Yt(n[0][0],n[0][1],n[1][0],n[1][1]),i=e.length;i--;)t=e[i],(!Je(t,n)||!r(t)||xo(t.a.x-t.b.x)<Uo&&xo(t.a.y-t.b.y)<Uo)&&(t.a=t.b=null,e.splice(i,1))}function Je(n,t){var e=n.b;if(e)return!0;var r,i,u=n.a,o=t[0][0],a=t[1][0],l=t[0][1],c=t[1][1],f=n.l,s=n.r,h=f.x,p=f.y,g=s.x,v=s.y,d=(h+g)/2,y=(p+v)/2;if(v===p){if(o>d||d>=a)return;if(h>g){if(u){if(u.y>=c)return}else u={x:d,y:l};e={x:d,y:c}}else{if(u){if(u.y<l)return}else u={x:d,y:c};e={x:d,y:l}}}else if(r=(h-g)/(v-p),i=y-r*d,-1>r||r>1)if(h>g){if(u){if(u.y>=c)return}else u={x:(l-i)/r,y:l};e={x:(c-i)/r,y:c}}else{if(u){if(u.y<l)return}else u={x:(c-i)/r,y:c};e={x:(l-i)/r,y:l}}else if(v>p){if(u){if(u.x>=a)return}else u={x:o,y:r*o+i};e={x:a,y:r*a+i}}else{if(u){if(u.x<o)return}else u={x:a,y:r*a+i};e={x:o,y:r*o+i}}return n.a=u,n.b=e,!0}function Ge(n,t){this.l=n,this.r=t,this.a=this.b=null}function Ke(n,t,e,r){var i=new Ge(n,t);return il.push(i),e&&nr(i,n,t,e),r&&nr(i,t,n,r),ul[n.i].edges.push(new tr(i,n,t)),ul[t.i].edges.push(new tr(i,t,n)),i}function Qe(n,t,e){var r=new Ge(n,null);return r.a=t,r.b=e,il.push(r),r}function nr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function tr(n,t,e){var r=n.a,i=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(i.x-r.x,r.y-i.y):Math.atan2(r.x-i.x,i.y-r.y)}function er(){this._=null}function rr(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function ir(n,t){var e=t,r=t.R,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ur(n,t){var e=t,r=t.L,i=e.U;i?i.L===e?i.L=r:i.R=r:n._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function or(n){for(;n.L;)n=n.L;return n}function ar(n,t){var e,r,i,u=n.sort(lr).pop();for(il=[],ul=new Array(n.length),ol=new er,ll=new er;;)if(i=al,u&&(!i||u.y<i.y||u.y===i.y&&u.x<i.x))u.x===e&&u.y===r||(ul[u.i]=new Ye(u),He(u),e=u.x,r=u.y),u=n.pop();else{if(!i)break;Fe(i.arc)}t&&(We(t),Ze(t));var o={cells:ul,edges:il};return ol=ll=il=ul=null,o}function lr(n,t){return t.y-n.y||t.x-n.x}function cr(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function fr(n){return n.x}function sr(n){return n.y}function hr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function pr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var o=.5*(e+i),a=.5*(r+u),l=t.nodes;l[0]&&pr(n,l[0],e,r,o,a),l[1]&&pr(n,l[1],o,r,i,a),l[2]&&pr(n,l[2],e,a,o,u),l[3]&&pr(n,l[3],o,a,i,u)}}function gr(n,t,e,r,i,u,o){var a,l=1/0;return function c(n,f,s,h,p){if(!(f>u||s>o||r>h||i>p)){if(g=n.point){var g,v=t-n.x,d=e-n.y,y=v*v+d*d;if(l>y){var m=Math.sqrt(l=y);r=t-m,i=e-m,u=t+m,o=e+m,a=g}}for(var M=n.nodes,x=.5*(f+h),b=.5*(s+p),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:c(n,f,s,x,b);break;case 1:c(n,x,s,h,b);break;case 2:c(n,f,b,x,p);break;case 3:c(n,x,b,h,p)}}}(n,r,i,u,o),a}function vr(n,t){n=ao.rgb(n),t=ao.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,o=t.g-r,a=t.b-i;return function(n){return"#"+bn(Math.round(e+u*n))+bn(Math.round(r+o*n))+bn(Math.round(i+a*n))}}function dr(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Mr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function yr(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function mr(n,t){var e,r,i,u=hl.lastIndex=pl.lastIndex=0,o=-1,a=[],l=[];for(n+="",t+="";(e=hl.exec(n))&&(r=pl.exec(t));)(i=r.index)>u&&(i=t.slice(u,i),a[o]?a[o]+=i:a[++o]=i),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,l.push({i:o,x:yr(e,r)})),u=pl.lastIndex;return u<t.length&&(i=t.slice(u),a[o]?a[o]+=i:a[++o]=i),a.length<2?l[0]?(t=l[0].x,function(n){return t(n)+""}):function(){return t}:(t=l.length,function(n){for(var e,r=0;t>r;++r)a[(e=l[r]).i]=e.x(n);return a.join("")})}function Mr(n,t){for(var e,r=ao.interpolators.length;--r>=0&&!(e=ao.interpolators[r](n,t)););return e}function xr(n,t){var e,r=[],i=[],u=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(Mr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;o>e;++e)i[e]=t[e];return function(n){for(e=0;a>e;++e)i[e]=r[e](n);return i}}function br(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function _r(n){return function(t){return 1-n(1-t)}}function wr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function Sr(n){return n*n}function kr(n){return n*n*n}function Nr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Er(n){return function(t){return Math.pow(t,n)}}function Ar(n){return 1-Math.cos(n*Io)}function Cr(n){return Math.pow(2,10*(n-1))}function zr(n){return 1-Math.sqrt(1-n*n)}function Lr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Ho*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Ho/t)}}function qr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Tr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Rr(n,t){n=ao.hcl(n),t=ao.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,o=t.c-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return sn(e+u*n,r+o*n,i+a*n)+""}}function Dr(n,t){n=ao.hsl(n),t=ao.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,o=t.s-r,a=t.l-i;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return cn(e+u*n,r+o*n,i+a*n)+""}}function Pr(n,t){n=ao.lab(n),t=ao.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,o=t.a-r,a=t.b-i;return function(n){return pn(e+u*n,r+o*n,i+a*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function jr(n){var t=[n.a,n.b],e=[n.c,n.d],r=Hr(t),i=Fr(t,e),u=Hr(Or(e,t,-i))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,i*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Zo,this.translate=[n.e,n.f],this.scale=[r,u],this.skew=u?Math.atan2(i,u)*Zo:0}function Fr(n,t){return n[0]*t[0]+n[1]*t[1]}function Hr(n){var t=Math.sqrt(Fr(n,n));return t&&(n[0]/=t,n[1]/=t),t}function Or(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Ir(n){return n.length?n.pop()+",":""}function Yr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push("translate(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else(t[0]||t[1])&&e.push("translate("+t+")")}function Zr(n,t,e,r){n!==t?(n-t>180?t+=360:t-n>180&&(n+=360),r.push({i:e.push(Ir(e)+"rotate(",null,")")-2,x:yr(n,t)})):t&&e.push(Ir(e)+"rotate("+t+")")}function Vr(n,t,e,r){n!==t?r.push({i:e.push(Ir(e)+"skewX(",null,")")-2,x:yr(n,t)}):t&&e.push(Ir(e)+"skewX("+t+")")}function Xr(n,t,e,r){if(n[0]!==t[0]||n[1]!==t[1]){var i=e.push(Ir(e)+"scale(",null,",",null,")");r.push({i:i-4,x:yr(n[0],t[0])},{i:i-2,x:yr(n[1],t[1])})}else 1===t[0]&&1===t[1]||e.push(Ir(e)+"scale("+t+")")}function $r(n,t){var e=[],r=[];return n=ao.transform(n),t=ao.transform(t),Yr(n.translate,t.translate,e,r),Zr(n.rotate,t.rotate,e,r),Vr(n.skew,t.skew,e,r),Xr(n.scale,t.scale,e,r),n=t=null,function(n){for(var t,i=-1,u=r.length;++i<u;)e[(t=r[i]).i]=t.x(n);return e.join("")}}function Br(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Wr(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Jr(n){for(var t=n.source,e=n.target,r=Kr(t,e),i=[t];t!==r;)t=t.parent,i.push(t);for(var u=i.length;e!==r;)i.splice(u,0,e),e=e.parent;return i}function Gr(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Kr(n,t){if(n===t)return n;for(var e=Gr(n),r=Gr(t),i=e.pop(),u=r.pop(),o=null;i===u;)o=i,i=e.pop(),u=r.pop();return o}function Qr(n){n.fixed|=2}function ni(n){n.fixed&=-7}function ti(n){n.fixed|=4,n.px=n.x,n.py=n.y}function ei(n){n.fixed&=-5}function ri(n,t,e){var r=0,i=0;if(n.charge=0,!n.leaf)for(var u,o=n.nodes,a=o.length,l=-1;++l<a;)u=o[l],null!=u&&(ri(u,t,e),n.charge+=u.charge,r+=u.charge*u.cx,i+=u.charge*u.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var c=t*e[n.point.index];n.charge+=n.pointCharge=c,r+=c*n.point.x,i+=c*n.point.y}n.cx=r/n.charge,n.cy=i/n.charge}function ii(n,t){return ao.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=fi,n}function ui(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(i=n.children)&&(r=i.length))for(var r,i;--r>=0;)e.push(i[r])}function oi(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(u=n.children)&&(i=u.length))for(var i,u,o=-1;++o<i;)e.push(u[o]);for(;null!=(n=r.pop());)t(n)}function ai(n){return n.children}function li(n){return n.value}function ci(n,t){return t.value-n.value}function fi(n){return ao.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function si(n){return n.x}function hi(n){return n.y}function pi(n,t,e){n.y0=t,n.y=e}function gi(n){return ao.range(n.length)}function vi(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function di(n){for(var t,e=1,r=0,i=n[0][1],u=n.length;u>e;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function yi(n){return n.reduce(mi,0)}function mi(n,t){return n+t[1]}function Mi(n,t){return xi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function xi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function bi(n){return[ao.min(n),ao.max(n)]}function _i(n,t){return n.value-t.value}function wi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Si(n,t){n._pack_next=t,t._pack_prev=n}function ki(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Ni(n){function t(n){f=Math.min(n.x-n.r,f),s=Math.max(n.x+n.r,s),h=Math.min(n.y-n.r,h),p=Math.max(n.y+n.r,p)}if((e=n.children)&&(c=e.length)){var e,r,i,u,o,a,l,c,f=1/0,s=-(1/0),h=1/0,p=-(1/0);if(e.forEach(Ei),r=e[0],r.x=-r.r,r.y=0,t(r),c>1&&(i=e[1],i.x=i.r,i.y=0,t(i),c>2))for(u=e[2],zi(r,i,u),t(u),wi(r,u),r._pack_prev=u,wi(u,i),i=r._pack_next,o=3;c>o;o++){zi(r,i,u=e[o]);var g=0,v=1,d=1;for(a=i._pack_next;a!==i;a=a._pack_next,v++)if(ki(a,u)){g=1;break}if(1==g)for(l=r._pack_prev;l!==a._pack_prev&&!ki(l,u);l=l._pack_prev,d++);g?(d>v||v==d&&i.r<r.r?Si(r,i=a):Si(r=l,i),o--):(wi(r,u),i=u,t(u))}var y=(f+s)/2,m=(h+p)/2,M=0;for(o=0;c>o;o++)u=e[o],u.x-=y,u.y-=m,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Ai)}}function Ei(n){n._pack_next=n._pack_prev=n}function Ai(n){delete n._pack_next,delete n._pack_prev}function Ci(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,o=i.length;++u<o;)Ci(i[u],t,e,r)}function zi(n,t,e){var r=n.r+e.r,i=t.x-n.x,u=t.y-n.y;if(r&&(i||u)){var o=t.r+e.r,a=i*i+u*u;o*=o,r*=r;var l=.5+(r-o)/(2*a),c=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+l*i+c*u,e.y=n.y+l*u-c*i}else e.x=n.x+r,e.y=n.y}function Li(n,t){return n.parent==t.parent?1:2}function qi(n){var t=n.children;return t.length?t[0]:n.t}function Ti(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ri(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Di(n){for(var t,e=0,r=0,i=n.children,u=i.length;--u>=0;)t=i[u],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Pi(n,t,e){return n.a.parent===t.parent?n.a:e}function Ui(n){return 1+ao.max(n,function(n){return n.y})}function ji(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Fi(n){var t=n.children;return t&&t.length?Fi(t[0]):n}function Hi(n){var t,e=n.children;return e&&(t=e.length)?Hi(e[t-1]):n}function Oi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ii(n,t){var e=n.x+t[3],r=n.y+t[0],i=n.dx-t[1]-t[3],u=n.dy-t[0]-t[2];return 0>i&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Yi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Zi(n){return n.rangeExtent?n.rangeExtent():Yi(n.range())}function Vi(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Xi(n,t){var e,r=0,i=n.length-1,u=n[r],o=n[i];return u>o&&(e=r,r=i,i=e,e=u,u=o,o=e),n[r]=t.floor(u),n[i]=t.ceil(o),n}function $i(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:Sl}function Bi(n,t,e,r){var i=[],u=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)i.push(e(n[o-1],n[o])),u.push(r(t[o-1],t[o]));return function(t){var e=ao.bisect(n,t,1,a)-1;return u[e](i[e](t))}}function Wi(n,t,e,r){function i(){var i=Math.min(n.length,t.length)>2?Bi:Vi,l=r?Wr:Br;return o=i(n,t,l,e),a=i(t,n,l,Mr),u}function u(n){return o(n)}var o,a;return u.invert=function(n){return a(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return Qi(n,t)},u.tickFormat=function(t,e){return nu(n,t,e)},u.nice=function(t){return Gi(n,t),i()},u.copy=function(){return Wi(n,t,e,r)},i()}function Ji(n,t){return ao.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Gi(n,t){return Xi(n,$i(Ki(n,t)[2])),Xi(n,$i(Ki(n,t)[2])),n}function Ki(n,t){null==t&&(t=10);var e=Yi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function Qi(n,t){return ao.range.apply(ao,Ki(n,t))}function nu(n,t,e){var r=Ki(n,t);if(e){var i=ha.exec(e);if(i.shift(),"s"===i[8]){var u=ao.formatPrefix(Math.max(xo(r[0]),xo(r[1])));return i[7]||(i[7]="."+tu(u.scale(r[2]))),i[8]="f",e=ao.format(i.join("")),function(n){return e(u.scale(n))+u.symbol}}i[7]||(i[7]="."+eu(i[8],r)),e=i.join("")}else e=",."+tu(r[2])+"f";return ao.format(e)}function tu(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function eu(n,t){var e=tu(t[2]);return n in kl?Math.abs(e-tu(Math.max(xo(t[0]),xo(t[1]))))+ +("e"!==n):e-2*("%"===n)}function ru(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(i(t))}return o.invert=function(t){return u(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),o):t},o.nice=function(){var t=Xi(r.map(i),e?Math:El);return n.domain(t),r=t.map(u),o},o.ticks=function(){var n=Yi(r),o=[],a=n[0],l=n[1],c=Math.floor(i(a)),f=Math.ceil(i(l)),s=t%1?2:t;if(isFinite(f-c)){if(e){for(;f>c;c++)for(var h=1;s>h;h++)o.push(u(c)*h);o.push(u(c))}else for(o.push(u(c));c++<f;)for(var h=s-1;h>0;h--)o.push(u(c)*h);for(c=0;o[c]<a;c++);for(f=o.length;o[f-1]>l;f--);o=o.slice(c,f)}return o},o.tickFormat=function(n,e){if(!arguments.length)return Nl;arguments.length<2?e=Nl:"function"!=typeof e&&(e=ao.format(e));var r=Math.max(1,t*n/o.ticks().length);return function(n){var o=n/u(Math.round(i(n)));return t-.5>o*t&&(o*=t),r>=o?e(n):""}},o.copy=function(){return ru(n.copy(),t,e,r)},Ji(o,n)}function iu(n,t,e){function r(t){return n(i(t))}var i=uu(t),u=uu(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return Qi(e,n)},r.tickFormat=function(n,t){return nu(e,n,t)},r.nice=function(n){return r.domain(Gi(e,n))},r.exponent=function(o){return arguments.length?(i=uu(t=o),u=uu(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return iu(n.copy(),t,e)},Ji(r,n)}function uu(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function ou(n,t){function e(e){return u[((i.get(e)||("range"===t.t?i.set(e,n.push(e)):NaN))-1)%u.length]}function r(t,e){return ao.range(n.length).map(function(n){return t+e*n})}var i,u,o;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new c;for(var u,o=-1,a=r.length;++o<a;)i.has(u=r[o])||i.set(u,n.push(u));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(u=n,o=0,t={t:"range",a:arguments},e):u},e.rangePoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=(l+c)/2,0):(c-l)/(n.length-1+a);return u=r(l+f*a/2,f),o=0,t={t:"rangePoints",a:arguments},e},e.rangeRoundPoints=function(i,a){arguments.length<2&&(a=0);var l=i[0],c=i[1],f=n.length<2?(l=c=Math.round((l+c)/2),0):(c-l)/(n.length-1+a)|0;return u=r(l+Math.round(f*a/2+(c-l-(n.length-1+a)*f)/2),f),o=0,t={t:"rangeRoundPoints",a:arguments},e},e.rangeBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=(s-f)/(n.length-a+2*l);return u=r(f+h*l,h),c&&u.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(i,a,l){arguments.length<2&&(a=0),arguments.length<3&&(l=a);var c=i[1]<i[0],f=i[c-0],s=i[1-c],h=Math.floor((s-f)/(n.length-a+2*l));return u=r(f+Math.round((s-f-(n.length-a)*h)/2),h),c&&u.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Yi(t.a[0])},e.copy=function(){return ou(n,t)},e.domain(n)}function au(n,t){function u(){var e=0,r=t.length;for(a=[];++e<r;)a[e-1]=ao.quantile(n,e/r);return o}function o(n){return isNaN(n=+n)?void 0:t[ao.bisect(a,n)]}var a;return o.domain=function(t){return arguments.length?(n=t.map(r).filter(i).sort(e),u()):n},o.range=function(n){return arguments.length?(t=n,u()):t},o.quantiles=function(){return a},o.invertExtent=function(e){return e=t.indexOf(e),0>e?[NaN,NaN]:[e>0?a[e-1]:n[0],e<a.length?a[e]:n[n.length-1]]},o.copy=function(){return au(n,t)},u()}function lu(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(u*(t-n))))]}function i(){return u=e.length/(t-n),o=e.length-1,r}var u,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],i()):[n,t]},r.range=function(n){return arguments.length?(e=n,i()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?NaN:t/u+n,[t,t+1/u]},r.copy=function(){return lu(n,t,e)},i()}function cu(n,t){function e(e){return e>=e?t[ao.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return cu(n,t)},e}function fu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Qi(n,t)},t.tickFormat=function(t,e){return nu(n,t,e)},t.copy=function(){return fu(n)},t}function su(){return 0}function hu(n){return n.innerRadius}function pu(n){return n.outerRadius}function gu(n){return n.startAngle}function vu(n){return n.endAngle}function du(n){return n&&n.padAngle}function yu(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function mu(n,t,e,r,i){var u=n[0]-t[0],o=n[1]-t[1],a=(i?r:-r)/Math.sqrt(u*u+o*o),l=a*o,c=-a*u,f=n[0]+l,s=n[1]+c,h=t[0]+l,p=t[1]+c,g=(f+h)/2,v=(s+p)/2,d=h-f,y=p-s,m=d*d+y*y,M=e-r,x=f*p-h*s,b=(0>y?-1:1)*Math.sqrt(Math.max(0,M*M*m-x*x)),_=(x*y-d*b)/m,w=(-x*d-y*b)/m,S=(x*y+d*b)/m,k=(-x*d+y*b)/m,N=_-g,E=w-v,A=S-g,C=k-v;return N*N+E*E>A*A+C*C&&(_=S,w=k),[[_-l,w-c],[_*e/M,w*e/M]]}function Mu(n){function t(t){function o(){c.push("M",u(n(f),a))}for(var l,c=[],f=[],s=-1,h=t.length,p=En(e),g=En(r);++s<h;)i.call(this,l=t[s],s)?f.push([+p.call(this,l,s),+g.call(this,l,s)]):f.length&&(o(),f=[]);return f.length&&o(),c.length?c.join(""):null}var e=Ce,r=ze,i=zt,u=xu,o=u.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(i=n,t):i},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?u=n:(u=Tl.get(n)||xu).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function xu(n){return n.length>1?n.join("L"):n+"Z"}function bu(n){return n.join("L")+"Z"}function _u(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&i.push("H",r[0]),i.join("")}function wu(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("V",(r=n[t])[1],"H",r[0]);return i.join("")}function Su(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t<e;)i.push("H",(r=n[t])[0],"V",r[1]);return i.join("")}function ku(n,t){return n.length<4?xu(n):n[1]+Au(n.slice(1,-1),Cu(n,t))}function Nu(n,t){return n.length<3?bu(n):n[0]+Au((n.push(n[0]),n),Cu([n[n.length-2]].concat(n,[n[1]]),t))}function Eu(n,t){return n.length<3?xu(n):n[0]+Au(n,Cu(n,t))}function Au(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return xu(n);var e=n.length!=t.length,r="",i=n[0],u=n[1],o=t[0],a=o,l=1;if(e&&(r+="Q"+(u[0]-2*o[0]/3)+","+(u[1]-2*o[1]/3)+","+u[0]+","+u[1],i=n[1],l=2),t.length>1){a=t[1],u=n[l],l++,r+="C"+(i[0]+o[0])+","+(i[1]+o[1])+","+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1];for(var c=2;c<t.length;c++,l++)u=n[l],a=t[c],r+="S"+(u[0]-a[0])+","+(u[1]-a[1])+","+u[0]+","+u[1]}if(e){var f=n[l];r+="Q"+(u[0]+2*a[0]/3)+","+(u[1]+2*a[1]/3)+","+f[0]+","+f[1]}return r}function Cu(n,t){for(var e,r=[],i=(1-t)/2,u=n[0],o=n[1],a=1,l=n.length;++a<l;)e=u,u=o,o=n[a],r.push([i*(o[0]-e[0]),i*(o[1]-e[1])]);return r}function zu(n){if(n.length<3)return xu(n);var t=1,e=n.length,r=n[0],i=r[0],u=r[1],o=[i,i,i,(r=n[1])[0]],a=[u,u,u,r[1]],l=[i,",",u,"L",Ru(Pl,o),",",Ru(Pl,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),Du(l,o,a);return n.pop(),l.push("L",r),l.join("")}function Lu(n){if(n.length<4)return xu(n);for(var t,e=[],r=-1,i=n.length,u=[0],o=[0];++r<3;)t=n[r],u.push(t[0]),o.push(t[1]);for(e.push(Ru(Pl,u)+","+Ru(Pl,o)),--r;++r<i;)t=n[r],u.shift(),u.push(t[0]),o.shift(),o.push(t[1]),Du(e,u,o);return e.join("")}function qu(n){for(var t,e,r=-1,i=n.length,u=i+4,o=[],a=[];++r<4;)e=n[r%i],o.push(e[0]),a.push(e[1]);for(t=[Ru(Pl,o),",",Ru(Pl,a)],--r;++r<u;)e=n[r%i],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),Du(t,o,a);return t.join("")}function Tu(n,t){var e=n.length-1;if(e)for(var r,i,u=n[0][0],o=n[0][1],a=n[e][0]-u,l=n[e][1]-o,c=-1;++c<=e;)r=n[c],i=c/e,r[0]=t*r[0]+(1-t)*(u+i*a),r[1]=t*r[1]+(1-t)*(o+i*l);return zu(n)}function Ru(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function Du(n,t,e){n.push("C",Ru(Rl,t),",",Ru(Rl,e),",",Ru(Dl,t),",",Ru(Dl,e),",",Ru(Pl,t),",",Ru(Pl,e))}function Pu(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Uu(n){for(var t=0,e=n.length-1,r=[],i=n[0],u=n[1],o=r[0]=Pu(i,u);++t<e;)r[t]=(o+(o=Pu(i=u,u=n[t+1])))/2;return r[t]=o,r}function ju(n){for(var t,e,r,i,u=[],o=Uu(n),a=-1,l=n.length-1;++a<l;)t=Pu(n[a],n[a+1]),xo(t)<Uo?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,i=e*e+r*r,i>9&&(i=3*t/Math.sqrt(i),o[a]=i*e,o[a+1]=i*r));for(a=-1;++a<=l;)i=(n[Math.min(l,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),u.push([i||0,o[a]*i||0]);return u}function Fu(n){return n.length<3?xu(n):n[0]+Au(n,ju(n))}function Hu(n){for(var t,e,r,i=-1,u=n.length;++i<u;)t=n[i],e=t[0],r=t[1]-Io,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function Ou(n){function t(t){function l(){v.push("M",a(n(y),s),f,c(n(d.reverse()),s),"Z")}for(var h,p,g,v=[],d=[],y=[],m=-1,M=t.length,x=En(e),b=En(i),_=e===r?function(){
return p}:En(r),w=i===u?function(){return g}:En(u);++m<M;)o.call(this,h=t[m],m)?(d.push([p=+x.call(this,h,m),g=+b.call(this,h,m)]),y.push([+_.call(this,h,m),+w.call(this,h,m)])):d.length&&(l(),d=[],y=[]);return d.length&&l(),v.length?v.join(""):null}var e=Ce,r=Ce,i=0,u=ze,o=zt,a=xu,l=a.key,c=a,f="L",s=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(i=u=n,t):u},t.y0=function(n){return arguments.length?(i=n,t):i},t.y1=function(n){return arguments.length?(u=n,t):u},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(l="function"==typeof n?a=n:(a=Tl.get(n)||xu).key,c=a.reverse||a,f=a.closed?"M":"L",t):l},t.tension=function(n){return arguments.length?(s=n,t):s},t}function Iu(n){return n.radius}function Yu(n){return[n.x,n.y]}function Zu(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]-Io;return[e*Math.cos(r),e*Math.sin(r)]}}function Vu(){return 64}function Xu(){return"circle"}function $u(n){var t=Math.sqrt(n/Fo);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Bu(n){return function(){var t,e,r;(t=this[n])&&(r=t[e=t.active])&&(r.timer.c=null,r.timer.t=NaN,--t.count?delete t[e]:delete this[n],t.active+=.5,r.event&&r.event.interrupt.call(this,this.__data__,r.index))}}function Wu(n,t,e){return ko(n,Yl),n.namespace=t,n.id=e,n}function Ju(n,t,e,r){var i=n.id,u=n.namespace;return Y(n,"function"==typeof e?function(n,o,a){n[u][i].tween.set(t,r(e.call(n,n.__data__,o,a)))}:(e=r(e),function(n){n[u][i].tween.set(t,e)}))}function Gu(n){return null==n&&(n=""),function(){this.textContent=n}}function Ku(n){return null==n?"__transition__":"__transition_"+n+"__"}function Qu(n,t,e,r,i){function u(n){var t=v.delay;return f.t=t+l,n>=t?o(n-t):void(f.c=o)}function o(e){var i=g.active,u=g[i];u&&(u.timer.c=null,u.timer.t=NaN,--g.count,delete g[i],u.event&&u.event.interrupt.call(n,n.__data__,u.index));for(var o in g)if(r>+o){var c=g[o];c.timer.c=null,c.timer.t=NaN,--g.count,delete g[o]}f.c=a,qn(function(){return f.c&&a(e||1)&&(f.c=null,f.t=NaN),1},0,l),g.active=r,v.event&&v.event.start.call(n,n.__data__,t),p=[],v.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&p.push(r)}),h=v.ease,s=v.duration}function a(i){for(var u=i/s,o=h(u),a=p.length;a>0;)p[--a].call(n,o);return u>=1?(v.event&&v.event.end.call(n,n.__data__,t),--g.count?delete g[r]:delete n[e],1):void 0}var l,f,s,h,p,g=n[e]||(n[e]={active:0,count:0}),v=g[r];v||(l=i.time,f=qn(u,0,l),v=g[r]={tween:new c,time:l,timer:f,delay:i.delay,duration:i.duration,ease:i.ease,index:t},i=null,++g.count)}function no(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function to(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function eo(n){return n.toISOString()}function ro(n,t,e){function r(t){return n(t)}function i(n,e){var r=n[1]-n[0],i=r/e,u=ao.bisect(Kl,i);return u==Kl.length?[t.year,Ki(n.map(function(n){return n/31536e6}),e)[2]]:u?t[i/Kl[u-1]<Kl[u]/i?u-1:u]:[tc,Ki(n,e)[2]]}return r.invert=function(t){return io(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(io)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,io(+e+1),t).length}var u=r.domain(),o=Yi(u),a=null==n?i(o,10):"number"==typeof n&&i(o,n);return a&&(n=a[0],t=a[1]),r.domain(Xi(u,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Yi(r.domain()),u=null==n?i(e,10):"number"==typeof n?i(e,n):!n.range&&[{range:n},t];return u&&(n=u[0],t=u[1]),n.range(e[0],io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return ro(n.copy(),t,e)},Ji(r,n)}function io(n){return new Date(n)}function uo(n){return JSON.parse(n.responseText)}function oo(n){var t=fo.createRange();return t.selectNode(fo.body),t.createContextualFragment(n.responseText)}var ao={version:"3.5.17"},lo=[].slice,co=function(n){return lo.call(n)},fo=this.document;if(fo)try{co(fo.documentElement.childNodes)[0].nodeType}catch(so){co=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),fo)try{fo.createElement("DIV").style.setProperty("opacity",0,"")}catch(ho){var po=this.Element.prototype,go=po.setAttribute,vo=po.setAttributeNS,yo=this.CSSStyleDeclaration.prototype,mo=yo.setProperty;po.setAttribute=function(n,t){go.call(this,n,t+"")},po.setAttributeNS=function(n,t,e){vo.call(this,n,t,e+"")},yo.setProperty=function(n,t,e){mo.call(this,n,t+"",e)}}ao.ascending=e,ao.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:NaN},ao.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&e>r&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&e>r&&(e=r)}return e},ao.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i<u;)if(null!=(r=n[i])&&r>=r){e=r;break}for(;++i<u;)null!=(r=n[i])&&r>e&&(e=r)}else{for(;++i<u;)if(null!=(r=t.call(n,n[i],i))&&r>=r){e=r;break}for(;++i<u;)null!=(r=t.call(n,n[i],i))&&r>e&&(e=r)}return e},ao.extent=function(n,t){var e,r,i,u=-1,o=n.length;if(1===arguments.length){for(;++u<o;)if(null!=(r=n[u])&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=n[u])&&(e>r&&(e=r),r>i&&(i=r))}else{for(;++u<o;)if(null!=(r=t.call(n,n[u],u))&&r>=r){e=i=r;break}for(;++u<o;)null!=(r=t.call(n,n[u],u))&&(e>r&&(e=r),r>i&&(i=r))}return[e,i]},ao.sum=function(n,t){var e,r=0,u=n.length,o=-1;if(1===arguments.length)for(;++o<u;)i(e=+n[o])&&(r+=e);else for(;++o<u;)i(e=+t.call(n,n[o],o))&&(r+=e);return r},ao.mean=function(n,t){var e,u=0,o=n.length,a=-1,l=o;if(1===arguments.length)for(;++a<o;)i(e=r(n[a]))?u+=e:--l;else for(;++a<o;)i(e=r(t.call(n,n[a],a)))?u+=e:--l;return l?u/l:void 0},ao.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),i=+n[r-1],u=e-r;return u?i+u*(n[r]-i):i},ao.median=function(n,t){var u,o=[],a=n.length,l=-1;if(1===arguments.length)for(;++l<a;)i(u=r(n[l]))&&o.push(u);else for(;++l<a;)i(u=r(t.call(n,n[l],l)))&&o.push(u);return o.length?ao.quantile(o.sort(e),.5):void 0},ao.variance=function(n,t){var e,u,o=n.length,a=0,l=0,c=-1,f=0;if(1===arguments.length)for(;++c<o;)i(e=r(n[c]))&&(u=e-a,a+=u/++f,l+=u*(e-a));else for(;++c<o;)i(e=r(t.call(n,n[c],c)))&&(u=e-a,a+=u/++f,l+=u*(e-a));return f>1?l/(f-1):void 0},ao.deviation=function(){var n=ao.variance.apply(this,arguments);return n?Math.sqrt(n):n};var Mo=u(e);ao.bisectLeft=Mo.left,ao.bisect=ao.bisectRight=Mo.right,ao.bisector=function(n){return u(1===n.length?function(t,r){return e(n(t),r)}:n)},ao.shuffle=function(n,t,e){(u=arguments.length)<3&&(e=n.length,2>u&&(t=0));for(var r,i,u=e-t;u;)i=Math.random()*u--|0,r=n[u+t],n[u+t]=n[i+t],n[i+t]=r;return n},ao.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ao.pairs=function(n){for(var t,e=0,r=n.length-1,i=n[0],u=new Array(0>r?0:r);r>e;)u[e]=[t=i,i=n[++e]];return u},ao.transpose=function(n){if(!(i=n.length))return[];for(var t=-1,e=ao.min(n,o),r=new Array(e);++t<e;)for(var i,u=-1,a=r[t]=new Array(i);++u<i;)a[u]=n[u][t];return r},ao.zip=function(){return ao.transpose(arguments)},ao.keys=function(n){var t=[];for(var e in n)t.push(e);return t},ao.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},ao.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},ao.merge=function(n){for(var t,e,r,i=n.length,u=-1,o=0;++u<i;)o+=n[u].length;for(e=new Array(o);--i>=0;)for(r=n[i],t=r.length;--t>=0;)e[--o]=r[t];return e};var xo=Math.abs;ao.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,i=[],u=a(xo(e)),o=-1;if(n*=u,t*=u,e*=u,0>e)for(;(r=n+e*++o)>t;)i.push(r/u);else for(;(r=n+e*++o)<t;)i.push(r/u);return i},ao.map=function(n,t){var e=new c;if(n instanceof c)n.forEach(function(n,t){e.set(n,t)});else if(Array.isArray(n)){var r,i=-1,u=n.length;if(1===arguments.length)for(;++i<u;)e.set(i,n[i]);else for(;++i<u;)e.set(t.call(n,r=n[i],i),r)}else for(var o in n)e.set(o,n[o]);return e};var bo="__proto__",_o="\x00";l(c,{has:h,get:function(n){return this._[f(n)]},set:function(n,t){return this._[f(n)]=t},remove:p,keys:g,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:s(t),value:this._[t]});return n},size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t),this._[t])}}),ao.nest=function(){function n(t,o,a){if(a>=u.length)return r?r.call(i,o):e?o.sort(e):o;for(var l,f,s,h,p=-1,g=o.length,v=u[a++],d=new c;++p<g;)(h=d.get(l=v(f=o[p])))?h.push(f):d.set(l,[f]);return t?(f=t(),s=function(e,r){f.set(e,n(t,r,a))}):(f={},s=function(e,r){f[e]=n(t,r,a)}),d.forEach(s),f}function t(n,e){if(e>=u.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,i={},u=[],o=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(ao.map,e,0),0)},i.key=function(n){return u.push(n),i},i.sortKeys=function(n){return o[u.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},ao.set=function(n){var t=new y;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},l(y,{has:h,add:function(n){return this._[f(n+="")]=!0,n},remove:p,values:g,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,s(t))}}),ao.behavior={},ao.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r<i;)n[e=arguments[r]]=M(n,t,t[e]);return n};var wo=["webkit","ms","moz","Moz","o","O"];ao.dispatch=function(){for(var n=new _,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=w(n);return n},_.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ao.event=null,ao.requote=function(n){return n.replace(So,"\\$&")};var So=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ko={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},No=function(n,t){return t.querySelector(n)},Eo=function(n,t){return t.querySelectorAll(n)},Ao=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(Ao=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(No=function(n,t){return Sizzle(n,t)[0]||null},Eo=Sizzle,Ao=Sizzle.matchesSelector),ao.selection=function(){return ao.select(fo.documentElement)};var Co=ao.selection.prototype=[];Co.select=function(n){var t,e,r,i,u=[];n=A(n);for(var o=-1,a=this.length;++o<a;){u.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var l=-1,c=r.length;++l<c;)(i=r[l])?(t.push(e=n.call(i,i.__data__,l,o)),e&&"__data__"in i&&(e.__data__=i.__data__)):t.push(null)}return E(u)},Co.selectAll=function(n){var t,e,r=[];n=C(n);for(var i=-1,u=this.length;++i<u;)for(var o=this[i],a=-1,l=o.length;++a<l;)(e=o[a])&&(r.push(t=co(n.call(e,e.__data__,a,i))),t.parentNode=e);return E(r)};var zo="http://www.w3.org/1999/xhtml",Lo={svg:"http://www.w3.org/2000/svg",xhtml:zo,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};ao.ns={prefix:Lo,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&"xmlns"!==(e=n.slice(0,t))&&(n=n.slice(t+1)),Lo.hasOwnProperty(e)?{space:Lo[e],local:n}:n}},Co.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ao.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},Co.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,i=-1;if(t=e.classList){for(;++i<r;)if(!t.contains(n[i]))return!1}else for(t=e.getAttribute("class");++i<r;)if(!q(n[i]).test(t))return!1;return!0}for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},Co.style=function(n,e,r){var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>i){var u=this.node();return t(u).getComputedStyle(u,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},Co.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},Co.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Co.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Co.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Co.insert=function(n,t){return n=j(n),t=A(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},Co.remove=function(){return this.each(F)},Co.data=function(n,t){function e(n,e){var r,i,u,o=n.length,s=e.length,h=Math.min(o,s),p=new Array(s),g=new Array(s),v=new Array(o);if(t){var d,y=new c,m=new Array(o);for(r=-1;++r<o;)(i=n[r])&&(y.has(d=t.call(i,i.__data__,r))?v[r]=i:y.set(d,i),m[r]=d);for(r=-1;++r<s;)(i=y.get(d=t.call(e,u=e[r],r)))?i!==!0&&(p[r]=i,i.__data__=u):g[r]=H(u),y.set(d,!0);for(r=-1;++r<o;)r in m&&y.get(m[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)i=n[r],u=e[r],i?(i.__data__=u,p[r]=i):g[r]=H(u);for(;s>r;++r)g[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}g.update=p,g.parentNode=p.parentNode=v.parentNode=n.parentNode,a.push(g),l.push(p),f.push(v)}var r,i,u=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++u<o;)(i=r[u])&&(n[u]=i.__data__);return n}var a=Z([]),l=E([]),f=E([]);if("function"==typeof n)for(;++u<o;)e(r=this[u],n.call(r,r.parentNode.__data__,u));else for(;++u<o;)e(r=this[u],n);return l.enter=function(){return a},l.exit=function(){return f},l},Co.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},Co.filter=function(n){var t,e,r,i=[];"function"!=typeof n&&(n=O(n));for(var u=0,o=this.length;o>u;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var a=0,l=e.length;l>a;a++)(r=e[a])&&n.call(r,r.__data__,a,u)&&t.push(r)}return E(i)},Co.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],i=r.length-1,u=r[i];--i>=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Co.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},Co.each=function(n){return Y(this,function(t,e,r){n.call(t,t.__data__,e,r)})},Co.call=function(n){var t=co(arguments);return n.apply(t[0]=this,t),this},Co.empty=function(){return!this.node()},Co.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Co.size=function(){var n=0;return Y(this,function(){++n}),n};var qo=[];ao.selection.enter=Z,ao.selection.enter.prototype=qo,qo.append=Co.append,qo.empty=Co.empty,qo.node=Co.node,qo.call=Co.call,qo.size=Co.size,qo.select=function(n){for(var t,e,r,i,u,o=[],a=-1,l=this.length;++a<l;){r=(i=this[a]).update,o.push(t=[]),t.parentNode=i.parentNode;for(var c=-1,f=i.length;++c<f;)(u=i[c])?(t.push(r[c]=e=n.call(i.parentNode,u.__data__,c,a)),e.__data__=u.__data__):t.push(null)}return E(o)},qo.insert=function(n,t){return arguments.length<2&&(t=V(this)),Co.insert.call(this,n,t)},ao.select=function(t){var e;return"string"==typeof t?(e=[No(t,fo)],e.parentNode=fo.documentElement):(e=[t],e.parentNode=n(t)),E([e])},ao.selectAll=function(n){var t;return"string"==typeof n?(t=co(Eo(n,fo)),t.parentNode=fo.documentElement):(t=co(n),t.parentNode=null),E([t])},Co.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var To=ao.map({mouseenter:"mouseover",mouseleave:"mouseout"});fo&&To.forEach(function(n){"on"+n in fo&&To.remove(n)});var Ro,Do=0;ao.mouse=function(n){return J(n,k())};var Po=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ao.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,i=0,u=t.length;u>i;++i)if((r=t[i]).identifier===e)return J(n,r)},ao.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",o)}function e(n,t,e,u,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],g|=n|e,M=r,p({type:"drag",x:r[0]+c[0],y:r[1]+c[1],dx:n,dy:e}))}function l(){t(h,v)&&(y.on(u+d,null).on(o+d,null),m(g),p({type:"dragend"}))}var c,f=this,s=ao.event.target.correspondingElement||ao.event.target,h=f.parentNode,p=r.of(f,arguments),g=0,v=n(),d=".drag"+(null==v?"":"-"+v),y=ao.select(e(s)).on(u+d,a).on(o+d,l),m=W(s),M=t(h,v);i?(c=i.apply(f,arguments),c=[c.x-M[0],c.y-M[1]]):c=[0,0],p({type:"dragstart"})}}var r=N(n,"drag","dragstart","dragend"),i=null,u=e(b,ao.mouse,t,"mousemove","mouseup"),o=e(G,ao.touch,m,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},ao.rebind(n,r,"on")},ao.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?co(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Uo=1e-6,jo=Uo*Uo,Fo=Math.PI,Ho=2*Fo,Oo=Ho-Uo,Io=Fo/2,Yo=Fo/180,Zo=180/Fo,Vo=Math.SQRT2,Xo=2,$o=4;ao.interpolateZoom=function(n,t){var e,r,i=n[0],u=n[1],o=n[2],a=t[0],l=t[1],c=t[2],f=a-i,s=l-u,h=f*f+s*s;if(jo>h)r=Math.log(c/o)/Vo,e=function(n){return[i+n*f,u+n*s,o*Math.exp(Vo*n*r)]};else{var p=Math.sqrt(h),g=(c*c-o*o+$o*h)/(2*o*Xo*p),v=(c*c-o*o-$o*h)/(2*c*Xo*p),d=Math.log(Math.sqrt(g*g+1)-g),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-d)/Vo,e=function(n){var t=n*r,e=rn(d),a=o/(Xo*p)*(e*un(Vo*t+d)-en(d));return[i+a*f,u+a*s,o*e/rn(Vo*t+d)]}}return e.duration=1e3*r,e},ao.behavior.zoom=function(){function n(n){n.on(L,s).on(Wo+".zoom",p).on("dblclick.zoom",g).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function i(n){k.k=Math.max(A[0],Math.min(A[1],n))}function u(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},i(Math.pow(2,o)),u(d=e,r),t=ao.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function l(n){z++||n({type:"zoomstart"})}function c(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function f(n){--z||(n({type:"zoomend"}),d=null)}function s(){function n(){a=1,u(ao.mouse(i),h),c(o)}function r(){s.on(q,null).on(T,null),p(a),f(o)}var i=this,o=D.of(i,arguments),a=0,s=ao.select(t(i)).on(q,n).on(T,r),h=e(ao.mouse(i)),p=W(i);Il.call(i),l(o)}function h(){function n(){var n=ao.touches(g);return p=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ao.event.target;ao.select(t).on(x,r).on(b,a),_.push(t);for(var e=ao.event.changedTouches,i=0,u=e.length;u>i;++i)d[e[i].identifier]=null;var l=n(),c=Date.now();if(1===l.length){if(500>c-M){var f=l[0];o(g,f,d[f.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=c}else if(l.length>1){var f=l[0],s=l[1],h=f[0]-s[0],p=f[1]-s[1];y=h*h+p*p}}function r(){var n,t,e,r,o=ao.touches(g);Il.call(g);for(var a=0,l=o.length;l>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var f=(f=e[0]-n[0])*f+(f=e[1]-n[1])*f,s=y&&Math.sqrt(f/y);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],i(s*p)}M=null,u(n,t),c(v)}function a(){if(ao.event.touches.length){for(var t=ao.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var i in d)return void n()}ao.selectAll(_).on(m,null),w.on(L,s).on(R,h),N(),f(v)}var p,g=this,v=D.of(g,arguments),d={},y=0,m=".zoom-"+ao.event.changedTouches[0].identifier,x="touchmove"+m,b="touchend"+m,_=[],w=ao.select(g),N=W(g);t(),l(v),w.on(L,null).on(R,t)}function p(){var n=D.of(this,arguments);m?clearTimeout(m):(Il.call(this),v=e(d=y||ao.mouse(this)),l(n)),m=setTimeout(function(){m=null,f(n)},50),S(),i(Math.pow(2,.002*Bo())*k.k),u(d,v),c(n)}function g(){var n=ao.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ao.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,y,m,M,x,b,_,w,k={x:0,y:0,k:1},E=[960,500],A=Jo,C=250,z=0,L="mousedown.zoom",q="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=N(n,"zoomstart","zoom","zoomend");return Wo||(Wo="onwheel"in fo?(Bo=function(){return-ao.event.deltaY*(ao.event.deltaMode?120:1)},"wheel"):"onmousewheel"in fo?(Bo=function(){return ao.event.wheelDelta},"mousewheel"):(Bo=function(){return-ao.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Hl?ao.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},l(n)}).tween("zoom:zoom",function(){var e=E[0],r=E[1],i=d?d[0]:e/2,u=d?d[1]:r/2,o=ao.interpolateZoom([(i-k.x)/k.k,(u-k.y)/k.k,e/k.k],[(i-t.x)/t.k,(u-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:i-r[0]*a,y:u-r[1]*a,k:a},c(n)}}).each("interrupt.zoom",function(){f(n)}).each("end.zoom",function(){f(n)}):(this.__chart__=k,l(n),c(n),f(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:null},i(+t),a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(A=null==t?Jo:[+t[0],+t[1]],n):A},n.center=function(t){return arguments.length?(y=t&&[+t[0],+t[1]],n):y},n.size=function(t){return arguments.length?(E=t&&[+t[0],+t[1]],n):E},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ao.rebind(n,D,"on")};var Bo,Wo,Jo=[0,1/0];ao.color=an,an.prototype.toString=function(){return this.rgb()+""},ao.hsl=ln;var Go=ln.prototype=new an;Go.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,this.l/n)},Go.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ln(this.h,this.s,n*this.l)},Go.rgb=function(){return cn(this.h,this.s,this.l)},ao.hcl=fn;var Ko=fn.prototype=new an;Ko.brighter=function(n){return new fn(this.h,this.c,Math.min(100,this.l+Qo*(arguments.length?n:1)))},Ko.darker=function(n){return new fn(this.h,this.c,Math.max(0,this.l-Qo*(arguments.length?n:1)))},Ko.rgb=function(){return sn(this.h,this.c,this.l).rgb()},ao.lab=hn;var Qo=18,na=.95047,ta=1,ea=1.08883,ra=hn.prototype=new an;ra.brighter=function(n){return new hn(Math.min(100,this.l+Qo*(arguments.length?n:1)),this.a,this.b)},ra.darker=function(n){return new hn(Math.max(0,this.l-Qo*(arguments.length?n:1)),this.a,this.b)},ra.rgb=function(){return pn(this.l,this.a,this.b)},ao.rgb=mn;var ia=mn.prototype=new an;ia.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),new mn(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mn(i,i,i)},ia.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mn(n*this.r,n*this.g,n*this.b)},ia.hsl=function(){return wn(this.r,this.g,this.b)},ia.toString=function(){return"#"+bn(this.r)+bn(this.g)+bn(this.b)};var ua=ao.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});ua.forEach(function(n,t){ua.set(n,Mn(t))}),ao.functor=En,ao.xhr=An(m),ao.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var o=Cn(n,t,null==e?r:i(e),u);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:i(n)):e},o}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function u(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(f>=c)return o;if(i)return i=!1,u;var t=f;if(34===n.charCodeAt(t)){for(var e=t;e++<c;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}f=e+2;var r=n.charCodeAt(e+1);return 13===r?(i=!0,10===n.charCodeAt(e+2)&&++f):10===r&&(i=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;c>f;){var r=n.charCodeAt(f++),a=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(f)&&(++f,++a);else if(r!==l)continue;return n.slice(t,f-a)}return n.slice(t)}for(var r,i,u={},o={},a=[],c=n.length,f=0,s=0;(r=e())!==o;){for(var h=[];r!==u&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,s++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new y,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(u).join("\n")},e},ao.csv=ao.dsv(",","text/csv"),ao.tsv=ao.dsv(" ","text/tab-separated-values");var oa,aa,la,ca,fa=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ao.timer=function(){qn.apply(this,arguments)},ao.timer.flush=function(){Rn(),Dn()},ao.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var sa=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Un);ao.formatPrefix=function(n,t){var e=0;return(n=+n)&&(0>n&&(n*=-1),t&&(n=ao.round(n,Pn(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),sa[8+e/3]};var ha=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,pa=ao.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ao.round(n,Pn(n,t))).toFixed(Math.max(0,Math.min(20,Pn(n*(1+1e-15),t))))}}),ga=ao.time={},va=Date;Hn.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){da.setUTCDate.apply(this._,arguments)},setDay:function(){da.setUTCDay.apply(this._,arguments)},setFullYear:function(){da.setUTCFullYear.apply(this._,arguments)},setHours:function(){da.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){da.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){da.setUTCMinutes.apply(this._,arguments)},setMonth:function(){da.setUTCMonth.apply(this._,arguments)},setSeconds:function(){da.setUTCSeconds.apply(this._,arguments)},setTime:function(){da.setTime.apply(this._,arguments)}};var da=Date.prototype;ga.year=On(function(n){return n=ga.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ga.years=ga.year.range,ga.years.utc=ga.year.utc.range,ga.day=On(function(n){var t=new va(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ga.days=ga.day.range,ga.days.utc=ga.day.utc.range,ga.dayOfYear=function(n){var t=ga.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ga[n]=On(function(n){return(n=ga.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ga[n+"s"]=e.range,ga[n+"s"].utc=e.utc.range,ga[n+"OfYear"]=function(n){var e=ga.year(n).getDay();return Math.floor((ga.dayOfYear(n)+(e+t)%7)/7)}}),ga.week=ga.sunday,ga.weeks=ga.sunday.range,ga.weeks.utc=ga.sunday.utc.range,ga.weekOfYear=ga.sundayOfYear;var ya={"-":"",_:" ",0:"0"},ma=/^\s*\d+/,Ma=/^%/;ao.locale=function(n){return{numberFormat:jn(n),timeFormat:Yn(n)}};var xa=ao.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
diff --git a/assets/sass/_base.sass b/assets/sass/_base.sass
index 064f5149..566e8a94 100644
--- a/assets/sass/_base.sass
+++ b/assets/sass/_base.sass
@@ -1,3 +1,9 @@
+.margin-top
+ margin-top: 20px
+
+.margin-bottom
+ margin-bottom: 20px
+
.pull-right
text-align: right
@@ -5,9 +11,6 @@ ul.no-bullet li
list-style-type: none
margin-left: 0
-.chosen-select
- min-height: 27px
-
#app-loading-icon
position: fixed
right: 3px
diff --git a/assets/sass/_board.sass b/assets/sass/_board.sass
index c94879bc..d7d10d2e 100644
--- a/assets/sass/_board.sass
+++ b/assets/sass/_board.sass
@@ -65,11 +65,10 @@ td.board-column-task-collapsed
.board-add-icon
float: left
padding: 0 5px
- a
+ i
text-decoration: none
color: link-color('primary')
- font-size: size('xlarge')
- line-height: 70%
+ font-size: size('large')
&:focus, &:hover
text-decoration: none
color: red
diff --git a/assets/sass/_dialog_box.sass b/assets/sass/_dialog_box.sass
deleted file mode 100644
index 38364230..00000000
--- a/assets/sass/_dialog_box.sass
+++ /dev/null
@@ -1,4 +0,0 @@
-@import variables
-
-#main .confirm
- max-width: 700px
diff --git a/assets/sass/_file_upload.sass b/assets/sass/_file_upload.sass
index b258620e..bdd31a62 100644
--- a/assets/sass/_file_upload.sass
+++ b/assets/sass/_file_upload.sass
@@ -26,6 +26,6 @@
padding-bottom: 8px
border-bottom: 1px dotted #ddd
width: 95%
- &.file-error
+ .file-error
font-weight: bold
color: color('error')
diff --git a/assets/sass/_form.sass b/assets/sass/_form.sass
index ace988f5..00cea65a 100644
--- a/assets/sass/_form.sass
+++ b/assets/sass/_form.sass
@@ -1,13 +1,19 @@
@import variables
@import mixins
-form
- margin-bottom: 20px
+fieldset
+ border: 1px solid #ccc
+ margin-top: 20px
+
+legend
+ font-weight: 500
+ font-size: size('medium')
label
cursor: pointer
display: block
margin-top: 10px
+ font-weight: 400
input
&[type="number"], &[type="date"], &[type="email"], &[type="password"], &[type="text"]:not(.input-addon-field)
@@ -19,7 +25,6 @@ input
height: 25px
padding-bottom: 0
font-family: sans-serif
- margin-top: 10px
+appearance
@include placeholder
color: color('lighter')
@@ -111,10 +116,15 @@ ul.form-errors li
border: none
label
display: inline
+ padding-right: 3px
input, select
margin: 0 15px 0 0
.form-required
display: none
+ .form-actions
+ display: inline-block
+ .js-submit-buttons-rendered
+ display: inline-block
.form-inline-group
display: inline
@@ -129,9 +139,12 @@ ul.form-errors li
margin-right: 25px
flex-grow: 1
+ fieldset
+ margin-top: 0
+
.form-login
max-width: 350px
- margin: 8% auto 0
+ margin: 5% auto 0
li
margin-left: 25px
line-height: 25px
@@ -141,5 +154,6 @@ ul.form-errors li
.reset-password
margin-top: 20px
+ margin-bottom: 20px
a
color: color('light')
diff --git a/assets/sass/_links.sass b/assets/sass/_links.sass
index d4544391..e5aa5f31 100644
--- a/assets/sass/_links.sass
+++ b/assets/sass/_links.sass
@@ -10,3 +10,7 @@ a
&:hover
color: link-color('hover')
text-decoration: none
+ .fa
+ padding-right: 3px
+ text-decoration: none
+ color: color('primary') \ No newline at end of file
diff --git a/assets/sass/_markdown_editor.sass b/assets/sass/_markdown_editor.sass
index b9279be9..ac25101e 100644
--- a/assets/sass/_markdown_editor.sass
+++ b/assets/sass/_markdown_editor.sass
@@ -1,6 +1,7 @@
@import variables
.text-editor
+ margin-top: 10px
a
font-size: size('normal')
color: color('light')
@@ -10,7 +11,12 @@
color: link-color('primary')
.text-editor-preview-area
border: 1px solid color('lighter')
- width: 400px
- height: 200px
+ width: 700px
+ max-width: 99%
+ height: 250px
overflow: auto
padding: 2px
+ textarea
+ width: 700px
+ max-width: 98%
+ height: 250px \ No newline at end of file
diff --git a/assets/sass/_popover.sass b/assets/sass/_modal.sass
index b45f8401..68b0329b 100644
--- a/assets/sass/_popover.sass
+++ b/assets/sass/_modal.sass
@@ -1,7 +1,7 @@
@import variables
@import mixins
-#popover-container
+#modal-overlay
position: fixed
top: 0
left: 0
@@ -11,25 +11,24 @@
overflow: auto
z-index: 100
-#popover-content
+#modal-box
position: fixed
- width: 950px
- max-width: 95%
- max-height: calc(100% - 50px)
- top: 5%
+ max-height: calc(100% - 30px)
+ top: 2%
left: 50%
transform: translateX(-50%)
- padding: 0 15px 15px
background: #fff
overflow: auto
+ border-radius: 5px
-#popover-content-header
+#modal-content
+ padding: 0 5px 5px
+
+#modal-header
text-align: right
+ padding-right: 5px
-#popover-close-button
+#modal-close-button
color: color('primary')
&:hover
color: color('error')
-
-.popover-form
- margin-bottom: 0
diff --git a/assets/sass/_pagination.sass b/assets/sass/_pagination.sass
index 792fb945..c4944d06 100644
--- a/assets/sass/_pagination.sass
+++ b/assets/sass/_pagination.sass
@@ -3,6 +3,11 @@
.pagination
text-align: center
+.pagination-showing
+ margin-right: 5px
+ padding-right: 5px
+ border-right: 1px solid #999
+
.pagination-next
margin-left: 5px
diff --git a/assets/sass/_listing.sass b/assets/sass/_panel.sass
index 64ff4adc..74552292 100644
--- a/assets/sass/_listing.sass
+++ b/assets/sass/_panel.sass
@@ -1,9 +1,10 @@
@import variables
-.listing
+.panel
border-radius: 4px
- padding: 8px 35px 8px 14px
- margin-bottom: 20px
+ padding: 8px 35px 8px 10px
+ margin-top: 10px
+ margin-bottom: 15px
border: 1px solid #ddd
color: color('primary')
background-color: bg-color('light')
@@ -11,7 +12,4 @@
li
list-style-type: square
margin-left: 20px
- margin-bottom: 3px
- ul
- margin-top: 15px
- margin-bottom: 15px
+ line-height: 1.35em
diff --git a/assets/sass/_select_dropdown.sass b/assets/sass/_select_dropdown.sass
index cdd15c64..f0cef59c 100644
--- a/assets/sass/_select_dropdown.sass
+++ b/assets/sass/_select_dropdown.sass
@@ -35,6 +35,7 @@
input.select-dropdown-input
margin: 0 0 0 5px
border: none
+ height: 23px
&:focus
border: none
box-shadow: none
@@ -44,3 +45,8 @@
top: 4px
right: 5px
cursor: pointer
+ .select-loading-icon
+ color: color('medium')
+ position: absolute
+ top: 4px
+ right: 5px \ No newline at end of file
diff --git a/assets/sass/_task_form.sass b/assets/sass/_task_form.sass
new file mode 100644
index 00000000..b7583981
--- /dev/null
+++ b/assets/sass/_task_form.sass
@@ -0,0 +1,32 @@
+@import variables
+
+.task-form-container
+ @include grid(100)
+
+.task-form-main-column
+ @include grid_width(60/100)
+ @include custom-device(1000px)
+ @include grid_width(1)
+
+ input[type="text"]
+ width: 700px
+ max-width: 99%
+
+.task-form-secondary-column
+ max-width: 250px
+ min-width: 200px
+ max-height: 600px
+ padding-left: 10px
+ overflow: auto
+ @include grid_width(20/100)
+ @include custom-device(1000px)
+ @include grid_width(1)
+ max-width: 99%
+ max-height: none
+ label:first-child
+ margin-top: 0
+ @include custom-device(1000px)
+ margin-top: 10px
+
+.task-form-bottom
+ @include grid_width(1)
diff --git a/assets/sass/_thumbnails.sass b/assets/sass/_thumbnails.sass
index f4f0c12b..b860a607 100644
--- a/assets/sass/_thumbnails.sass
+++ b/assets/sass/_thumbnails.sass
@@ -29,6 +29,8 @@
font-weight: 700
font-size: size('compact')
color: color('medium')
+ overflow: hidden
+ text-overflow: ellipsis
.file-thumbnail-description
font-size: size('small')
diff --git a/assets/sass/app.sass b/assets/sass/app.sass
index 378b3ea3..475d1536 100644
--- a/assets/sass/app.sass
+++ b/assets/sass/app.sass
@@ -14,8 +14,7 @@
@import accordion
@import select_dropdown
@import suggest_menu
-@import dialog_box
-@import popover
+@import modal
@import pagination
@import header
@import logo
@@ -41,6 +40,7 @@
@import task_board_date
@import task_tags
@import task_summary
+@import task_form
@import task_listing
@import comment
@import subtasks
@@ -48,7 +48,7 @@
@import markdown_editor
@import markdown_rendering
@import documentation
-@import listing
+@import panel
@import activity_stream
@import gantt_chart
@import user_mentions
diff --git a/bower.json b/bower.json
index 938b89e4..a34083b7 100644
--- a/bower.json
+++ b/bower.json
@@ -14,7 +14,6 @@
"jquery-ui": "^1.11.4",
"jqueryui-touch-punch": "*",
"jqueryui-timepicker-addon": "^1.6.3",
- "mousetrap": "^1.5.3",
"font-awesome": "fontawesome#^4.7.0",
"d3": "~3.5.0",
"isMobile": "0.4.0",
diff --git a/composer.json b/composer.json
index a49f263b..ca25d3a2 100644
--- a/composer.json
+++ b/composer.json
@@ -35,7 +35,7 @@
"paragonie/random_compat": "2.0.2",
"pimple/pimple" : "3.0.2",
"ramsey/array_column": "1.1.3",
- "swiftmailer/swiftmailer" : "5.4.2",
+ "swiftmailer/swiftmailer" : "5.4.5",
"symfony/console" : "2.8.7",
"symfony/event-dispatcher" : "2.7.14",
"gregwar/captcha": "1.1.1"
diff --git a/composer.lock b/composer.lock
index 64feaa9c..a327c2aa 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "5111a8477b4462a68a9a93af931fbfeb",
- "content-hash": "8609029c4ce32c3b3aec0778320a729a",
+ "hash": "3d24ad1182c0460eda5791bd7fc68984",
+ "content-hash": "67d44f262438806c115a362c9912b669",
"packages": [
{
"name": "christian-riesen/base32",
@@ -597,22 +597,30 @@
},
{
"name": "psr/log",
- "version": "1.0.0",
+ "version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
- "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
"shasum": ""
},
+ "require": {
+ "php": ">=5.3.0"
+ },
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
"autoload": {
- "psr-0": {
- "Psr\\Log\\": ""
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -626,12 +634,13 @@
}
],
"description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
- "time": "2012-12-21 11:40:51"
+ "time": "2016-10-10 12:19:37"
},
{
"name": "ramsey/array_column",
@@ -680,23 +689,24 @@
},
{
"name": "swiftmailer/swiftmailer",
- "version": "v5.4.2",
+ "version": "v5.4.5",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
- "reference": "d8db871a54619458a805229a057ea2af33c753e8"
+ "reference": "cd142238a339459b10da3d8234220963f392540c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d8db871a54619458a805229a057ea2af33c753e8",
- "reference": "d8db871a54619458a805229a057ea2af33c753e8",
+ "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/cd142238a339459b10da3d8234220963f392540c",
+ "reference": "cd142238a339459b10da3d8234220963f392540c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
- "mockery/mockery": "~0.9.1,<0.9.4"
+ "mockery/mockery": "~0.9.1",
+ "symfony/phpunit-bridge": "~3.2"
},
"type": "library",
"extra": {
@@ -729,7 +739,7 @@
"mail",
"mailer"
],
- "time": "2016-05-01 08:45:47"
+ "time": "2016-12-29 10:02:40"
},
{
"name": "symfony/console",
@@ -853,16 +863,16 @@
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.2.0",
+ "version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "dff51f72b0706335131b00a7f49606168c582594"
+ "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
- "reference": "dff51f72b0706335131b00a7f49606168c582594",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
+ "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
"shasum": ""
},
"require": {
@@ -874,7 +884,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2-dev"
+ "dev-master": "1.3-dev"
}
},
"autoload": {
@@ -908,7 +918,7 @@
"portable",
"shim"
],
- "time": "2016-05-18 14:26:46"
+ "time": "2016-11-14 01:06:16"
},
{
"name": "zendframework/zendxml",
@@ -1062,16 +1072,16 @@
},
{
"name": "phpspec/prophecy",
- "version": "v1.6.1",
+ "version": "v1.6.2",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
+ "reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
- "reference": "58a8137754bc24b25740d4281399a4a3596058e0",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
+ "reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
"shasum": ""
},
"require": {
@@ -1079,10 +1089,11 @@
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
- "sebastian/recursion-context": "^1.0"
+ "sebastian/recursion-context": "^1.0|^2.0"
},
"require-dev": {
- "phpspec/phpspec": "^2.0"
+ "phpspec/phpspec": "^2.0",
+ "phpunit/phpunit": "^4.8 || ^5.6.5"
},
"type": "library",
"extra": {
@@ -1120,7 +1131,7 @@
"spy",
"stub"
],
- "time": "2016-06-07 08:13:47"
+ "time": "2016-11-21 14:58:47"
},
{
"name": "phpunit/php-code-coverage",
@@ -1186,16 +1197,16 @@
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.4.1",
+ "version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
- "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+ "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"shasum": ""
},
"require": {
@@ -1229,7 +1240,7 @@
"filesystem",
"iterator"
],
- "time": "2015-06-21 13:08:43"
+ "time": "2016-10-03 07:40:28"
},
{
"name": "phpunit/php-text-template",
@@ -1318,16 +1329,16 @@
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.8",
+ "version": "1.4.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
+ "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
- "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
+ "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
"shasum": ""
},
"require": {
@@ -1363,7 +1374,7 @@
"keywords": [
"tokenizer"
],
- "time": "2015-09-15 10:49:45"
+ "time": "2016-11-15 14:06:22"
},
{
"name": "phpunit/phpunit",
@@ -1559,22 +1570,22 @@
},
{
"name": "sebastian/comparator",
- "version": "1.2.0",
+ "version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
+ "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
- "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
+ "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
- "sebastian/exporter": "~1.2"
+ "sebastian/exporter": "~1.2 || ~2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
@@ -1619,7 +1630,7 @@
"compare",
"equality"
],
- "time": "2015-07-26 15:48:44"
+ "time": "2016-11-19 09:18:40"
},
{
"name": "sebastian/diff",
@@ -1675,23 +1686,23 @@
},
{
"name": "sebastian/environment",
- "version": "1.3.7",
+ "version": "1.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
- "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+ "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.4"
+ "phpunit/phpunit": "^4.8 || ^5.0"
},
"type": "library",
"extra": {
@@ -1721,7 +1732,7 @@
"environment",
"hhvm"
],
- "time": "2016-05-17 03:18:57"
+ "time": "2016-08-18 05:49:44"
},
{
"name": "sebastian/exporter",
diff --git a/config.default.php b/config.default.php
index 09774689..9b55295f 100644
--- a/config.default.php
+++ b/config.default.php
@@ -4,8 +4,8 @@
/* Rename this file to config.php if you want to change the values */
/*******************************************************************/
-// Data folder (must be writeable by the web server user)
-define('DATA_DIR', 'data');
+// Data folder (must be writeable by the web server user and absolute)
+define('DATA_DIR', __DIR__.DIRECTORY_SEPARATOR.'data');
// Enable/Disable debug
define('DEBUG', false);
diff --git a/doc/api-json-rpc.markdown b/doc/api-json-rpc.markdown
index fc612682..fad19466 100644
--- a/doc/api-json-rpc.markdown
+++ b/doc/api-json-rpc.markdown
@@ -63,6 +63,7 @@ Usage
- [Task Files](api-task-file-procedures.markdown)
- [Project Files](api-project-file-procedures.markdown)
- [Links](api-link-procedures.markdown)
+- [Tags](api-tags-procedures.markdown)
- [Internal Task Links](api-internal-task-link-procedures.markdown)
- [External Task Links](api-external-task-link-procedures.markdown)
- [Comments](api-comment-procedures.markdown)
diff --git a/doc/api-tags-procedures.markdown b/doc/api-tags-procedures.markdown
new file mode 100644
index 00000000..8d69430c
--- /dev/null
+++ b/doc/api-tags-procedures.markdown
@@ -0,0 +1,195 @@
+API Tags Procedures
+===================
+
+getAllTags
+----------
+
+- Purpose: **Get all tags**
+- Parameters: none
+- Result on success: **List of tags**
+- Result on failure: **false|null**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"getAllTags","id":45253426}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "id": "1",
+ "name": "another tag",
+ "project_id": "33"
+ }
+ ],
+ "id": 45253426
+}
+```
+
+getTagsByProject
+----------------
+
+- Purpose: **Get all tags for a given project**
+- Parameters:
+ - **project_id** (integer)
+- Result on success: **List of tags**
+- Result on failure: **false|null**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"getTagsByProject","id":1217591720,"params":[33]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "id": "1",
+ "name": "some tag",
+ "project_id": "33"
+ }
+ ],
+ "id": 1217591720
+}
+```
+
+createTag
+---------
+
+- Purpose: **Create a new tag**
+- Parameters:
+ - **project_id** (integer)
+ - **tag** (string)
+- Result on success: **tag_id**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"createTag","id":1775436017,"params":[33,"some tag"]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": 1,
+ "id": 1775436017
+}
+```
+
+updateTag
+---------
+
+- Purpose: **Rename a tag**
+- Parameters:
+ - **tag_id** (integer)
+ - **tag** (string)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"updateTag","id":2037516512,"params":["1","another tag"]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 2037516512
+}
+```
+
+removeTag
+---------
+
+- Purpose: **removeTag**
+- Parameters:
+ - **tag_id** (integer)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"removeTag","id":907581298,"params":["1"]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 907581298
+}
+```
+
+setTaskTags
+-----------
+
+- Purpose: **Assign/Create/Update tags for a task**
+- Parameters:
+ - **project_id** (integer)
+ - **task_id** (integer)
+ - **tags** List of tags ([]string)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"setTaskTags","id":1524522873,"params":[39,17,["tag1","tag2"]]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 1524522873
+}
+```
+
+getTaskTags
+-----------
+
+- Purpose: **Get assigned tags to a task**
+- Parameters:
+ - **task_id** (integer)
+- Result on success: **Dictionary of tags**
+- Result on failure: **false|null**
+
+Request example:
+
+```json
+{"jsonrpc":"2.0","method":"getTaskTags","id":1667157705,"params":[17]}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "1": "tag1",
+ "2": "tag2"
+ },
+ "id": 1667157705
+}
+```
diff --git a/doc/api-task-procedures.markdown b/doc/api-task-procedures.markdown
index 2897c81a..db106f74 100644
--- a/doc/api-task-procedures.markdown
+++ b/doc/api-task-procedures.markdown
@@ -17,11 +17,12 @@ API Task Procedures
- **score** (integer, optional)
- **swimlane_id** (integer, optional)
- **priority** (integer, optional)
- - **recurrence_status** (integer, optional)
- - **recurrence_trigger** (integer, optional)
- - **recurrence_factor** (integer, optional)
- - **recurrence_timeframe** (integer, optional)
- - **recurrence_basedate** (integer, optional)
+ - **recurrence_status** (integer, optional)
+ - **recurrence_trigger** (integer, optional)
+ - **recurrence_factor** (integer, optional)
+ - **recurrence_timeframe** (integer, optional)
+ - **recurrence_basedate** (integer, optional)
+ - **tags** ([]string, optional)
- Result on success: **task_id**
- Result on failure: **false**
@@ -400,11 +401,12 @@ Response example:
- **category_id** (integer, optional)
- **score** (integer, optional)
- **priority** (integer, optional)
- - **recurrence_status** (integer, optional)
- - **recurrence_trigger** (integer, optional)
- - **recurrence_factor** (integer, optional)
- - **recurrence_timeframe** (integer, optional)
- - **recurrence_basedate** (integer, optional)
+ - **recurrence_status** (integer, optional)
+ - **recurrence_trigger** (integer, optional)
+ - **recurrence_factor** (integer, optional)
+ - **recurrence_timeframe** (integer, optional)
+ - **recurrence_basedate** (integer, optional)
+ - **tags** ([]string, optional)
- Result on success: **true**
- Result on failure: **false**
diff --git a/doc/automatic-actions.markdown b/doc/automatic-actions.markdown
index d109a95b..add62662 100644
--- a/doc/automatic-actions.markdown
+++ b/doc/automatic-actions.markdown
@@ -1,15 +1,15 @@
Automatic Actions
=================
-To minimize the user interaction, Kanboard support automated actions.
+To minimize user interaction, Kanboard support automated actions.
-Each automatic action is defined like that:
+Each automatic action is defined with these properties:
- An event to listen
-- Action linked to this event
-- Eventually there is some parameters to define
+- Action linked to the event
+- Additional parameters
-Each project has a different set of automatic actions, the configuration panel is located on the project listing page, just click on the link **Automatic actions**.
+Each project has a different set of automatic actions. The configuration panel is located on the project listing page - just click on the link **Automatic actions**.
Add a new action
----------------
@@ -18,19 +18,19 @@ Click on the link **Add a new automatic action**.
![Automatique action](screenshots/automatic-action-creation.png)
-- Choose an action
-- Then, select an event
-- And finally, define the parameters
+1. Choose an action
+2. Select an event
+3. Define the parameters
-List of available actions
+Available actions
-------------------------
- Create a comment from an external provider
- Add a comment log when moving the task between columns
-- Assign automatically a category based on a color
+- Automatically assign a category based on a color
- Change the category based on an external label
-- Assign automatically a category based on a link
-- Assign automatically a color based on a category
+- Automatically assign a category based on a link
+- Automatically assign a color based on a category
- Assign a color when the task is moved to a specific column
- Change task color when using a specific task link
- Assign a color to a specific user
@@ -75,7 +75,7 @@ Here are some examples used in real life:
### When a task is completed, duplicate this task to another project
-Let's say we have two projects "Customer orders" and "Production", once the order is validated, swap it to the "Production" project.
+Let's say we have two projects: "Customer orders" and "Production". Once the order is validated, swap it to the "Production" project.
- Choose action: **Duplicate the task to another project**
- Choose the event: **Closing a task**
@@ -83,7 +83,7 @@ Let's say we have two projects "Customer orders" and "Production", once the orde
### When a task is moved to the last column, move the exact same task to another project
-Let's say we have two projects "Ideas" and "Development", once the idea is validated, swap it to the "Development" project.
+Let's say we have two projects: "Ideas" and "Development". Once the idea is validated, swap it to the "Development" project.
- Choose action: **Move the task to another project**
- Choose the event: **Move a task to another column**
diff --git a/doc/board-collapsed-expanded.markdown b/doc/board-collapsed-expanded.markdown
index 0164da95..aeffcf10 100644
--- a/doc/board-collapsed-expanded.markdown
+++ b/doc/board-collapsed-expanded.markdown
@@ -9,7 +9,7 @@ Collapsed mode
![Tasks collapsed](screenshots/board-collapsed-mode.png)
-- If the task is assigned to someone, the initials of the person are shown next to the task number
+- If the task is assigned to someone, the initials of the person are shown next to the task number.
- If the task title is too long, you can put your mouse over the task to show a tooltip with the full title.
Expanded mode
diff --git a/doc/board-show-hide-columns.markdown b/doc/board-show-hide-columns.markdown
index 113298d3..0da2d28d 100644
--- a/doc/board-show-hide-columns.markdown
+++ b/doc/board-show-hide-columns.markdown
@@ -9,4 +9,4 @@ To hide a column, click on the column dropdown menu and choose "Hide this column
![Show a column](screenshots/show-column.png)
-To show again the column, click on the "plus icon".
+To show the column again, click on the "plus icon".
diff --git a/doc/cli.markdown b/doc/cli.markdown
index 8bd5bde5..b1722308 100644
--- a/doc/cli.markdown
+++ b/doc/cli.markdown
@@ -30,6 +30,7 @@ Options:
Available commands:
cronjob Execute daily cronjob
help Displays help for a command
+ job Execute individual job (read payload from stdin)
list Lists commands
worker Execute queue worker
db
@@ -207,6 +208,12 @@ Note: Installed files will have the same permissions as the current user
./cli worker
```
+### Execute individual job (mostly for debugging)
+
+```bash
+echo 'RAW_JOB_DATA' | ./cli job
+```
+
### Execute database migrations
If the parameter `DB_RUN_MIGRATIONS` is set to `false`, you have run the database migrations manually:
diff --git a/doc/creating-projects.markdown b/doc/creating-projects.markdown
index 373d93eb..05d5b20c 100644
--- a/doc/creating-projects.markdown
+++ b/doc/creating-projects.markdown
@@ -16,24 +16,24 @@ From the dashboard, click on the link **New project**:
![Project creation form](screenshots/new-project.png)
-It's very easy, you just have to find a name for your project!
+It's very easy: you just have to find a name for your project!
Creating a private project
--------------------------
-- Everybody can create a private project
+- Anybody can create a private project
- There is **NO** user management
-- Only the owner and administrators can access to the project
+- Only the owner and administrators can access the project
From the dashboard, click on the link **New private project**.
Creating projects from another project
--------------------------------------
-When you create a new project, your can choose to duplicate the properties of another project :
+When you create a new project, you can choose to duplicate the properties of another project:
- Permissions
- Actions
- Swimlanes
-- Catégories
+- Categories
- Tasks
diff --git a/doc/editing-projects.markdown b/doc/editing-projects.markdown
index e7fea212..c9c1a5a0 100644
--- a/doc/editing-projects.markdown
+++ b/doc/editing-projects.markdown
@@ -1,15 +1,15 @@
Editing Projects
================
-Projects can be renamed and disabled at any time.
+Projects can be renamed or disabled at any time.
-To rename a project, just click on the link "Edit project" on the left.
+To rename a project, just click on the link entitled "Edit project" on the left.
![Project edition](screenshots/project-edition.png)
-- The start date and end date are used to generate the project Gantt chart
-- The description is visible as tooltip on the board and on the projects listing page
-- Administrators and project administrators can convert a private project to multiple users project by changing the checkbox "Private project".
-- You can also convert multiple users project to a private project.
+- The start date and end date are used to generate the project Gantt chart.
+- The description is visible as a tooltip on the board and on the projects listing page.
+- Administrators and project administrators can convert a private project to a multiple-user project by changing the checkbox "Private project".
+- You can also convert a multiple-user project to a private project.
-Note: When you make a project private, all existing users will still have access to the project. Adjust the list of users according to your needs.
+Note: When you make a project private, all existing users will still have access to the project. You can adjust the list of users according to your needs.
diff --git a/doc/es_ES/kanban-vs-todo-and-scrum.markdown b/doc/es_ES/kanban-vs-todo-and-scrum.markdown
index 6e8d9e6c..5295a6d1 100644
--- a/doc/es_ES/kanban-vs-todo-and-scrum.markdown
+++ b/doc/es_ES/kanban-vs-todo-and-scrum.markdown
@@ -11,7 +11,7 @@ Kanban vs Todo lists
### Kanban:
-- Multi fases,
+- Multi fases,
- Concentración absoluta para evitar multitareas por que se puede establecer un limite por columna para mejorar el progreso
diff --git a/doc/installation.markdown b/doc/installation.markdown
index 518282be..d8969c1c 100644
--- a/doc/installation.markdown
+++ b/doc/installation.markdown
@@ -60,7 +60,7 @@ Other Database Types
Kanboard supports Mysql and Postgres as alternative to Sqlite.
-- [Mysql configuration](mysql-configuration.markdown]
+- [Mysql configuration](mysql-configuration.markdown)
- [Postgres configuration](postgresql-configuration.markdown)
Optional Installation
diff --git a/doc/kanban-vs-todo-and-scrum.markdown b/doc/kanban-vs-todo-and-scrum.markdown
index 4e083ff8..ea97811c 100644
--- a/doc/kanban-vs-todo-and-scrum.markdown
+++ b/doc/kanban-vs-todo-and-scrum.markdown
@@ -11,8 +11,8 @@ Kanban vs Todo lists
### Kanban:
-- Multiple phases, each column represent a step
-- Bring focus and avoid multitasking because you can set a work in progress limit per column
+- Multiple phases, each column represents a step
+- Bring focus and avoid multitasking by setting a work-in-progress limit per column
Kanban vs Scrum
---------------
@@ -23,15 +23,15 @@ Kanban vs Scrum
- Do not allow changes during the iteration
- Estimation is required
- Uses velocity as default metric
-- Scrum board is cleared between each sprint
+- Scrum board is cleared between sprints
- Scrum has pre-defined roles like scrum master, product owners and the team
- A lot of meetings: planning, backlogs grooming, daily stand-up, retrospective
### Kanban:
- Continuous flow
-- Changes can be made at anytime
+- Changes can be made at any time
- Estimation is optional
- Use lead and cycle time to measure performance
- Kanban board is persistent
-- Kanban doesn't impose strict constraints or meetings, process is more flexible
+- Kanban doesn't impose strict constraints or meetings; process is more flexible
diff --git a/doc/mysql-configuration.markdown b/doc/mysql-configuration.markdown
index 9d60271c..c199353e 100644
--- a/doc/mysql-configuration.markdown
+++ b/doc/mysql-configuration.markdown
@@ -1,23 +1,23 @@
-Mysql/MariaDB Configuration
+MySQL/MariaDB Configuration
===========================
By default Kanboard use Sqlite to stores its data.
-However it's possible to use Mysql or MariaDB instead of Sqlite.
+However it's possible to use MySQL or MariaDB instead of Sqlite.
Requirements
------------
-- Mysql server
+- MySQL server
- The PHP extension `pdo_mysql` installed
-Note: Kanboard is tested with **Mysql >= 5.5 and MariaDB >= 10.0**
+Note: Kanboard is tested with **MySQL >= 5.5 and MariaDB >= 10.0**
-Mysql configuration
+MySQL configuration
-------------------
### Create a database
-The first step is to create a database on your Mysql server.
+The first step is to create a database on your MySQL server.
By example, you can do that with the command line mysql client:
```sql
@@ -31,10 +31,10 @@ The file `config.php` should contains those values:
```php
<?php
-// We choose to use Mysql instead of Sqlite
+// We choose to use MySQL instead of Sqlite
define('DB_DRIVER', 'mysql');
-// Mysql parameters
+// MySQL parameters
define('DB_USERNAME', 'REPLACE_ME');
define('DB_PASSWORD', 'REPLACE_ME');
define('DB_HOSTNAME', 'REPLACE_ME');
@@ -58,15 +58,15 @@ The file `app/Schema/Sql/mysql.sql` is a SQL dump that represents the last versi
SSL configuration
-----------------
-These parameters have to be defined to enable the Mysql SSL connection:
+These parameters have to be defined to enable the MySQL SSL connection:
```php
-// Mysql SSL key
+// MySQL SSL key
define('DB_SSL_KEY', '/path/to/client-key.pem');
-// Mysql SSL certificate
+// MySQL SSL certificate
define('DB_SSL_CERT', '/path/to/client-cert.pem');
-// Mysql SSL CA
+// MySQL SSL CA
define('DB_SSL_CA', '/path/to/ca-cert.pem');
```
diff --git a/doc/nice-urls.markdown b/doc/nice-urls.markdown
index bfea719d..a054e85d 100644
--- a/doc/nice-urls.markdown
+++ b/doc/nice-urls.markdown
@@ -85,6 +85,51 @@ In your Kanboard `config.php`:
define('ENABLE_URL_REWRITE', true);
```
+Another example with Kanboard in a subfolder:
+
+```
+server {
+ listen 443 ssl default_server;
+ listen [::]:443 ssl default_server;
+
+ root /var/www/html;
+ index index.php index.html index.htm;
+ server_name _;
+
+ location / {
+ try_files $uri $uri/ =404;
+ }
+
+ location ^~ /kanboard {
+
+ location /kanboard {
+ try_files $uri $uri/ /kanboard/index.php$is_args$args;
+ }
+
+ location ~ ^/kanboard/(?:kanboard|config.php|config.default.php) {
+ deny all;
+ }
+
+ location ~* /kanboard/data {
+ deny all;
+ }
+
+ location ~ \.php(?:$|/) {
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param HTTPS on; # Use only if HTTPS is configured
+ include fastcgi_params;
+ fastcgi_pass unix:/var/run/php5-fpm.sock;
+ }
+
+ location ~ /kanboard/\.ht {
+ deny all;
+ }
+ }
+}
+```
+
Adapt the example above according to your own configuration.
IIS configuration example
diff --git a/doc/plugin-helpers.markdown b/doc/plugin-helpers.markdown
index 8cc6b42a..d65467f8 100644
--- a/doc/plugin-helpers.markdown
+++ b/doc/plugin-helpers.markdown
@@ -6,7 +6,7 @@ Helper skeleton:
```php
<?php
-namespace Kanboard\Plugin\MyPlugin\Helper\MyHelper;
+namespace Kanboard\Plugin\MyPlugin\Helper;
use Kanboard\Core\Base;
diff --git a/doc/plugin-hooks.markdown b/doc/plugin-hooks.markdown
index 8f1a3bb7..23750ff7 100644
--- a/doc/plugin-hooks.markdown
+++ b/doc/plugin-hooks.markdown
@@ -202,6 +202,7 @@ List of template hooks:
| `template:board:task:footer` | Task in board: footer |
| `template:board:task:icons` | Task in board: tooltip icon |
| `template:board:column:dropdown` | Dropdown menu in board columns |
+| `template:board:column:header` | Board column header |
| `template:board:tooltip:subtasks:header:before-assignee` | Header of Subtask table on tootip before Assignee |
| `template:board:tooltip:subtasks:rows` | Column on row of Subtask table on tooltip |
| `template:config:sidebar` | Sidebar on settings page |
@@ -212,8 +213,6 @@ List of template hooks:
| `template:dashboard:show` | Main page of the dashboard |
| `template:dashboard:subtasks:header:before-timetracking` | Header of Subtask table before Time Tracking |
| `template:dashboard:subtasks:rows` | Column on row of Subtask table of the dashboard |
-| `template:export:sidebar` | Sidebar on export pages |
-| `template:import:sidebar` | Sidebar on import pages |
| `template:header:dropdown` | Page header dropdown menu (user avatar icon) |
| `template:header:creation-dropdown` | Page header dropdown menu (plus icon) |
| `template:layout:head` | Page layout `<head/>` tag |
@@ -227,6 +226,7 @@ List of template hooks:
| `template:project-user:sidebar` | Sidebar on project user overview page |
| `template:project-list:menu:before` | Project list: before menu entries |
| `template:project-list:menu:after` | Project list: after menu entries |
+| `template:project-overview:before-description` | Project overview: before description |
| `template:task:layout:top` | Task layout top (after page header) |
| `template:task:details:top` | Task summary top |
| `template:task:details:bottom` | Task summary bottom |
diff --git a/doc/plugin-overrides.markdown b/doc/plugin-overrides.markdown
index 96a09e47..3b94bd60 100644
--- a/doc/plugin-overrides.markdown
+++ b/doc/plugin-overrides.markdown
@@ -40,3 +40,34 @@ You can still use the original template using the "kanboard:" prefix:
```php
<?= $this->render('kanboard:header') ?>
```
+
+Formatter Overrides
+-------------------
+
+Here an example to override formatter objects in Kanboard:
+
+```php
+class MyFormatter extends UserAutoCompleteFormatter
+{
+ public function format()
+ {
+ $users = parent::format();
+
+ foreach ($users as &$user) {
+ $user['label'] = 'something'; // Do something useful here
+ }
+
+ return $users;
+ }
+}
+
+class Plugin extends Base
+{
+ public function initialize()
+ {
+ $this->container['userAutoCompleteFormatter'] = $this->container->factory(function ($c) {
+ return new MyFormatter($c);
+ });
+ }
+}
+```
diff --git a/doc/plugin-registration.markdown b/doc/plugin-registration.markdown
index 2c80aab3..5a4a6234 100644
--- a/doc/plugin-registration.markdown
+++ b/doc/plugin-registration.markdown
@@ -71,6 +71,15 @@ class Plugin extends Base
{
$this->template->hook->attach('template:layout:head', 'theme:layout/head');
}
+
+ public function getCompatibleVersion()
+ {
+ // Examples:
+ // >=1.0.37
+ // <1.0.37
+ // <=1.0.37
+ return '1.0.37';
+ }
}
```
@@ -93,6 +102,7 @@ Available methods from `Kanboard\Core\Plugin\Base`:
- `getPluginHomepage()`: Should return plugin Homepage (link)
- `setContentSecurityPolicy(array $rules)`: Override default HTTP CSP rules
- `onStartup()`: If present, this method is executed automatically when the event "app.bootstrap" is triggered
+- `getCompatibleVersion()`: You may want to specify the Kanboard version compatible with the plugin
Your plugin registration class can also inherit from Kanboard\Core\Base, that way you can access all classes and methods of Kanboard easily.
diff --git a/doc/project-permissions.markdown b/doc/project-permissions.markdown
index 16586bc6..99e4caa2 100644
--- a/doc/project-permissions.markdown
+++ b/doc/project-permissions.markdown
@@ -1,8 +1,8 @@
Project Permissions
===================
-Each project is isolated and compartmented from each other.
-The project access must be allowed by the project owner.
+Each project is isolated from other projects.
+Project access must be allowed by the project owner.
Each user and each group can have a different role assigned.
There are 3 types of [roles for projects](roles.markdown):
@@ -13,11 +13,11 @@ There are 3 types of [roles for projects](roles.markdown):
Only administrators have access to everything.
-Roles assignation is available from **Project Settings > Permissions**:
+Role assignments are visible in **Project Settings > Permissions**:
![Project Permissions](screenshots/project-permissions.png)
-If you choose to allow everybody, all Kanboard users will be considered Project Member.
-That also means there is no role management anymore. Permission per user or per group cannot be applied.
+If you choose to allow everybody, all Kanboard users will be considered 'Project Member'.
+With this setting, role management will have no effect. Permission per user or per group cannot be applied.
-Private projects cannot define permission.
+Private projects cannot define permissions.
diff --git a/doc/project-views.markdown b/doc/project-views.markdown
index 19284407..f700055e 100644
--- a/doc/project-views.markdown
+++ b/doc/project-views.markdown
@@ -10,7 +10,7 @@ Board View
![Board view](screenshots/board-view.png)
-- With this view you can drag and drop tasks between columns easily.
+- With this view, you can drag and drop tasks between columns easily.
- You can also use the keyboard shortcut **"v b"** to switch to the board view.
- Tasks with a shadow are recently modified.
@@ -25,7 +25,7 @@ Calendar View
![Calendar view](screenshots/calendar-view.png)
-- With this view you can visualize tasks with a due date.
+- With this view, you can visualize tasks with a due date.
- Depending of the settings, you can also see tasks in progress.
- You can also use the keyboard shortcut **"v c"** to switch to the calendar view.
- [Learn more about calendar configuration](calendar-configuration.markdown)
@@ -35,7 +35,7 @@ List View
![List view](screenshots/list-view.png)
-- With this view all results of your search are displayed in a table.
+- With this view, all results of your search are displayed in a table.
- You can also use the keyboard shortcut **"v l"** to switch to the list view.
Gantt View
@@ -43,16 +43,16 @@ Gantt View
![Gantt view](screenshots/gantt-view.png)
-- The Gantt view displays tasks on a horizontal timeline
-- The start date and the due date are used to display the chart
-- For quick access, use the keyboard shortcut: **v g**
+- The Gantt view displays tasks on a horizontal timeline.
+- The start date and the due date are used to display the chart.
+- For quick access, use the keyboard shortcut: **v g**.
Project Overview
----------------
![Project overview](screenshots/project-view.png)
-- View the description of the project
-- Attach and upload documents to the project
-- View list of project members
-- View the last activities of the project
+- View the description of the project.
+- Attach and upload documents to the project.
+- View list of project members.
+- View the last activities of the project.
diff --git a/doc/removing-projects.markdown b/doc/removing-projects.markdown
index f9e622cb..0c4c5f36 100644
--- a/doc/removing-projects.markdown
+++ b/doc/removing-projects.markdown
@@ -1,10 +1,10 @@
Removing Projects
=================
-To remove a project, you must be manager of the project or administrator.
+To remove a project, you must be the manager of the project or an administrator.
Go to the **"Project settings"**, and from the menu on the left, at the bottom, choose **"Remove"**.
![Removing Projects](screenshots/project-remove.png)
-Removing a project remove all tasks that belongs to this project.
+Removing a project removes all tasks that belong to this project.
diff --git a/doc/search.markdown b/doc/search.markdown
index 17d27416..760551df 100644
--- a/doc/search.markdown
+++ b/doc/search.markdown
@@ -106,6 +106,10 @@ Attribute: **description** or **desc**
Example: `description:"text search"`
+### Search by completion
+
+Attribute: **completed**
+
### Search by external reference
The task reference is an external id of your task, by example a ticket number from another software.
diff --git a/doc/sharing-projects.markdown b/doc/sharing-projects.markdown
index 614c3230..400f7cb4 100644
--- a/doc/sharing-projects.markdown
+++ b/doc/sharing-projects.markdown
@@ -1,13 +1,13 @@
Sharing boards and tasks
========================
-By default, boards are private but it's possible to make a board public.
+By default, boards are private, but it's possible to make a board public.
-A public board **cannot be modified, it's a read-only access**.
-This access is protected by a random token, only people who have the right URL can see the board.
+A public board **cannot be modified: it has read-only access**.
+Access is protected by a random token. Only people who have the right URL can see the board.
Public boards are automatically refreshed every 60 seconds.
-Task details are also available in read-only.
+Task details are also available in read-only mode.
Usage examples:
@@ -21,7 +21,7 @@ Select your project, then click on "Public access" and finally click on the butt
![Enable public access](screenshots/project-enable-sharing.png)
-When the public access is enabled, a couple of links are generated:
+When public access is enabled, a couple of links are generated:
- Public board view
- RSS feed subscription link
@@ -29,7 +29,7 @@ When the public access is enabled, a couple of links are generated:
![Disable public access](screenshots/project-disable-sharing.png)
-You can also disable the public access whenever you want.
+You can also disable public access whenever you want.
-Each time, you enable or disable the public access a new random token is generated.
-**The previous links will not work anymore**.
+Each time you enable or disable public access, a new random token is generated.
+**The previous links will not work anymore**!
diff --git a/doc/suse-installation.markdown b/doc/suse-installation.markdown
index 788b4fce..2af773f7 100644
--- a/doc/suse-installation.markdown
+++ b/doc/suse-installation.markdown
@@ -9,6 +9,6 @@ sudo zypper install php5 php5-sqlite php5-gd php5-json php5-mcrypt php5-mbstring
cd /srv/www/htdocs
sudo wget https://kanboard.net/kanboard-latest.zip
sudo unzip kanboard-latest.zip
-sudo chmod -R 777 kanboard
+sudo chown -R wwwrun /srv/www/htdocs/kanboard
sudo rm kanboard-latest.zip
```
diff --git a/doc/usage-examples.markdown b/doc/usage-examples.markdown
index 5efc6f9a..c200e082 100644
--- a/doc/usage-examples.markdown
+++ b/doc/usage-examples.markdown
@@ -8,7 +8,7 @@ Software development
- Backlog
- Ready
-- Work in progress
+- Work-in-progress
- To be validated
- Validated
- Deployed in production
@@ -18,7 +18,7 @@ Bug tracking
- Reported
- Confirmed
-- Work in progress
+- Work-in-progress
- Tested
- Fixed
diff --git a/doc/what-is-kanban.markdown b/doc/what-is-kanban.markdown
index 5d2eed02..de8377b2 100644
--- a/doc/what-is-kanban.markdown
+++ b/doc/what-is-kanban.markdown
@@ -11,22 +11,22 @@ There are only two constraints imposed by Kanban:
Visualize your workflow
-----------------------
-- Your work is displayed on a board, you have a clear overview of your project
+- Your work is displayed on a board so that you have a clear overview of your project
- Each column represents a step in your workflow
-Bring focus and avoid multitasking
+Limit your work in progress
----------------------------------
-
-- Each phase can have a work in progress limits
-- Limits are great to identify bottlenecks
+- Encourages focus by avoiding multitasking
+- Each phase can have work-in-progress limits
+- Limits help identify bottlenecks
- Limits avoid working on too many tasks at the same time
-Measure performance and improvement
------------------------------------
+Performance Measurement
+=======================
Kanban uses lead and cycle times to measure performance:
-- **Lead time**: Time between the task is created and completed
-- **Cycle time**: Time between the task is started and completed
+- **Lead time**: Time between task creation and completion
+- **Cycle time**: Time between task start and completion
-For example, you may have a lead time of 100 days and only have to work 1 hour to complete the task.
+For example, you may have a lead time of 100 days but only have to work 1 hour to complete the task.
diff --git a/gulpfile.js b/gulpfile.js
index 3b641b06..0f4e405d 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -3,7 +3,6 @@ var concat = require('gulp-concat');
var bower = require('gulp-bower');
var uglify = require('gulp-uglify');
var sass = require('gulp-sass');
-var strip = require('gulp-strip-comments');
var src = {
js: [
@@ -48,8 +47,6 @@ var vendor = {
'bower_components/moment/min/moment.min.js',
'bower_components/fullcalendar/dist/fullcalendar.min.js',
'bower_components/fullcalendar/dist/locale-all.js',
- 'bower_components/mousetrap/mousetrap.min.js',
- 'bower_components/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js',
'bower_components/d3/d3.min.js',
'bower_components/c3/c3.min.js',
'bower_components/isMobile/isMobile.min.js',
diff --git a/package.json b/package.json
index d2a47830..e4e0b780 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,13 @@
{
"name": "kanboard",
"devDependencies": {
- "bower": "^1.7.9",
+ "bower": "^1.8.0",
"gulp": "^3.9.1",
- "gulp-bower": "0.0.13",
- "gulp-cli": "^1.2.1",
- "gulp-concat": "^2.6.0",
- "gulp-sass": "^2.3.2",
- "gulp-strip-comments": "^2.4.3",
- "gulp-uglify": "^1.5.3",
+ "gulp-bower": "^0.0.13",
+ "gulp-cli": "^1.2.2",
+ "gulp-concat": "^2.6.1",
+ "gulp-sass": "^3.0.0",
+ "gulp-uglify": "^2.0.0",
"jshint": "^2.9.4"
},
"dependencies": {
diff --git a/tests/integration/CommentProcedureTest.php b/tests/integration/CommentProcedureTest.php
index 881d938c..0a969420 100644
--- a/tests/integration/CommentProcedureTest.php
+++ b/tests/integration/CommentProcedureTest.php
@@ -35,10 +35,12 @@ class CommentProcedureTest extends BaseProcedureTest
$this->assertNotEmpty($comment);
$this->assertEquals(1, $comment['user_id']);
$this->assertEquals('foobar', $comment['comment']);
+ $this->assertEquals($comment['date_creation'], $comment['date_modification']);
}
public function assertUpdateComment()
{
+ sleep(1); // Integration test fails because its too fast
$this->assertTrue($this->app->execute('updateComment', array(
'id' => $this->commentId,
'content' => 'test',
@@ -46,6 +48,7 @@ class CommentProcedureTest extends BaseProcedureTest
$comment = $this->app->getComment($this->commentId);
$this->assertEquals('test', $comment['comment']);
+ $this->assertNotEquals($comment['date_creation'], $comment['date_modification']);
}
public function assertGetAllComments()
diff --git a/tests/integration/TaskTagProcedureTest.php b/tests/integration/TaskTagProcedureTest.php
index ae6139d3..4b820c9a 100644
--- a/tests/integration/TaskTagProcedureTest.php
+++ b/tests/integration/TaskTagProcedureTest.php
@@ -12,6 +12,8 @@ class TaskTagProcedureTest extends BaseProcedureTest
$this->assertCreateTask();
$this->assertSetTaskTags();
$this->assertGetTaskTags();
+ $this->assertCreateTaskWithTags();
+ $this->assertUpdateTaskWithTags();
}
public function assertSetTaskTags()
@@ -24,4 +26,29 @@ class TaskTagProcedureTest extends BaseProcedureTest
$tags = $this->app->getTaskTags($this->taskId);
$this->assertEquals(array('tag1', 'tag2'), array_values($tags));
}
+
+ public function assertCreateTaskWithTags()
+ {
+ $this->taskId = $this->app->createTask(array(
+ 'title' => $this->taskTitle,
+ 'project_id' => $this->projectId,
+ 'tags' => array('tag A', 'tag B'),
+ ));
+
+ $this->assertNotFalse($this->taskId);
+
+ $tags = $this->app->getTaskTags($this->taskId);
+ $this->assertEquals(array('tag A', 'tag B'), array_values($tags));
+ }
+
+ public function assertUpdateTaskWithTags()
+ {
+ $this->assertTrue($this->app->updateTask(array(
+ 'id' => $this->taskId,
+ 'tags' => array('tag C'),
+ )));
+
+ $tags = $this->app->getTaskTags($this->taskId);
+ $this->assertEquals(array('tag C'), array_values($tags));
+ }
}
diff --git a/tests/units.postgres.xml b/tests/units.postgres.xml
index 3442db1c..cf538a82 100644
--- a/tests/units.postgres.xml
+++ b/tests/units.postgres.xml
@@ -10,4 +10,4 @@
<const name="DB_PASSWORD" value="" />
<const name="DB_NAME" value="kanboard_unit_test" />
</php>
-</phpunit> \ No newline at end of file
+</phpunit>
diff --git a/tests/units/Base.php b/tests/units/Base.php
index 1b986fcb..1c93e9b8 100644
--- a/tests/units/Base.php
+++ b/tests/units/Base.php
@@ -47,6 +47,7 @@ abstract class Base extends PHPUnit_Framework_TestCase
$this->container->register(new Kanboard\ServiceProvider\RouteProvider());
$this->container->register(new Kanboard\ServiceProvider\AvatarProvider());
$this->container->register(new Kanboard\ServiceProvider\FilterProvider());
+ $this->container->register(new Kanboard\ServiceProvider\FormatterProvider());
$this->container->register(new Kanboard\ServiceProvider\JobProvider());
$this->container->register(new Kanboard\ServiceProvider\QueueProvider());
$this->container->register(new Kanboard\ServiceProvider\ExternalTaskProvider());
diff --git a/tests/units/Core/DateParserTest.php b/tests/units/Core/DateParserTest.php
index 1cf98bd3..e0dfb4c1 100644
--- a/tests/units/Core/DateParserTest.php
+++ b/tests/units/Core/DateParserTest.php
@@ -64,7 +64,7 @@ class DateParserTest extends Base
$dates = $dateParser->getDateTimeFormats(true);
$this->assertEquals('m/d/Y H:i', $dates[0]);
- $this->container['configModel']->save(array('application_datetime_format' => 'd/m/Y g:i a'));
+ $this->container['configModel']->save(array('application_date_format' => 'd/m/Y', 'application_time_format' => 'g:i a'));
$this->container['memoryCache']->flush();
$dates = $dateParser->getDateTimeFormats();
@@ -121,7 +121,7 @@ class DateParserTest extends Base
{
$this->container['configModel']->save(array(
'application_date_format' => 'd/m/Y',
- 'application_datetime_format' => 'd/m/Y g:i a',
+ 'application_time_format' => 'g:i a',
));
$dateParser = new DateParser($this->container);
@@ -138,7 +138,7 @@ class DateParserTest extends Base
{
$this->container['configModel']->save(array(
'application_date_format' => 'd.m.Y',
- 'application_datetime_format' => 'd.m.Y H:i',
+ 'application_time_format' => 'H:i',
));
$dateParser = new DateParser($this->container);
@@ -204,9 +204,6 @@ class DateParserTest extends Base
$this->assertEquals(array('date' => '06/02/2016'), $dateParser->format($values, array('date'), 'd/m/Y'));
$this->assertEquals(array('date' => '02/06/2016 7:30 pm'), $dateParser->format($values, array('date'), 'm/d/Y g:i a'));
-
- $values['date'] = '2016-02-06';
- $this->assertEquals(array('date' => '06/02/2016'), $dateParser->format($values, array('date'), 'd/m/Y'));
}
public function testConvert()
diff --git a/tests/units/Core/ExternalTask/ExternalTaskManagerTest.php b/tests/units/Core/ExternalTask/ExternalTaskManagerTest.php
index e6f4e069..8eec64de 100644
--- a/tests/units/Core/ExternalTask/ExternalTaskManagerTest.php
+++ b/tests/units/Core/ExternalTask/ExternalTaskManagerTest.php
@@ -41,4 +41,10 @@ class ExternalTaskManagerTest extends Base
$expected = array('MyProvider1' => 'MyProvider1', 'MyProvider2' => 'MyProvider2');
$this->assertEquals($expected, $providers);
}
+
+ public function testGetProviderListWithNoProviders()
+ {
+ $manager = new ExternalTaskManager();
+ $this->assertSame(array(), $manager->getProvidersList());
+ }
}
diff --git a/tests/units/Core/Http/RequestTest.php b/tests/units/Core/Http/RequestTest.php
index 1db0100c..697c3c0f 100644
--- a/tests/units/Core/Http/RequestTest.php
+++ b/tests/units/Core/Http/RequestTest.php
@@ -43,6 +43,9 @@ class RequestTest extends Base
$request = new Request($this->container, array(), array(), array('myvar' => 'myvalue', 'csrf_token' => $this->container['token']->getCSRFToken()), array(), array());
$this->assertEquals(array('myvar' => 'myvalue'), $request->getValues());
+
+ $request = new Request($this->container, array(), array(), array('myvar' => 'myvalue', '-----------------------------7e1c32510025c--' => '', 'csrf_token' => $this->container['token']->getCSRFToken()), array(), array());
+ $this->assertEquals(array('myvar' => 'myvalue'), $request->getValues());
}
public function testGetFileContent()
diff --git a/tests/units/Core/Plugin/VersionTest.php b/tests/units/Core/Plugin/VersionTest.php
new file mode 100644
index 00000000..78f10d95
--- /dev/null
+++ b/tests/units/Core/Plugin/VersionTest.php
@@ -0,0 +1,29 @@
+<?php
+
+use Kanboard\Core\Plugin\Version;
+
+require_once __DIR__.'/../../Base.php';
+
+class VersionTest extends Base
+{
+ public function testIsCompatible()
+ {
+ $this->assertFalse(Version::isCompatible('1.0.29', '1.0.28'));
+ $this->assertTrue(Version::isCompatible('1.0.28', '1.0.28'));
+ $this->assertTrue(Version::isCompatible('1.0.28', 'master.1234'));
+ $this->assertTrue(Version::isCompatible('>=1.0.32', 'master'));
+ $this->assertTrue(Version::isCompatible('>=1.0.32', '1.0.32'));
+ $this->assertTrue(Version::isCompatible('>=1.0.32', '1.0.33'));
+ $this->assertTrue(Version::isCompatible('>1.0.32', '1.0.33'));
+ $this->assertFalse(Version::isCompatible('>1.0.32', '1.0.32'));
+ $this->assertTrue(Version::isCompatible('1.0.32', 'v1.0.32'));
+ $this->assertTrue(Version::isCompatible('>=v1.0.32', 'v1.0.32'));
+ $this->assertTrue(Version::isCompatible('<=v1.0.36', 'v1.0.36'));
+ $this->assertFalse(Version::isCompatible('<1.0.36', 'v1.0.36'));
+ $this->assertTrue(Version::isCompatible('<1.0.40', '1.0.36'));
+ $this->assertTrue(Version::isCompatible('<=1.0.40', '1.0.36'));
+ $this->assertFalse(Version::isCompatible('<1.0.40', '1.0.40'));
+ $this->assertFalse(Version::isCompatible('1.0.40', 'v1.0.36'));
+ $this->assertTrue(Version::isCompatible('<1.1.0', 'v1.0.36'));
+ }
+}
diff --git a/tests/units/Helper/FileHelperText.php b/tests/units/Helper/FileHelperTest.php
index 215b024b..7db43460 100644
--- a/tests/units/Helper/FileHelperText.php
+++ b/tests/units/Helper/FileHelperTest.php
@@ -30,7 +30,14 @@ class FileHelperTest extends Base
$helper = new FileHelper($this->container);
$this->assertEquals('text', $helper->getPreviewType('test.txt'));
$this->assertEquals('markdown', $helper->getPreviewType('test.markdown'));
- $this->assertEquals('md', $helper->getPreviewType('test.md'));
+ $this->assertEquals('markdown', $helper->getPreviewType('test.md'));
$this->assertEquals(null, $helper->getPreviewType('test.doc'));
}
+
+ public function testGetBrowserViewType()
+ {
+ $fileHelper = new FileHelper($this->container);
+ $this->assertSame('application/pdf', $fileHelper->getBrowserViewType('SomeFile.PDF'));
+ $this->assertSame(null, $fileHelper->getBrowserViewType('SomeFile.doc'));
+ }
}
diff --git a/tests/units/Helper/TaskHelperTest.php b/tests/units/Helper/TaskHelperTest.php
index 2e2da6ee..8609983e 100644
--- a/tests/units/Helper/TaskHelperTest.php
+++ b/tests/units/Helper/TaskHelperTest.php
@@ -9,9 +9,9 @@ class TaskHelperTest extends Base
public function testSelectPriority()
{
$helper = new TaskHelper($this->container);
- $this->assertNotEmpty($helper->selectPriority(array('priority_end' => '1', 'priority_start' => '5', 'priority_default' => '2'), array()));
- $this->assertNotEmpty($helper->selectPriority(array('priority_end' => '3', 'priority_start' => '1', 'priority_default' => '2'), array()));
- $this->assertEmpty($helper->selectPriority(array('priority_end' => '3', 'priority_start' => '3', 'priority_default' => '2'), array()));
+ $this->assertNotEmpty($helper->renderPriorityField(array('priority_end' => '1', 'priority_start' => '5', 'priority_default' => '2'), array()));
+ $this->assertNotEmpty($helper->renderPriorityField(array('priority_end' => '3', 'priority_start' => '1', 'priority_default' => '2'), array()));
+ $this->assertEmpty($helper->renderPriorityField(array('priority_end' => '3', 'priority_start' => '3', 'priority_default' => '2'), array()));
}
public function testFormatPriority()
diff --git a/tests/units/Model/CommentModelTest.php b/tests/units/Model/CommentModelTest.php
index 4178a839..c75401cc 100644
--- a/tests/units/Model/CommentModelTest.php
+++ b/tests/units/Model/CommentModelTest.php
@@ -26,6 +26,7 @@ class CommentModelTest extends Base
$this->assertEquals(1, $comment['user_id']);
$this->assertEquals('admin', $comment['username']);
$this->assertEquals(time(), $comment['date_creation'], '', 3);
+ $this->assertEquals(time(), $comment['date_modification'], '', 3);
$comment = $commentModel->getById(2);
$this->assertNotEmpty($comment);
@@ -34,6 +35,7 @@ class CommentModelTest extends Base
$this->assertEquals(0, $comment['user_id']);
$this->assertEquals('', $comment['username']);
$this->assertEquals(time(), $comment['date_creation'], '', 3);
+ $this->assertEquals(time(), $comment['date_modification'], '', 3);
}
public function testGetAll()
@@ -73,6 +75,7 @@ class CommentModelTest extends Base
$comment = $commentModel->getById(1);
$this->assertNotEmpty($comment);
$this->assertEquals('bla', $comment['comment']);
+ $this->assertEquals(time(), $comment['date_modification'], '', 3);
}
public function testRemove()
diff --git a/tests/units/Model/InviteModelTest.php b/tests/units/Model/InviteModelTest.php
new file mode 100644
index 00000000..3a0519fb
--- /dev/null
+++ b/tests/units/Model/InviteModelTest.php
@@ -0,0 +1,27 @@
+<?php
+
+use Kanboard\Model\InviteModel;
+
+require_once __DIR__.'/../Base.php';
+
+class InviteModelTest extends Base
+{
+ public function testCreation()
+ {
+ $inviteModel = new InviteModel($this->container);
+
+ $this->container['emailClient']
+ ->expects($this->exactly(2))
+ ->method('send');
+
+ $inviteModel->createInvites(array('user@domain1.tld', '', 'user@domain2.tld'), 1);
+ }
+
+ public function testRemove()
+ {
+ $inviteModel = new InviteModel($this->container);
+ $inviteModel->createInvites(array('user@domain1.tld', 'user@domain2.tld'), 0);
+ $this->assertTrue($inviteModel->remove('user@domain1.tld'));
+ $this->assertFalse($inviteModel->remove('foobar'));
+ }
+}
diff --git a/tests/units/ServiceProvider/ClassProviderTest.php b/tests/units/ServiceProvider/ClassProviderTest.php
new file mode 100644
index 00000000..f6528918
--- /dev/null
+++ b/tests/units/ServiceProvider/ClassProviderTest.php
@@ -0,0 +1,21 @@
+<?php
+
+use Kanboard\ServiceProvider\ClassProvider;
+use Pimple\Container;
+
+require_once __DIR__.'/../Base.php';
+
+class ModelProviderTest extends Base
+{
+ public function testServiceInstance()
+ {
+ $container = new Container();
+ $serviceProvider = new ClassProvider($container);
+ $serviceProvider->register($container);
+
+ $instance1 = $container['userModel'];
+ $instance2 = $container['userModel'];
+
+ $this->assertSame($instance1, $instance2);
+ }
+}
diff --git a/tests/units/ServiceProvider/FormatterProviderTest.php b/tests/units/ServiceProvider/FormatterProviderTest.php
new file mode 100644
index 00000000..7984a12b
--- /dev/null
+++ b/tests/units/ServiceProvider/FormatterProviderTest.php
@@ -0,0 +1,21 @@
+<?php
+
+use Kanboard\ServiceProvider\FormatterProvider;
+use Pimple\Container;
+
+require_once __DIR__.'/../Base.php';
+
+class FormatterProviderTest extends Base
+{
+ public function testServiceInstance()
+ {
+ $container = new Container();
+ $serviceProvider = new FormatterProvider($container);
+ $serviceProvider->register($container);
+
+ $instance1 = $container['userAutoCompleteFormatter'];
+ $instance2 = $container['userAutoCompleteFormatter'];
+
+ $this->assertNotSame($instance1, $instance2);
+ }
+}
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 00000000..bfef20bc
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,2413 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abbrev@1:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
+
+align-text@^0.1.1, align-text@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+ dependencies:
+ kind-of "^3.0.2"
+ longest "^1.0.1"
+ repeat-string "^1.5.2"
+
+ansi-escapes@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107"
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+aproba@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0"
+
+archy@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
+
+are-we-there-yet@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.0 || ^1.1.13"
+
+arr-diff@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+ dependencies:
+ arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-differ@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+
+array-find-index@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+
+array-index@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9"
+ dependencies:
+ debug "^2.2.0"
+ es6-symbol "^3.0.2"
+
+array-uniq@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+
+array-unique@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+asn1@~0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+async-foreach@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
+
+async@~0.2.6:
+ version "0.2.10"
+ resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
+
+balanced-match@^0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4"
+ dependencies:
+ tweetnacl "^0.14.3"
+
+beeper@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
+
+block-stream@*:
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+ dependencies:
+ inherits "~2.0.0"
+
+boom@2.x.x:
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+ dependencies:
+ hoek "2.x.x"
+
+bower@^1.3.12, bower@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a"
+
+brace-expansion@^1.0.0:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+ dependencies:
+ balanced-match "^0.4.1"
+ concat-map "0.0.1"
+
+braces@^1.8.2:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+ dependencies:
+ expand-range "^1.8.1"
+ preserve "^0.2.0"
+ repeat-element "^1.1.2"
+
+buffer-shims@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
+
+builtin-modules@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+camelcase-keys@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+ dependencies:
+ camelcase "^2.0.0"
+ map-obj "^1.0.0"
+
+camelcase@^1.0.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^2.0.0, camelcase@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+
+camelcase@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
+
+center-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+ dependencies:
+ align-text "^0.1.3"
+ lazy-cache "^1.0.3"
+
+chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+cli-cursor@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+ dependencies:
+ restore-cursor "^1.0.1"
+
+cli-width@^1.0.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d"
+
+cli@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14"
+ dependencies:
+ exit "0.1.2"
+ glob "^7.1.1"
+
+cliui@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+ dependencies:
+ center-align "^0.1.1"
+ right-align "^0.1.1"
+ wordwrap "0.0.2"
+
+cliui@^3.0.3, cliui@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wrap-ansi "^2.0.0"
+
+clone-buffer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
+
+clone-stats@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+
+clone-stats@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
+
+clone@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f"
+
+clone@^1.0.0, clone@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
+
+cloneable-readable@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117"
+ dependencies:
+ inherits "^2.0.1"
+ process-nextick-args "^1.0.6"
+ through2 "^2.0.1"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@^2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+ dependencies:
+ graceful-readlink ">= 1.0.0"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+concat-with-sourcemaps@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz#f55b3be2aeb47601b10a2d5259ccfb70fd2f1dd6"
+ dependencies:
+ source-map "^0.5.1"
+
+console-browserify@1.1.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+ dependencies:
+ date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+cross-spawn@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
+ dependencies:
+ lru-cache "^4.0.1"
+ which "^1.2.9"
+
+cryptiles@2.x.x:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+ dependencies:
+ boom "2.x.x"
+
+currently-unhandled@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+ dependencies:
+ array-find-index "^1.0.1"
+
+d@^0.1.1, d@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309"
+ dependencies:
+ es5-ext "~0.10.2"
+
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ dependencies:
+ assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+dateformat@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17"
+
+debug@^2.2.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
+ dependencies:
+ ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+defaults@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
+ dependencies:
+ clone "^1.0.2"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+deprecated@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19"
+
+detect-file@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
+ dependencies:
+ fs-exists-sync "^0.1.0"
+
+dom-serializer@0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
+ dependencies:
+ domelementtype "~1.1.1"
+ entities "~1.1.1"
+
+domelementtype@1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
+
+domelementtype@~1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
+
+domhandler@2.3:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738"
+ dependencies:
+ domelementtype "1"
+
+domutils@1.5:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+ dependencies:
+ dom-serializer "0"
+ domelementtype "1"
+
+duplexer2@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
+ dependencies:
+ readable-stream "~1.1.9"
+
+ecc-jsbn@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+ dependencies:
+ jsbn "~0.1.0"
+
+end-of-stream@~0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf"
+ dependencies:
+ once "~1.3.0"
+
+entities@1.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26"
+
+entities@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
+
+error-ex@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9"
+ dependencies:
+ is-arrayish "^0.2.1"
+
+es5-ext@^0.10.7, es5-ext@~0.10.11, es5-ext@~0.10.2:
+ version "0.10.12"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047"
+ dependencies:
+ es6-iterator "2"
+ es6-symbol "~3.1"
+
+es6-iterator@2:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac"
+ dependencies:
+ d "^0.1.1"
+ es5-ext "^0.10.7"
+ es6-symbol "3"
+
+es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
+ dependencies:
+ d "~0.1.1"
+ es5-ext "~0.10.11"
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+exit-hook@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+
+exit@0.1.2, exit@0.1.x:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+ dependencies:
+ is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+ dependencies:
+ fill-range "^2.1.0"
+
+expand-tilde@^1.2.1, expand-tilde@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+ dependencies:
+ os-homedir "^1.0.1"
+
+extend@^3.0.0, extend@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+ dependencies:
+ is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fancy-log@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948"
+ dependencies:
+ chalk "^1.1.1"
+ time-stamp "^1.0.0"
+
+figures@^1.3.5:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+ dependencies:
+ escape-string-regexp "^1.0.5"
+ object-assign "^4.1.0"
+
+filename-regex@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fill-range@^2.1.0:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+ dependencies:
+ is-number "^2.1.0"
+ isobject "^2.0.0"
+ randomatic "^1.1.3"
+ repeat-element "^1.1.2"
+ repeat-string "^1.5.2"
+
+find-index@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
+
+find-up@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+ dependencies:
+ path-exists "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+findup-sync@^0.4.2:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
+ dependencies:
+ detect-file "^0.1.0"
+ is-glob "^2.0.1"
+ micromatch "^2.3.7"
+ resolve-dir "^0.1.0"
+
+findup-sync@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16"
+ dependencies:
+ glob "~5.0.0"
+
+fined@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97"
+ dependencies:
+ expand-tilde "^1.2.1"
+ lodash.assignwith "^4.0.7"
+ lodash.isempty "^4.2.1"
+ lodash.isplainobject "^4.0.4"
+ lodash.isstring "^4.0.1"
+ lodash.pick "^4.2.1"
+ parse-filepath "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+
+flagged-respawn@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
+
+for-in@^0.1.5:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8"
+
+for-own@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072"
+ dependencies:
+ for-in "^0.1.5"
+
+foreachasync@3.x:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6"
+
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.5"
+ mime-types "^2.1.12"
+
+fs-exists-sync@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fstream@^1.0.0, fstream@^1.0.2:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822"
+ dependencies:
+ graceful-fs "^4.1.2"
+ inherits "~2.0.0"
+ mkdirp ">=0.5 0"
+ rimraf "2"
+
+gauge@~2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46"
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-color "^0.1.7"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+gauge@~2.7.1:
+ version "2.7.2"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774"
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ supports-color "^0.2.0"
+ wide-align "^1.1.0"
+
+gaze@^0.5.1:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f"
+ dependencies:
+ globule "~0.1.0"
+
+gaze@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
+ dependencies:
+ globule "^1.0.0"
+
+generate-function@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
+
+generate-object-property@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
+ dependencies:
+ is-property "^1.0.0"
+
+get-caller-file@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+get-stdin@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+
+getpass@^0.1.1:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+ dependencies:
+ assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+ dependencies:
+ glob-parent "^2.0.0"
+ is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+ dependencies:
+ is-glob "^2.0.0"
+
+glob-stream@^3.1.5:
+ version "3.1.18"
+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
+ dependencies:
+ glob "^4.3.1"
+ glob2base "^0.0.12"
+ minimatch "^2.0.1"
+ ordered-read-streams "^0.1.0"
+ through2 "^0.6.1"
+ unique-stream "^1.0.0"
+
+glob-watcher@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
+ dependencies:
+ gaze "^0.5.1"
+
+glob2base@^0.0.12:
+ version "0.0.12"
+ resolved "http://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
+ dependencies:
+ find-index "^0.1.1"
+
+glob@^4.3.1:
+ version "4.5.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f"
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^2.0.1"
+ once "^1.3.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.2"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@~3.1.21:
+ version "3.1.21"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
+ dependencies:
+ graceful-fs "~1.2.0"
+ inherits "1"
+ minimatch "~0.2.11"
+
+glob@~5.0.0:
+ version "5.0.15"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "2 || 3"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-modules@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+ dependencies:
+ global-prefix "^0.1.4"
+ is-windows "^0.2.0"
+
+global-prefix@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+ dependencies:
+ homedir-polyfill "^1.0.0"
+ ini "^1.3.4"
+ is-windows "^0.2.0"
+ which "^1.2.12"
+
+globule@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
+ dependencies:
+ glob "~7.1.1"
+ lodash "~4.16.4"
+ minimatch "~3.0.2"
+
+globule@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5"
+ dependencies:
+ glob "~3.1.21"
+ lodash "~1.0.1"
+ minimatch "~0.2.11"
+
+glogg@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5"
+ dependencies:
+ sparkles "^1.0.0"
+
+graceful-fs@^3.0.0:
+ version "3.0.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
+ dependencies:
+ natives "^1.1.0"
+
+graceful-fs@^4.1.2:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+graceful-fs@~1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
+
+"graceful-readlink@>= 1.0.0":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+
+gulp-bower@^0.0.13:
+ version "0.0.13"
+ resolved "https://registry.yarnpkg.com/gulp-bower/-/gulp-bower-0.0.13.tgz#7ca4e3c5a599d08fada2b1c054cce8cde4e74235"
+ dependencies:
+ bower "^1.3.12"
+ gulp-util "^3.0.1"
+ inquirer "^0.11.2"
+ through2 "0.6.2"
+ walk "2.3.3"
+
+gulp-cli@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-1.2.2.tgz#7392def6316c6e7939a4f296f3f540151ae3a275"
+ dependencies:
+ archy "^1.0.0"
+ chalk "^1.1.0"
+ fancy-log "^1.1.0"
+ gulplog "^1.0.0"
+ interpret "^1.0.0"
+ liftoff "^2.1.0"
+ lodash.isfunction "^3.0.8"
+ lodash.isplainobject "^4.0.4"
+ lodash.isstring "^4.0.1"
+ lodash.sortby "^4.5.0"
+ matchdep "^1.0.0"
+ mute-stdout "^1.0.0"
+ pretty-hrtime "^1.0.0"
+ semver-greatest-satisfied-range "^1.0.0"
+ tildify "^1.0.0"
+ v8flags "^2.0.9"
+ wreck "^6.3.0"
+ yargs "^3.28.0"
+
+gulp-concat@^2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353"
+ dependencies:
+ concat-with-sourcemaps "^1.0.0"
+ through2 "^2.0.0"
+ vinyl "^2.0.0"
+
+gulp-sass@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-sass/-/gulp-sass-3.0.0.tgz#22adde0b2bcc40f9bb38435b49f48cd459e002d3"
+ dependencies:
+ gulp-util "^3.0"
+ lodash.clonedeep "^4.3.2"
+ node-sass "^4.0.0"
+ through2 "^2.0.0"
+ vinyl-sourcemaps-apply "^0.2.0"
+
+gulp-uglify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-2.0.0.tgz#cbe4aae4fe0b6bdd760335bc46f200fff699c4af"
+ dependencies:
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ lodash "^4.13.1"
+ make-error-cause "^1.1.1"
+ through2 "^2.0.0"
+ uglify-js "2.7.0"
+ uglify-save-license "^0.4.1"
+ vinyl-sourcemaps-apply "^0.2.0"
+
+gulp-util@^3.0, gulp-util@^3.0.0, gulp-util@^3.0.1:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
+ dependencies:
+ array-differ "^1.0.0"
+ array-uniq "^1.0.2"
+ beeper "^1.0.0"
+ chalk "^1.0.0"
+ dateformat "^2.0.0"
+ fancy-log "^1.1.0"
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ lodash._reescape "^3.0.0"
+ lodash._reevaluate "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.template "^3.0.0"
+ minimist "^1.1.0"
+ multipipe "^0.1.2"
+ object-assign "^3.0.0"
+ replace-ext "0.0.1"
+ through2 "^2.0.0"
+ vinyl "^0.5.0"
+
+gulp@^3.9.1:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
+ dependencies:
+ archy "^1.0.0"
+ chalk "^1.0.0"
+ deprecated "^0.0.1"
+ gulp-util "^3.0.0"
+ interpret "^1.0.0"
+ liftoff "^2.1.0"
+ minimist "^1.1.0"
+ orchestrator "^0.3.0"
+ pretty-hrtime "^1.0.0"
+ semver "^4.1.0"
+ tildify "^1.0.0"
+ v8flags "^2.0.2"
+ vinyl-fs "^0.3.0"
+
+gulplog@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
+ dependencies:
+ glogg "^1.0.0"
+
+har-validator@~2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
+ dependencies:
+ chalk "^1.1.1"
+ commander "^2.9.0"
+ is-my-json-valid "^2.12.4"
+ pinkie-promise "^2.0.0"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-color@^0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
+
+has-gulplog@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
+ dependencies:
+ sparkles "^1.0.0"
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hawk@~3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+ dependencies:
+ boom "2.x.x"
+ cryptiles "2.x.x"
+ hoek "2.x.x"
+ sntp "1.x.x"
+
+hoek@2.x.x:
+ version "2.16.3"
+ resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+homedir-polyfill@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
+ dependencies:
+ parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b"
+
+htmlparser2@3.8.x:
+ version "3.8.3"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068"
+ dependencies:
+ domelementtype "1"
+ domhandler "2.3"
+ domutils "1.5"
+ entities "1.0"
+ readable-stream "1.1"
+
+http-signature@~1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+ dependencies:
+ assert-plus "^0.2.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+in-publish@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
+
+indent-string@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+ dependencies:
+ repeating "^2.0.0"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+ini@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+inquirer@^0.11.2:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.11.4.tgz#81e3374e8361beaff2d97016206d359d0b32fa4d"
+ dependencies:
+ ansi-escapes "^1.1.0"
+ ansi-regex "^2.0.0"
+ chalk "^1.0.0"
+ cli-cursor "^1.0.1"
+ cli-width "^1.0.1"
+ figures "^1.3.5"
+ lodash "^3.3.1"
+ readline2 "^1.0.1"
+ run-async "^0.1.0"
+ rx-lite "^3.1.2"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.0"
+ through "^2.3.6"
+
+interpret@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-absolute@^0.2.3:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb"
+ dependencies:
+ is-relative "^0.2.1"
+ is-windows "^0.2.0"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-buffer@^1.0.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b"
+
+is-builtin-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+ dependencies:
+ builtin-modules "^1.0.0"
+
+is-dotfile@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+ dependencies:
+ is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+ dependencies:
+ is-extglob "^1.0.0"
+
+is-my-json-valid@^2.12.4:
+ version "2.15.0"
+ resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
+ dependencies:
+ generate-function "^2.0.0"
+ generate-object-property "^1.1.0"
+ jsonpointer "^4.0.0"
+ xtend "^4.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-property@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+
+is-relative@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
+ dependencies:
+ is-unc-path "^0.1.1"
+
+is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-unc-path@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9"
+ dependencies:
+ unc-path-regex "^0.1.0"
+
+is-utf8@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+is-windows@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+
+isarray@1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0"
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ dependencies:
+ isarray "1.0.0"
+
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+jodid25519@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+ dependencies:
+ jsbn "~0.1.0"
+
+jsbn@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"
+
+jshint@^2.9.4:
+ version "2.9.4"
+ resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.9.4.tgz#5e3ba97848d5290273db514aee47fe24cf592934"
+ dependencies:
+ cli "~1.0.0"
+ console-browserify "1.1.x"
+ exit "0.1.x"
+ htmlparser2 "3.8.x"
+ lodash "3.7.x"
+ minimatch "~3.0.2"
+ shelljs "0.3.x"
+ strip-json-comments "1.0.x"
+
+json-schema@0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stringify-safe@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+jsonpointer@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
+
+jsprim@^1.2.2:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252"
+ dependencies:
+ extsprintf "1.0.2"
+ json-schema "0.2.3"
+ verror "1.3.6"
+
+kind-of@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+ dependencies:
+ is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ dependencies:
+ invert-kv "^1.0.0"
+
+liftoff@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385"
+ dependencies:
+ extend "^3.0.0"
+ findup-sync "^0.4.2"
+ fined "^1.0.1"
+ flagged-respawn "^0.3.2"
+ lodash.isplainobject "^4.0.4"
+ lodash.isstring "^4.0.1"
+ lodash.mapvalues "^4.4.0"
+ rechoir "^0.6.2"
+ resolve "^1.1.7"
+
+load-json-file@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ strip-bom "^2.0.0"
+
+lodash._basecopy@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+
+lodash._basetostring@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
+
+lodash._basevalues@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
+
+lodash._getnative@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+
+lodash._isiterateecall@^3.0.0:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+
+lodash._reescape@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
+
+lodash._reevaluate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
+
+lodash._reinterpolate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+
+lodash._root@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
+
+lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
+
+lodash.assignwith@^4.0.7:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb"
+
+lodash.clonedeep@^4.3.2:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+
+lodash.escape@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
+ dependencies:
+ lodash._root "^3.0.0"
+
+lodash.isarguments@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+
+lodash.isarray@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+
+lodash.isempty@^4.2.1:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
+
+lodash.isfunction@^3.0.8:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.8.tgz#4db709fc81bc4a8fd7127a458a5346c5cdce2c6b"
+
+lodash.isplainobject@^4.0.4:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+
+lodash.isstring@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+
+lodash.keys@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+ dependencies:
+ lodash._getnative "^3.0.0"
+ lodash.isarguments "^3.0.0"
+ lodash.isarray "^3.0.0"
+
+lodash.mapvalues@^4.4.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
+
+lodash.mergewith@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
+
+lodash.pick@^4.2.1:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
+
+lodash.restparam@^3.0.0:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
+
+lodash.sortby@^4.5.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+
+lodash.template@^3.0.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
+ dependencies:
+ lodash._basecopy "^3.0.0"
+ lodash._basetostring "^3.0.0"
+ lodash._basevalues "^3.0.0"
+ lodash._isiterateecall "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+ lodash.keys "^3.0.0"
+ lodash.restparam "^3.0.0"
+ lodash.templatesettings "^3.0.0"
+
+lodash.templatesettings@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
+ dependencies:
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+
+lodash@3.7.x, lodash@^3.3.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.7.0.tgz#3678bd8ab995057c07ade836ed2ef087da811d45"
+
+lodash@^4.0.0, lodash@^4.13.1:
+ version "4.17.4"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+lodash@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
+
+lodash@~4.16.4:
+ version "4.16.6"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
+
+longest@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loud-rejection@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+ dependencies:
+ currently-unhandled "^0.4.1"
+ signal-exit "^3.0.0"
+
+lru-cache@2:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
+
+lru-cache@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
+ dependencies:
+ pseudomap "^1.0.1"
+ yallist "^2.0.0"
+
+make-error-cause@^1.1.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d"
+ dependencies:
+ make-error "^1.2.0"
+
+make-error@^1.2.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.2.1.tgz#9a6dfb4844423b9f145806728d05c6e935670e75"
+
+map-cache@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+
+matchdep@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-1.0.1.tgz#a57a33804491fbae208aba8f68380437abc2dca5"
+ dependencies:
+ findup-sync "~0.3.0"
+ micromatch "^2.3.7"
+ resolve "~1.1.6"
+ stack-trace "0.0.9"
+
+meow@^3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+ dependencies:
+ camelcase-keys "^2.0.0"
+ decamelize "^1.1.2"
+ loud-rejection "^1.0.0"
+ map-obj "^1.0.1"
+ minimist "^1.1.3"
+ normalize-package-data "^2.3.4"
+ object-assign "^4.0.1"
+ read-pkg-up "^1.0.1"
+ redent "^1.0.0"
+ trim-newlines "^1.0.0"
+
+micromatch@^2.3.7:
+ version "2.3.11"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+ dependencies:
+ arr-diff "^2.0.0"
+ array-unique "^0.2.1"
+ braces "^1.8.2"
+ expand-brackets "^0.1.4"
+ extglob "^0.3.1"
+ filename-regex "^2.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.1"
+ kind-of "^3.0.2"
+ normalize-path "^2.0.1"
+ object.omit "^2.0.0"
+ parse-glob "^3.0.4"
+ regex-cache "^0.4.2"
+
+mime-db@~1.25.0:
+ version "1.25.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+ version "2.1.13"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88"
+ dependencies:
+ mime-db "~1.25.0"
+
+"minimatch@2 || 3", minimatch@^3.0.2, minimatch@~3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+ dependencies:
+ brace-expansion "^1.0.0"
+
+minimatch@^2.0.1:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"
+ dependencies:
+ brace-expansion "^1.0.0"
+
+minimatch@~0.2.11:
+ version "0.2.14"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
+ dependencies:
+ lru-cache "2"
+ sigmund "~1.0.0"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.0, minimist@^1.1.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+ms@0.7.2:
+ version "0.7.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+multipipe@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
+ dependencies:
+ duplexer2 "0.0.2"
+
+mute-stdout@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.0.tgz#5b32ea07eb43c9ded6130434cf926f46b2a7fd4d"
+
+mute-stream@0.0.5:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
+
+nan@^2.3.2:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8"
+
+natives@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
+
+node-gyp@^3.3.1:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36"
+ dependencies:
+ fstream "^1.0.0"
+ glob "^7.0.3"
+ graceful-fs "^4.1.2"
+ minimatch "^3.0.2"
+ mkdirp "^0.5.0"
+ nopt "2 || 3"
+ npmlog "0 || 1 || 2 || 3"
+ osenv "0"
+ path-array "^1.0.0"
+ request "2"
+ rimraf "2"
+ semver "2.x || 3.x || 4 || 5"
+ tar "^2.0.0"
+ which "1"
+
+node-sass@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.1.1.tgz#dc3e27d25bd827b6276ea243be357c7c7cd07111"
+ dependencies:
+ async-foreach "^0.1.3"
+ chalk "^1.1.1"
+ cross-spawn "^3.0.0"
+ gaze "^1.0.0"
+ get-stdin "^4.0.1"
+ glob "^7.0.3"
+ in-publish "^2.0.0"
+ lodash.assign "^4.2.0"
+ lodash.clonedeep "^4.3.2"
+ lodash.mergewith "^4.6.0"
+ meow "^3.7.0"
+ mkdirp "^0.5.1"
+ nan "^2.3.2"
+ node-gyp "^3.3.1"
+ npmlog "^4.0.0"
+ request "^2.61.0"
+ sass-graph "^2.1.1"
+ stdout-stream "^1.4.0"
+
+"nopt@2 || 3":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
+ dependencies:
+ abbrev "1"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+ version "2.3.5"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df"
+ dependencies:
+ hosted-git-info "^2.1.4"
+ is-builtin-module "^1.0.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a"
+
+"npmlog@0 || 1 || 2 || 3":
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873"
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.6.0"
+ set-blocking "~2.0.0"
+
+npmlog@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f"
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.1"
+ set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+oauth-sign@~0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
+
+object.omit@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+ dependencies:
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
+once@^1.3.0, once@~1.3.0:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
+ dependencies:
+ wrappy "1"
+
+onetime@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+
+orchestrator@^0.3.0:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e"
+ dependencies:
+ end-of-stream "~0.1.5"
+ sequencify "~0.0.7"
+ stream-consume "~0.1.0"
+
+ordered-read-streams@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126"
+
+os-homedir@^1.0.0, os-homedir@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+ dependencies:
+ lcid "^1.0.0"
+
+os-tmpdir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@0:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+parse-filepath@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73"
+ dependencies:
+ is-absolute "^0.2.3"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
+parse-glob@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+ dependencies:
+ glob-base "^0.3.0"
+ is-dotfile "^1.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ dependencies:
+ error-ex "^1.2.0"
+
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+
+path-array@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271"
+ dependencies:
+ array-index "^1.0.0"
+
+path-exists@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+ dependencies:
+ pinkie-promise "^2.0.0"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ dependencies:
+ path-root-regex "^0.1.0"
+
+path-type@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+ dependencies:
+ graceful-fs "^4.1.2"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+pify@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+preserve@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-hrtime@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
+
+process-nextick-args@^1.0.6, process-nextick-args@~1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+pseudomap@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
+
+randomatic@^1.1.3:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+ dependencies:
+ is-number "^2.0.2"
+ kind-of "^3.0.2"
+
+read-pkg-up@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+ dependencies:
+ find-up "^1.0.0"
+ read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+ dependencies:
+ load-json-file "^1.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^1.0.0"
+
+readable-stream@1.1, readable-stream@~1.1.9:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+"readable-stream@>=1.0.28 <1.1.0-0":
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.1.5:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
+ dependencies:
+ buffer-shims "^1.0.0"
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "~1.0.0"
+ process-nextick-args "~1.0.6"
+ string_decoder "~0.10.x"
+ util-deprecate "~1.0.1"
+
+readline2@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ mute-stream "0.0.5"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ dependencies:
+ resolve "^1.1.6"
+
+redent@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+ dependencies:
+ indent-string "^2.1.0"
+ strip-indent "^1.0.1"
+
+regex-cache@^0.4.2:
+ version "0.4.3"
+ resolved "http://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+ dependencies:
+ is-equal-shallow "^0.1.3"
+ is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+ dependencies:
+ is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+
+replace-ext@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+
+request@2, request@^2.61.0:
+ version "2.79.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
+ dependencies:
+ aws-sign2 "~0.6.0"
+ aws4 "^1.2.1"
+ caseless "~0.11.0"
+ combined-stream "~1.0.5"
+ extend "~3.0.0"
+ forever-agent "~0.6.1"
+ form-data "~2.1.1"
+ har-validator "~2.0.6"
+ hawk "~3.1.3"
+ http-signature "~1.1.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.7"
+ oauth-sign "~0.8.1"
+ qs "~6.3.0"
+ stringstream "~0.0.4"
+ tough-cookie "~2.3.0"
+ tunnel-agent "~0.4.1"
+ uuid "^3.0.0"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve-dir@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+ dependencies:
+ expand-tilde "^1.2.2"
+ global-modules "^0.2.3"
+
+resolve@^1.1.6, resolve@^1.1.7:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c"
+
+resolve@~1.1.6:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+restore-cursor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+ dependencies:
+ exit-hook "^1.0.0"
+ onetime "^1.0.0"
+
+right-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+ dependencies:
+ align-text "^0.1.1"
+
+rimraf@2:
+ version "2.5.4"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
+ dependencies:
+ glob "^7.0.5"
+
+run-async@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
+ dependencies:
+ once "^1.3.0"
+
+rx-lite@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
+
+sass-graph@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b"
+ dependencies:
+ glob "^7.0.0"
+ lodash "^4.0.0"
+ yargs "^4.7.1"
+
+semver-greatest-satisfied-range@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.0.0.tgz#4fb441e2a8d26c40b598327557318de272a558a0"
+ dependencies:
+ semver "^4.2.0"
+ semver-regex "^1.0.0"
+
+semver-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9"
+
+"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^4.1.0, semver@^4.2.0:
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
+
+sequencify@~0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+shelljs@0.3.x:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1"
+
+sigmund@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+
+signal-exit@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+sntp@1.x.x:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+ dependencies:
+ hoek "2.x.x"
+
+source-map@^0.5.1, source-map@~0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+sparkles@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
+
+spdx-correct@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+ dependencies:
+ spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sshpk@^1.7.0:
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0"
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ dashdash "^1.12.0"
+ getpass "^0.1.1"
+ optionalDependencies:
+ bcrypt-pbkdf "^1.0.0"
+ ecc-jsbn "~0.1.1"
+ jodid25519 "^1.0.0"
+ jsbn "~0.1.0"
+ tweetnacl "~0.14.0"
+
+stack-trace@0.0.9:
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695"
+
+stdout-stream@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b"
+ dependencies:
+ readable-stream "^2.0.1"
+
+stream-consume@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
+
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+stringstream@~0.0.4:
+ version "0.0.5"
+ resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-bom@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794"
+ dependencies:
+ first-chunk-stream "^1.0.0"
+ is-utf8 "^0.2.0"
+
+strip-bom@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+ dependencies:
+ is-utf8 "^0.2.0"
+
+strip-indent@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+ dependencies:
+ get-stdin "^4.0.1"
+
+strip-json-comments@1.0.x:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
+
+supports-color@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a"
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+tar@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+ dependencies:
+ block-stream "*"
+ fstream "^1.0.2"
+ inherits "2"
+
+textarea-caret@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/textarea-caret/-/textarea-caret-3.0.2.tgz#f360c48699aa1abf718680a43a31a850665c2caf"
+
+through2@0.6.2, through2@^0.6.1:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.2.tgz#53265824c555e7fcdc4111dcdc52c7de64636c75"
+ dependencies:
+ readable-stream ">=1.0.28 <1.1.0-0"
+ xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0, through2@^2.0.1:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+
+tildify@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a"
+ dependencies:
+ os-homedir "^1.0.0"
+
+time-stamp@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.0.1.tgz#9f4bd23559c9365966f3302dbba2b07c6b99b151"
+
+tough-cookie@~2.3.0:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+ dependencies:
+ punycode "^1.4.1"
+
+trim-newlines@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+
+tunnel-agent@~0.4.1:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+uglify-js@2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.0.tgz#f021e38ba2ca740860f5bd5c695c2a817345f0ec"
+ dependencies:
+ async "~0.2.6"
+ source-map "~0.5.1"
+ uglify-to-browserify "~1.0.0"
+ yargs "~3.10.0"
+
+uglify-save-license@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/uglify-save-license/-/uglify-save-license-0.4.1.tgz#95726c17cc6fd171c3617e3bf4d8d82aa8c4cce1"
+
+uglify-to-browserify@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+unc-path-regex@^0.1.0:
+ version "0.1.2"
+ resolved "http://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+
+unique-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
+
+user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+uuid@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+v8flags@^2.0.2, v8flags@^2.0.9:
+ version "2.0.11"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
+ dependencies:
+ user-home "^1.1.1"
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+ dependencies:
+ spdx-correct "~1.0.0"
+ spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+ dependencies:
+ extsprintf "1.0.2"
+
+vinyl-fs@^0.3.0:
+ version "0.3.14"
+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6"
+ dependencies:
+ defaults "^1.0.0"
+ glob-stream "^3.1.5"
+ glob-watcher "^0.0.6"
+ graceful-fs "^3.0.0"
+ mkdirp "^0.5.0"
+ strip-bom "^1.0.0"
+ through2 "^0.6.1"
+ vinyl "^0.4.0"
+
+vinyl-sourcemaps-apply@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705"
+ dependencies:
+ source-map "^0.5.1"
+
+vinyl@^0.4.0:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847"
+ dependencies:
+ clone "^0.2.0"
+ clone-stats "^0.0.1"
+
+vinyl@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
+ dependencies:
+ clone "^1.0.0"
+ clone-stats "^0.0.1"
+ replace-ext "0.0.1"
+
+vinyl@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.1.tgz#1c3b4931e7ac4c1efee743f3b91a74c094407bb6"
+ dependencies:
+ clone "^1.0.0"
+ clone-buffer "^1.0.0"
+ clone-stats "^1.0.0"
+ cloneable-readable "^1.0.0"
+ is-stream "^1.1.0"
+ remove-trailing-separator "^1.0.1"
+ replace-ext "^1.0.0"
+
+walk@2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.3.tgz#b4c0e8c42464c16dbbe1d71666765eac07819e5f"
+ dependencies:
+ foreachasync "3.x"
+
+which-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@1, which@^1.2.12, which@^1.2.9:
+ version "1.2.12"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192"
+ dependencies:
+ isexe "^1.1.1"
+
+wide-align@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
+ dependencies:
+ string-width "^1.0.1"
+
+window-size@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+window-size@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
+
+window-size@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
+
+wordwrap@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+wreck@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/wreck/-/wreck-6.3.0.tgz#a1369769f07bbb62d6a378336a7871fc773c740b"
+ dependencies:
+ boom "2.x.x"
+ hoek "2.x.x"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.0, y18n@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yallist@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4"
+
+yargs-parser@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4"
+ dependencies:
+ camelcase "^3.0.0"
+ lodash.assign "^4.0.6"
+
+yargs@^3.28.0:
+ version "3.32.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
+ dependencies:
+ camelcase "^2.0.1"
+ cliui "^3.0.3"
+ decamelize "^1.1.1"
+ os-locale "^1.4.0"
+ string-width "^1.0.1"
+ window-size "^0.1.4"
+ y18n "^3.2.0"
+
+yargs@^4.7.1:
+ version "4.8.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0"
+ dependencies:
+ cliui "^3.2.0"
+ decamelize "^1.1.1"
+ get-caller-file "^1.0.1"
+ lodash.assign "^4.0.3"
+ os-locale "^1.4.0"
+ read-pkg-up "^1.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^1.0.1"
+ which-module "^1.0.0"
+ window-size "^0.2.0"
+ y18n "^3.2.1"
+ yargs-parser "^2.4.1"
+
+yargs@~3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+ dependencies:
+ camelcase "^1.0.2"
+ cliui "^2.1.0"
+ decamelize "^1.0.0"
+ window-size "0.1.0"