diff options
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r-- | app/assets/javascripts/abuse_reports.js (renamed from app/assets/javascripts/abuse_reports.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/activities.js (renamed from app/assets/javascripts/activities.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/awards_handler.js | 876 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/bind_in_out.js | 47 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/gl_emoji.js | 217 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/gl_emoji/spread_string.js | 50 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js | 154 | ||||
-rw-r--r-- | app/assets/javascripts/behaviors/toggler_behavior.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/blob/blob_ci_yaml.js (renamed from app/assets/javascripts/blob/blob_ci_yaml.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/blob/blob_dockerfile_selector.js (renamed from app/assets/javascripts/blob/blob_dockerfile_selector.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/blob/blob_dockerfile_selectors.js (renamed from app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/blob/blob_license_selectors.js (renamed from app/assets/javascripts/blob/blob_license_selectors.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/blob/template_selector.js (renamed from app/assets/javascripts/blob/template_selector.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/boards_bundle.js (renamed from app/assets/javascripts/boards/boards_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/board.js (renamed from app/assets/javascripts/boards/components/board.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/board_blank_state.js (renamed from app/assets/javascripts/boards/components/board_blank_state.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/board_delete.js (renamed from app/assets/javascripts/boards/components/board_delete.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/board_list.js (renamed from app/assets/javascripts/boards/components/board_list.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/board_sidebar.js (renamed from app/assets/javascripts/boards/components/board_sidebar.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/issue_card_inner.js (renamed from app/assets/javascripts/boards/components/issue_card_inner.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/empty_state.js (renamed from app/assets/javascripts/boards/components/modal/empty_state.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/filters.js (renamed from app/assets/javascripts/boards/components/modal/filters.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/filters/label.js (renamed from app/assets/javascripts/boards/components/modal/filters/label.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/filters/milestone.js (renamed from app/assets/javascripts/boards/components/modal/filters/milestone.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/filters/user.js (renamed from app/assets/javascripts/boards/components/modal/filters/user.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/footer.js (renamed from app/assets/javascripts/boards/components/modal/footer.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/header.js (renamed from app/assets/javascripts/boards/components/modal/header.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/index.js (renamed from app/assets/javascripts/boards/components/modal/index.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/list.js (renamed from app/assets/javascripts/boards/components/modal/list.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/lists_dropdown.js (renamed from app/assets/javascripts/boards/components/modal/lists_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/modal/tabs.js (renamed from app/assets/javascripts/boards/components/modal/tabs.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/new_list_dropdown.js (renamed from app/assets/javascripts/boards/components/new_list_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/components/sidebar/remove_issue.js (renamed from app/assets/javascripts/boards/components/sidebar/remove_issue.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/filters/due_date_filters.js (renamed from app/assets/javascripts/boards/filters/due_date_filters.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/mixins/modal_mixins.js (renamed from app/assets/javascripts/boards/mixins/modal_mixins.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/mixins/sortable_default_options.js (renamed from app/assets/javascripts/boards/mixins/sortable_default_options.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/models/issue.js (renamed from app/assets/javascripts/boards/models/issue.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/models/label.js (renamed from app/assets/javascripts/boards/models/label.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/models/list.js (renamed from app/assets/javascripts/boards/models/list.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/models/milestone.js (renamed from app/assets/javascripts/boards/models/milestone.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/models/user.js (renamed from app/assets/javascripts/boards/models/user.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/services/board_service.js (renamed from app/assets/javascripts/boards/services/board_service.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/stores/boards_store.js (renamed from app/assets/javascripts/boards/stores/boards_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/boards/stores/modal_store.js (renamed from app/assets/javascripts/boards/stores/modal_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/build_variables.js (renamed from app/assets/javascripts/build_variables.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/ci_lint_editor.js (renamed from app/assets/javascripts/ci_lint_editor.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_bundle.js (renamed from app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_service.js (renamed from app/assets/javascripts/commit/pipelines/pipelines_service.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_store.js (renamed from app/assets/javascripts/commit/pipelines/pipelines_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/commit/pipelines/pipelines_table.js (renamed from app/assets/javascripts/commit/pipelines/pipelines_table.js.es6) | 10 | ||||
-rw-r--r-- | app/assets/javascripts/commons/bootstrap.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/commons/index.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/commons/jquery.js | 11 | ||||
-rw-r--r-- | app/assets/javascripts/compare_autocomplete.js (renamed from app/assets/javascripts/compare_autocomplete.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/copy_as_gfm.js (renamed from app/assets/javascripts/copy_as_gfm.js.es6) | 5 | ||||
-rw-r--r-- | app/assets/javascripts/create_label.js (renamed from app/assets/javascripts/create_label.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_code_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_code_component.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_issue_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_issue_component.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_plan_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_plan_component.js.es6) | 10 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_production_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_production_component.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_review_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_review_component.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_staging_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_staging_component.js.es6) | 8 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/stage_test_component.js (renamed from app/assets/javascripts/cycle_analytics/components/stage_test_component.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/components/total_time_component.js (renamed from app/assets/javascripts/cycle_analytics/components/total_time_component.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js (renamed from app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6) | 3 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/cycle_analytics_service.js (renamed from app/assets/javascripts/cycle_analytics/cycle_analytics_service.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/cycle_analytics_store.js (renamed from app/assets/javascripts/cycle_analytics/cycle_analytics_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/default_event_objects.js (renamed from app/assets/javascripts/cycle_analytics/default_event_objects.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_branch.js.es6 | 7 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_branch.svg | 1 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_build_status.js.es6 | 7 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg | 1 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_commit.js.es6 | 7 | ||||
-rw-r--r-- | app/assets/javascripts/cycle_analytics/svg/icon_commit.svg | 1 | ||||
-rw-r--r-- | app/assets/javascripts/diff.js (renamed from app/assets/javascripts/diff.js.es6) | 10 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/components/comment_resolve_btn.js (renamed from app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/components/jump_to_discussion.js (renamed from app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/components/resolve_btn.js (renamed from app/assets/javascripts/diff_notes/components/resolve_btn.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/components/resolve_count.js (renamed from app/assets/javascripts/diff_notes/components/resolve_count.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js (renamed from app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/diff_notes_bundle.js (renamed from app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/mixins/discussion.js (renamed from app/assets/javascripts/diff_notes/mixins/discussion.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/models/discussion.js (renamed from app/assets/javascripts/diff_notes/models/discussion.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/models/note.js (renamed from app/assets/javascripts/diff_notes/models/note.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/services/resolve.js (renamed from app/assets/javascripts/diff_notes/services/resolve.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/diff_notes/stores/comments.js (renamed from app/assets/javascripts/diff_notes/stores/comments.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/dispatcher.js (renamed from app/assets/javascripts/dispatcher.js.es6) | 21 | ||||
-rw-r--r-- | app/assets/javascripts/due_date_select.js (renamed from app/assets/javascripts/due_date_select.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment.js (renamed from app/assets/javascripts/environments/components/environment.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_actions.js (renamed from app/assets/javascripts/environments/components/environment_actions.js.es6) | 12 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_external_url.js (renamed from app/assets/javascripts/environments/components/environment_external_url.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_item.js (renamed from app/assets/javascripts/environments/components/environment_item.js.es6) | 36 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_rollback.js (renamed from app/assets/javascripts/environments/components/environment_rollback.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_stop.js (renamed from app/assets/javascripts/environments/components/environment_stop.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environment_terminal_button.js (renamed from app/assets/javascripts/environments/components/environment_terminal_button.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/environments/components/environments_table.js (renamed from app/assets/javascripts/environments/components/environments_table.js.es6) | 20 | ||||
-rw-r--r-- | app/assets/javascripts/environments/environments_bundle.js (renamed from app/assets/javascripts/environments/environments_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/folder/environments_folder_bundle.js (renamed from app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/environments/folder/environments_folder_view.js (renamed from app/assets/javascripts/environments/folder/environments_folder_view.js.es6) | 2 | ||||
-rw-r--r-- | app/assets/javascripts/environments/services/environments_service.js (renamed from app/assets/javascripts/environments/services/environments_service.js.es6) | 2 | ||||
-rw-r--r-- | app/assets/javascripts/environments/stores/environments_store.js (renamed from app/assets/javascripts/environments/stores/environments_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/extensions/array.js (renamed from app/assets/javascripts/extensions/array.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/extensions/custom_event.js (renamed from app/assets/javascripts/extensions/custom_event.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/extensions/element.js (renamed from app/assets/javascripts/extensions/element.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/extensions/object.js (renamed from app/assets/javascripts/extensions/object.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/extensions/string.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/filterable_list.js | 45 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/dropdown_hint.js (renamed from app/assets/javascripts/filtered_search/dropdown_hint.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/dropdown_non_user.js (renamed from app/assets/javascripts/filtered_search/dropdown_non_user.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/dropdown_user.js (renamed from app/assets/javascripts/filtered_search/dropdown_user.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/dropdown_utils.js (renamed from app/assets/javascripts/filtered_search/dropdown_utils.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/filtered_search_dropdown.js (renamed from app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js (renamed from app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/filtered_search_manager.js (renamed from app/assets/javascripts/filtered_search/filtered_search_manager.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/filtered_search_token_keys.js (renamed from app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/filtered_search/filtered_search_tokenizer.js (renamed from app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/gfm_auto_complete.js (renamed from app/assets/javascripts/gfm_auto_complete.js.es6) | 17 | ||||
-rw-r--r-- | app/assets/javascripts/gl_field_error.js (renamed from app/assets/javascripts/gl_field_error.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/gl_field_errors.js (renamed from app/assets/javascripts/gl_field_errors.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/gl_form.js (renamed from app/assets/javascripts/gl_form.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/graphs/graphs_bundle.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/group_label_subscription.js (renamed from app/assets/javascripts/group_label_subscription.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/groups_list.js | 45 | ||||
-rw-r--r-- | app/assets/javascripts/issuable.js (renamed from app/assets/javascripts/issuable.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/issuable_bundle.js (renamed from app/assets/javascripts/issuable/issuable_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js (renamed from app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6) | 5 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js (renamed from app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js (renamed from app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/help_state.js (renamed from app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js (renamed from app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js (renamed from app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/components/time_tracker.js (renamed from app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6) | 4 | ||||
-rw-r--r-- | app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js (renamed from app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6) | 2 | ||||
-rw-r--r-- | app/assets/javascripts/issues_bulk_assignment.js (renamed from app/assets/javascripts/issues_bulk_assignment.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/label_manager.js (renamed from app/assets/javascripts/label_manager.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/lib/chart.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/lib/cropper.js | 7 | ||||
-rw-r--r-- | app/assets/javascripts/lib/d3.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/lib/raphael.js | 9 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js (renamed from app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/common_utils.js (renamed from app/assets/javascripts/lib/utils/common_utils.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/datetime_utility.js (renamed from app/assets/javascripts/lib/utils/datetime_utility.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/pretty_time.js (renamed from app/assets/javascripts/lib/utils/pretty_time.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/text_utility.js | 18 | ||||
-rw-r--r-- | app/assets/javascripts/lib/utils/url_utility.js (renamed from app/assets/javascripts/lib/utils/url_utility.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/lib/vue_resource.js.es6 | 2 | ||||
-rw-r--r-- | app/assets/javascripts/main.js (renamed from app/assets/javascripts/application.js) | 73 | ||||
-rw-r--r-- | app/assets/javascripts/member_expiration_date.js (renamed from app/assets/javascripts/member_expiration_date.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/members.js (renamed from app/assets/javascripts/members.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/components/diff_file_editor.js (renamed from app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js (renamed from app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js (renamed from app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/merge_conflict_service.js (renamed from app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/merge_conflict_store.js (renamed from app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js (renamed from app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js (renamed from app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js (renamed from app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_request_tabs.js (renamed from app/assets/javascripts/merge_request_tabs.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/merge_request_widget.js (renamed from app/assets/javascripts/merge_request_widget.js.es6) | 46 | ||||
-rw-r--r-- | app/assets/javascripts/merge_request_widget/ci_bundle.js (renamed from app/assets/javascripts/merge_request_widget/ci_bundle.js.es6) | 10 | ||||
-rw-r--r-- | app/assets/javascripts/mini_pipeline_graph_dropdown.js (renamed from app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/network/branch_graph.js | 703 | ||||
-rw-r--r-- | app/assets/javascripts/network/network.js | 33 | ||||
-rw-r--r-- | app/assets/javascripts/network/network_bundle.js | 26 | ||||
-rw-r--r-- | app/assets/javascripts/network/raphael.js | 74 | ||||
-rw-r--r-- | app/assets/javascripts/notes.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/pager.js (renamed from app/assets/javascripts/pager.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/pipelines.js (renamed from app/assets/javascripts/pipelines.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/profile/gl_crop.js (renamed from app/assets/javascripts/profile/gl_crop.js.es6) | 2 | ||||
-rw-r--r-- | app/assets/javascripts/profile/profile.js (renamed from app/assets/javascripts/profile/profile.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/project_label_subscription.js (renamed from app/assets/javascripts/project_label_subscription.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/project_variables.js (renamed from app/assets/javascripts/project_variables.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/projects_list.js | 64 | ||||
-rw-r--r-- | app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js (renamed from app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/protected_branches/protected_branch_create.js (renamed from app/assets/javascripts/protected_branches/protected_branch_create.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/protected_branches/protected_branch_dropdown.js (renamed from app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/protected_branches/protected_branch_edit.js (renamed from app/assets/javascripts/protected_branches/protected_branch_edit.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/protected_branches/protected_branch_edit_list.js (renamed from app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/search_autocomplete.js (renamed from app/assets/javascripts/search_autocomplete.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/shortcuts_blob.js (renamed from app/assets/javascripts/shortcuts_blob.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/shortcuts_navigation.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/signin_tabs_memoizer.js (renamed from app/assets/javascripts/signin_tabs_memoizer.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/smart_interval.js (renamed from app/assets/javascripts/smart_interval.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/snippets_list.js (renamed from app/assets/javascripts/snippets_list.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/subbable_resource.js (renamed from app/assets/javascripts/subbable_resource.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/subscription.js (renamed from app/assets/javascripts/subscription.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/templates/issuable_template_selector.js (renamed from app/assets/javascripts/templates/issuable_template_selector.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/templates/issuable_template_selectors.js (renamed from app/assets/javascripts/templates/issuable_template_selectors.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/terminal/terminal.js (renamed from app/assets/javascripts/terminal/terminal.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/terminal/terminal_bundle.js (renamed from app/assets/javascripts/terminal/terminal_bundle.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/todos.js (renamed from app/assets/javascripts/todos.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/u2f/authenticate.js (renamed from app/assets/javascripts/u2f/authenticate.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/user.js (renamed from app/assets/javascripts/user.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/user_callout.js | 4 | ||||
-rw-r--r-- | app/assets/javascripts/user_tabs.js (renamed from app/assets/javascripts/user_tabs.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/username_validator.js (renamed from app/assets/javascripts/username_validator.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/users/calendar.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/users_select.js | 23 | ||||
-rw-r--r-- | app/assets/javascripts/version_check_image.js (renamed from app/assets/javascripts/version_check_image.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/visibility_select.js (renamed from app/assets/javascripts/visibility_select.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/index.js (renamed from app/assets/javascripts/vue_pipelines_index/index.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/pipeline_actions.js (renamed from app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6) | 16 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/pipeline_url.js (renamed from app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/pipelines.js (renamed from app/assets/javascripts/vue_pipelines_index/pipelines.js.es6) | 7 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/stage.js (renamed from app/assets/javascripts/vue_pipelines_index/stage.js.es6) | 42 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/status.js | 64 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/status.js.es6 | 34 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/store.js (renamed from app/assets/javascripts/vue_pipelines_index/store.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/vue_pipelines_index/time_ago.js (renamed from app/assets/javascripts/vue_pipelines_index/time_ago.js.es6) | 7 | ||||
-rw-r--r-- | app/assets/javascripts/vue_realtime_listener/index.js (renamed from app/assets/javascripts/vue_realtime_listener/index.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/commit.js (renamed from app/assets/javascripts/vue_shared/components/commit.js.es6) | 10 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/pipelines_table.js (renamed from app/assets/javascripts/vue_shared/components/pipelines_table.js.es6) | 11 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/pipelines_table_row.js (renamed from app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6) | 45 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/table_pagination.js (renamed from app/assets/javascripts/vue_shared/components/table_pagination.js.es6) | 1 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/vue_resource_interceptor.js (renamed from app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6) | 0 | ||||
-rw-r--r-- | app/assets/javascripts/wikis.js (renamed from app/assets/javascripts/wikis.js.es6) | 0 |
216 files changed, 1813 insertions, 1241 deletions
diff --git a/app/assets/javascripts/abuse_reports.js.es6 b/app/assets/javascripts/abuse_reports.js index 8a260aae1b1..8a260aae1b1 100644 --- a/app/assets/javascripts/abuse_reports.js.es6 +++ b/app/assets/javascripts/abuse_reports.js diff --git a/app/assets/javascripts/activities.js.es6 b/app/assets/javascripts/activities.js index 648cb4d5d85..648cb4d5d85 100644 --- a/app/assets/javascripts/activities.js.es6 +++ b/app/assets/javascripts/activities.js diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index a4ccb30e447..4667980a960 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -1,380 +1,518 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, brace-style, no-underscore-dangle, no-return-assign, camelcase */ /* global Cookies */ -var emojiAliases = require('emoji-aliases'); - -(function() { - this.AwardsHandler = (function() { - var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence - function AwardsHandler() { - this.aliases = emojiAliases; - $(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) { - return function(e) { - e.stopPropagation(); - e.preventDefault(); - return _this.showEmojiMenu($(e.currentTarget)); - }; - })(this)); - $('html').on('click', function(e) { - var $target; - $target = $(e.target); - if (!$target.closest('.emoji-menu-content').length) { - $('.js-awards-block.current').removeClass('current'); - } - if (!$target.closest('.emoji-menu').length) { - if ($('.emoji-menu').is(':visible')) { - $('.js-add-award.is-active').removeClass('is-active'); - return $('.emoji-menu').removeClass('is-visible'); - } - } - }); - $(document).off('click', '.js-emoji-btn').on('click', '.js-emoji-btn', (function(_this) { - return function(e) { - var $target, emoji; - e.preventDefault(); - $target = $(e.currentTarget); - emoji = $target.find('.icon').data('emoji'); - $target.closest('.js-awards-block').addClass('current'); - return _this.addAward(_this.getVotesBlock(), _this.getAwardUrl(), emoji); - }; - })(this)); +const emojiMap = require('emoji-map'); +const emojiAliases = require('emoji-aliases'); +const glEmoji = require('./behaviors/gl_emoji'); + +const glEmojiTag = glEmoji.glEmojiTag; + +const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; +const requestAnimationFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.setTimeout; + +const FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence + +let categoryMap = null; + +const categoryLabelMap = { + activity: 'Activity', + people: 'People', + nature: 'Nature', + food: 'Food', + travel: 'Travel', + objects: 'Objects', + symbols: 'Symbols', + flags: 'Flags', +}; + +function buildCategoryMap() { + return Object.keys(emojiMap).reduce((currentCategoryMap, emojiNameKey) => { + const emojiInfo = emojiMap[emojiNameKey]; + if (currentCategoryMap[emojiInfo.category]) { + currentCategoryMap[emojiInfo.category].push(emojiNameKey); } - AwardsHandler.prototype.showEmojiMenu = function($addBtn) { - var $holder, $menu, url; - $menu = $('.emoji-menu'); - if ($addBtn.hasClass('js-note-emoji')) { - $addBtn.closest('.note').find('.js-awards-block').addClass('current'); - } else { - $addBtn.closest('.js-awards-block').addClass('current'); - } - if ($menu.length) { - $holder = $addBtn.closest('.js-award-holder'); - if ($menu.is('.is-visible')) { - $addBtn.removeClass('is-active'); - $menu.removeClass('is-visible'); - return $('#emoji_search').blur(); - } else { - $addBtn.addClass('is-active'); - this.positionMenu($menu, $addBtn); - $menu.addClass('is-visible'); - return $('#emoji_search').focus(); - } - } else { - $addBtn.addClass('is-loading is-active'); - url = this.getAwardMenuUrl(); - return this.createEmojiMenu(url, (function(_this) { - return function() { - $addBtn.removeClass('is-loading'); - $menu = $('.emoji-menu'); - _this.positionMenu($menu, $addBtn); - if (!_this.frequentEmojiBlockRendered) { - _this.renderFrequentlyUsedBlock(); - } - return setTimeout(function() { - $menu.addClass('is-visible'); - $('#emoji_search').focus(); - return _this.setupSearch(); - }, 200); - }; - })(this)); - } - }; - - AwardsHandler.prototype.createEmojiMenu = function(awardMenuUrl, callback) { - return $.get(awardMenuUrl, function(response) { - $('body').append(response); - return callback(); + return currentCategoryMap; + }, { + activity: [], + people: [], + nature: [], + food: [], + travel: [], + objects: [], + symbols: [], + flags: [], + }); +} + +function renderCategory(name, emojiList) { + return ` + <h5 class="emoji-menu-title"> + ${name} + </h5> + <ul class="clearfix emoji-menu-list"> + ${emojiList.map(emojiName => ` + <li class="emoji-menu-list-item"> + <button class="emoji-menu-btn text-center js-emoji-btn" type="button"> + ${glEmojiTag(emojiName, { + sprite: true, + })} + </button> + </li> + `).join('\n')} + </ul> + `; +} + +function AwardsHandler() { + this.eventListeners = []; + this.aliases = emojiAliases; + // If the user shows intent let's pre-build the menu + this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => { + const $menu = $('.emoji-menu'); + if ($menu.length === 0) { + requestAnimationFrame(() => { + this.createEmojiMenu(); }); - }; - - AwardsHandler.prototype.positionMenu = function($menu, $addBtn) { - var css, position; - position = $addBtn.data('position'); - // The menu could potentially be off-screen or in a hidden overflow element - // So we position the element absolute in the body - css = { - top: ($addBtn.offset().top + $addBtn.outerHeight()) + "px" - }; - if (position === 'right') { - css.left = (($addBtn.offset().left - $menu.outerWidth()) + 20) + "px"; - $menu.addClass('is-aligned-right'); - } else { - css.left = ($addBtn.offset().left) + "px"; - $menu.removeClass('is-aligned-right'); - } - return $menu.css(css); - }; - - AwardsHandler.prototype.addAward = function(votesBlock, awardUrl, emoji, checkMutuality, callback) { - if (checkMutuality == null) { - checkMutuality = true; - } - emoji = this.normilizeEmojiName(emoji); - this.postEmoji(awardUrl, emoji, (function(_this) { - return function() { - _this.addAwardToEmojiBar(votesBlock, emoji, checkMutuality); - return typeof callback === "function" ? callback() : void 0; - }; - })(this)); - return $('.emoji-menu').removeClass('is-visible'); - }; - - AwardsHandler.prototype.addAwardToEmojiBar = function(votesBlock, emoji, checkForMutuality) { - var $emojiButton, counter; - if (checkForMutuality == null) { - checkForMutuality = true; - } - if (checkForMutuality) { - this.checkMutuality(votesBlock, emoji); - } - this.addEmojiToFrequentlyUsedList(emoji); - emoji = this.normilizeEmojiName(emoji); - $emojiButton = this.findEmojiIcon(votesBlock, emoji).parent(); - if ($emojiButton.length > 0) { - if (this.isActive($emojiButton)) { - return this.decrementCounter($emojiButton, emoji); - } else { - counter = $emojiButton.find('.js-counter'); - counter.text(parseInt(counter.text(), 10) + 1); - $emojiButton.addClass('active'); - this.addYouToUserList(votesBlock, emoji); - return this.animateEmoji($emojiButton); - } - } else { - votesBlock.removeClass('hidden'); - return this.createEmoji(votesBlock, emoji); - } - }; - - AwardsHandler.prototype.getVotesBlock = function() { - var currentBlock; - currentBlock = $('.js-awards-block.current'); - if (currentBlock.length) { - return currentBlock; - } else { - return $('.js-awards-block').eq(0); - } - }; - - AwardsHandler.prototype.getAwardUrl = function() { - return this.getVotesBlock().data('award-url'); - }; - - AwardsHandler.prototype.checkMutuality = function(votesBlock, emoji) { - var $emojiButton, awardUrl, isAlreadyVoted, mutualVote; - awardUrl = this.getAwardUrl(); - if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; - $emojiButton = votesBlock.find("[data-emoji=" + mutualVote + "]").parent(); - isAlreadyVoted = $emojiButton.hasClass('active'); - if (isAlreadyVoted) { - this.addAward(votesBlock, awardUrl, mutualVote, false); - } - } - }; - - AwardsHandler.prototype.isActive = function($emojiButton) { - return $emojiButton.hasClass('active'); - }; - - AwardsHandler.prototype.decrementCounter = function($emojiButton, emoji) { - var counter, counterNumber; - counter = $('.js-counter', $emojiButton); - counterNumber = parseInt(counter.text(), 10); - if (counterNumber > 1) { - counter.text(counterNumber - 1); - this.removeYouFromUserList($emojiButton, emoji); - } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { - $emojiButton.tooltip('destroy'); - counter.text('0'); - this.removeYouFromUserList($emojiButton, emoji); - if ($emojiButton.parents('.note').length) { - this.removeEmoji($emojiButton); - } - } else { - this.removeEmoji($emojiButton); - } - return $emojiButton.removeClass('active'); - }; - - AwardsHandler.prototype.removeEmoji = function($emojiButton) { - var $votesBlock; - $emojiButton.tooltip('destroy'); - $emojiButton.remove(); - $votesBlock = this.getVotesBlock(); - if ($votesBlock.find('.js-emoji-btn').length === 0) { - return $votesBlock.addClass('hidden'); - } - }; - - AwardsHandler.prototype.getAwardTooltip = function($awardBlock) { - return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; - }; - - AwardsHandler.prototype.toSentence = function(list) { - if (list.length <= 2) { - return list.join(' and '); + } + // Prebuild the categoryMap + categoryMap = categoryMap || buildCategoryMap(); + }); + this.registerEventListener('on', $(document), 'click', '.js-add-award', (e) => { + e.stopPropagation(); + e.preventDefault(); + this.showEmojiMenu($(e.currentTarget)); + }); + + this.registerEventListener('on', $('html'), 'click', (e) => { + const $target = $(e.target); + if (!$target.closest('.emoji-menu-content').length) { + $('.js-awards-block.current').removeClass('current'); + } + if (!$target.closest('.emoji-menu').length) { + if ($('.emoji-menu').is(':visible')) { + $('.js-add-award.is-active').removeClass('is-active'); + $('.emoji-menu').removeClass('is-visible'); } - else { - return list.slice(0, -1).join(', ') + ', and ' + list[list.length - 1]; + } + }); + this.registerEventListener('on', $(document), 'click', '.js-emoji-btn', (e) => { + e.preventDefault(); + const $target = $(e.currentTarget); + const $glEmojiElement = $target.find('gl-emoji'); + const $spriteIconElement = $target.find('.icon'); + const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name'); + $target.closest('.js-awards-block').addClass('current'); + return this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji); + }); +} + +AwardsHandler.prototype.registerEventListener = function registerEventListener(method = 'on', element, ...args) { + element[method].call(element, ...args); + this.eventListeners.push({ + element, + args, + }); +}; + +AwardsHandler.prototype.showEmojiMenu = function showEmojiMenu($addBtn) { + if ($addBtn.hasClass('js-note-emoji')) { + $addBtn.closest('.note').find('.js-awards-block').addClass('current'); + } else { + $addBtn.closest('.js-awards-block').addClass('current'); + } + + const $menu = $('.emoji-menu'); + if ($menu.length) { + if ($menu.is('.is-visible')) { + $addBtn.removeClass('is-active'); + $menu.removeClass('is-visible'); + $('#emoji_search').blur(); + } else { + $addBtn.addClass('is-active'); + this.positionMenu($menu, $addBtn); + $menu.addClass('is-visible'); + $('#emoji_search').focus(); + } + } else { + $addBtn.addClass('is-loading is-active'); + this.createEmojiMenu(() => { + const $createdMenu = $('.emoji-menu'); + $addBtn.removeClass('is-loading'); + this.positionMenu($createdMenu, $addBtn); + if (!this.frequentEmojiBlockRendered) { + this.renderFrequentlyUsedBlock(); } - }; - - AwardsHandler.prototype.removeYouFromUserList = function($emojiButton, emoji) { - var authors, awardBlock, newAuthors, originalTitle; - awardBlock = $emojiButton; - originalTitle = this.getAwardTooltip(awardBlock); - authors = originalTitle.split(FROM_SENTENCE_REGEX); - authors.splice(authors.indexOf('You'), 1); - return awardBlock - .closest('.js-emoji-btn') - .removeData('title') - .removeAttr('data-title') - .removeAttr('data-original-title') - .attr('title', this.toSentence(authors)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.addYouToUserList = function(votesBlock, emoji) { - var awardBlock, origTitle, users; - awardBlock = this.findEmojiIcon(votesBlock, emoji).parent(); - origTitle = this.getAwardTooltip(awardBlock); - users = []; - if (origTitle) { - users = origTitle.trim().split(FROM_SENTENCE_REGEX); + return setTimeout(() => { + $createdMenu.addClass('is-visible'); + $('#emoji_search').focus(); + }, 200); + }); + } +}; + +// Create the emoji menu with the first category of emojis. +// Then render the remaining categories of emojis one by one to avoid jank. +AwardsHandler.prototype.createEmojiMenu = function createEmojiMenu(callback) { + if (this.isCreatingEmojiMenu) { + return; + } + this.isCreatingEmojiMenu = true; + + // Render the first category + categoryMap = categoryMap || buildCategoryMap(); + const categoryNameKey = Object.keys(categoryMap)[0]; + const emojisInCategory = categoryMap[categoryNameKey]; + const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory); + + const emojiMenuMarkup = ` + <div class="emoji-menu"> + <input type="text" name="emoji_search" id="emoji_search" value="" class="emoji-search search-input form-control" placeholder="Search emoji" /> + + <div class="emoji-menu-content"> + ${firstCategory} + </div> + </div> + `; + + document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup); + + this.addRemainingEmojiMenuCategories(); + this.setupSearch(); + if (callback) { + callback(); + } +}; + +AwardsHandler + .prototype + .addRemainingEmojiMenuCategories = function addRemainingEmojiMenuCategories() { + if (this.isAddingRemainingEmojiMenuCategories) { + return; + } + this.isAddingRemainingEmojiMenuCategories = true; + + categoryMap = categoryMap || buildCategoryMap(); + + // Avoid the jank and render the remaining categories separately + // This will take more time, but makes UI more responsive + const menu = document.querySelector('.emoji-menu'); + const emojiContentElement = menu.querySelector('.emoji-menu-content'); + const remainingCategories = Object.keys(categoryMap).slice(1); + const allCategoriesAddedPromise = remainingCategories.reduce( + (promiseChain, categoryNameKey) => + promiseChain.then(() => + new Promise((resolve) => { + const emojisInCategory = categoryMap[categoryNameKey]; + const categoryMarkup = renderCategory( + categoryLabelMap[categoryNameKey], + emojisInCategory, + ); + requestAnimationFrame(() => { + emojiContentElement.insertAdjacentHTML('beforeend', categoryMarkup); + resolve(); + }); + }), + ), + Promise.resolve(), + ); + + allCategoriesAddedPromise.then(() => { + // Used for tests + // We check for the menu in case it was destroyed in the meantime + if (menu) { + menu.dispatchEvent(new CustomEvent('build-emoji-menu-finish')); } - users.unshift('You'); - return awardBlock - .attr('title', this.toSentence(users)) - .tooltip('fixTitle'); - }; - - AwardsHandler.prototype.createEmoji_ = function(votesBlock, emoji) { - var $emojiButton, buttonHtml, emojiCssClass; - emojiCssClass = this.resolveNameToCssClass(emoji); - buttonHtml = "<button class='btn award-control js-emoji-btn has-tooltip active' title='You' data-placement='bottom'> <div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div> <span class='award-control-text js-counter'>1</span> </button>"; - $emojiButton = $(buttonHtml); - $emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('emoji', emoji); + }); + }; + +AwardsHandler.prototype.positionMenu = function positionMenu($menu, $addBtn) { + const position = $addBtn.data('position'); + // The menu could potentially be off-screen or in a hidden overflow element + // So we position the element absolute in the body + const css = { + top: `${$addBtn.offset().top + $addBtn.outerHeight()}px`, + }; + if (position === 'right') { + css.left = `${($addBtn.offset().left - $menu.outerWidth()) + 20}px`; + $menu.addClass('is-aligned-right'); + } else { + css.left = `${$addBtn.offset().left}px`; + $menu.removeClass('is-aligned-right'); + } + return $menu.css(css); +}; + +AwardsHandler.prototype.addAward = function addAward( + votesBlock, + awardUrl, + emoji, + checkMutuality, + callback, +) { + const normalizedEmoji = this.normalizeEmojiName(emoji); + this.postEmoji(awardUrl, normalizedEmoji, () => { + this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality); + return typeof callback === 'function' ? callback() : undefined; + }); + return $('.emoji-menu').removeClass('is-visible'); +}; + +AwardsHandler.prototype.addAwardToEmojiBar = function addAwardToEmojiBar( + votesBlock, + emoji, + checkForMutuality, +) { + if (checkForMutuality || checkForMutuality === null) { + this.checkMutuality(votesBlock, emoji); + } + this.addEmojiToFrequentlyUsedList(emoji); + const normalizedEmoji = this.normalizeEmojiName(emoji); + const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); + if ($emojiButton.length > 0) { + if (this.isActive($emojiButton)) { + this.decrementCounter($emojiButton, normalizedEmoji); + } else { + const counter = $emojiButton.find('.js-counter'); + counter.text(parseInt(counter.text(), 10) + 1); + $emojiButton.addClass('active'); + this.addYouToUserList(votesBlock, normalizedEmoji); this.animateEmoji($emojiButton); - $('.award-control').tooltip(); - return votesBlock.removeClass('current'); - }; - - AwardsHandler.prototype.animateEmoji = function($emoji) { - var className = 'pulse animated once short'; - $emoji.addClass(className); + } + } else { + votesBlock.removeClass('hidden'); + this.createEmoji(votesBlock, normalizedEmoji); + } +}; + +AwardsHandler.prototype.getVotesBlock = function getVotesBlock() { + const currentBlock = $('.js-awards-block.current'); + let resultantVotesBlock = currentBlock; + if (currentBlock.length === 0) { + resultantVotesBlock = $('.js-awards-block').eq(0); + } + + return resultantVotesBlock; +}; + +AwardsHandler.prototype.getAwardUrl = function getAwardUrl() { + return this.getVotesBlock().data('award-url'); +}; + +AwardsHandler.prototype.checkMutuality = function checkMutuality(votesBlock, emoji) { + const awardUrl = this.getAwardUrl(); + if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + const mutualVote = emoji === 'thumbsup' ? 'thumbsdown' : 'thumbsup'; + const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).parent(); + const isAlreadyVoted = $emojiButton.hasClass('active'); + if (isAlreadyVoted) { + this.addAward(votesBlock, awardUrl, mutualVote, false); + } + } +}; + +AwardsHandler.prototype.isActive = function isActive($emojiButton) { + return $emojiButton.hasClass('active'); +}; + +AwardsHandler.prototype.decrementCounter = function decrementCounter($emojiButton, emoji) { + const counter = $('.js-counter', $emojiButton); + const counterNumber = parseInt(counter.text(), 10); + if (counterNumber > 1) { + counter.text(counterNumber - 1); + this.removeYouFromUserList($emojiButton); + } else if (emoji === 'thumbsup' || emoji === 'thumbsdown') { + $emojiButton.tooltip('destroy'); + counter.text('0'); + this.removeYouFromUserList($emojiButton); + if ($emojiButton.parents('.note').length) { + this.removeEmoji($emojiButton); + } + } else { + this.removeEmoji($emojiButton); + } + return $emojiButton.removeClass('active'); +}; + +AwardsHandler.prototype.removeEmoji = function removeEmoji($emojiButton) { + $emojiButton.tooltip('destroy'); + $emojiButton.remove(); + const $votesBlock = this.getVotesBlock(); + if ($votesBlock.find('.js-emoji-btn').length === 0) { + $votesBlock.addClass('hidden'); + } +}; + +AwardsHandler.prototype.getAwardTooltip = function getAwardTooltip($awardBlock) { + return $awardBlock.attr('data-original-title') || $awardBlock.attr('data-title') || ''; +}; + +AwardsHandler.prototype.toSentence = function toSentence(list) { + let sentence; + if (list.length <= 2) { + sentence = list.join(' and '); + } else { + sentence = `${list.slice(0, -1).join(', ')}, and ${list[list.length - 1]}`; + } + + return sentence; +}; + +AwardsHandler.prototype.removeYouFromUserList = function removeYouFromUserList($emojiButton) { + const awardBlock = $emojiButton; + const originalTitle = this.getAwardTooltip(awardBlock); + const authors = originalTitle.split(FROM_SENTENCE_REGEX); + authors.splice(authors.indexOf('You'), 1); + return awardBlock + .closest('.js-emoji-btn') + .removeData('title') + .removeAttr('data-title') + .removeAttr('data-original-title') + .attr('title', this.toSentence(authors)) + .tooltip('fixTitle'); +}; + +AwardsHandler.prototype.addYouToUserList = function addYouToUserList(votesBlock, emoji) { + const awardBlock = this.findEmojiIcon(votesBlock, emoji).parent(); + const origTitle = this.getAwardTooltip(awardBlock); + let users = []; + if (origTitle) { + users = origTitle.trim().split(FROM_SENTENCE_REGEX); + } + users.unshift('You'); + return awardBlock + .attr('title', this.toSentence(users)) + .tooltip('fixTitle'); +}; + +AwardsHandler + .prototype + .createAwardButtonForVotesBlock = function createAwardButtonForVotesBlock(votesBlock, emojiName) { + const buttonHtml = ` + <button class="btn award-control js-emoji-btn has-tooltip active" title="You" data-placement="bottom"> + ${glEmojiTag(emojiName)} + <span class="award-control-text js-counter">1</span> + </button> + `; + const $emojiButton = $(buttonHtml); + $emojiButton.insertBefore(votesBlock.find('.js-award-holder')).find('.emoji-icon').data('name', emojiName); + this.animateEmoji($emojiButton); + $('.award-control').tooltip(); + votesBlock.removeClass('current'); + }; + +AwardsHandler.prototype.animateEmoji = function animateEmoji($emoji) { + const className = 'pulse animated once short'; + $emoji.addClass(className); + + this.registerEventListener('on', $emoji, animationEndEventString, (e) => { + $(e.currentTarget).removeClass(className); + }); +}; + +AwardsHandler.prototype.createEmoji = function createEmoji(votesBlock, emoji) { + if ($('.emoji-menu').length) { + this.createAwardButtonForVotesBlock(votesBlock, emoji); + } + this.createEmojiMenu(() => { + this.createAwardButtonForVotesBlock(votesBlock, emoji); + }); +}; + +AwardsHandler.prototype.postEmoji = function postEmoji(awardUrl, emoji, callback) { + return $.post(awardUrl, { + name: emoji, + }, (data) => { + if (data.ok) { + callback(); + } + }); +}; + +AwardsHandler.prototype.findEmojiIcon = function findEmojiIcon(votesBlock, emoji) { + return votesBlock.find(`.js-emoji-btn [data-name="${emoji}"]`); +}; + +AwardsHandler.prototype.scrollToAwards = function scrollToAwards() { + const options = { + scrollTop: $('.awards').offset().top - 110, + }; + return $('body, html').animate(options, 200); +}; + +AwardsHandler.prototype.normalizeEmojiName = function normalizeEmojiName(emoji) { + return Object.prototype.hasOwnProperty.call(this.aliases, emoji) ? this.aliases[emoji] : emoji; +}; + +AwardsHandler + .prototype + .addEmojiToFrequentlyUsedList = function addEmojiToFrequentlyUsedList(emoji) { + const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); + frequentlyUsedEmojis.push(emoji); + Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }); + }; + +AwardsHandler.prototype.getFrequentlyUsedEmojis = function getFrequentlyUsedEmojis() { + const frequentlyUsedEmojis = (Cookies.get('frequently_used_emojis') || '').split(','); + return _.compact(_.uniq(frequentlyUsedEmojis)); +}; + +AwardsHandler.prototype.renderFrequentlyUsedBlock = function renderFrequentlyUsedBlock() { + if (Cookies.get('frequently_used_emojis')) { + const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); + const ul = $('<ul class="clearfix emoji-menu-list frequent-emojis">'); + for (let i = 0, len = frequentlyUsedEmojis.length; i < len; i += 1) { + const emoji = frequentlyUsedEmojis[i]; + $(`.emoji-menu-content [data-name="${emoji}"]`).closest('li').clone().appendTo(ul); + } + $('.emoji-menu-content').prepend(ul).prepend($('<h5>').text('Frequently used')); + } + this.frequentEmojiBlockRendered = true; +}; + +AwardsHandler.prototype.setupSearch = function setupSearch() { + this.registerEventListener('on', $('input.emoji-search'), 'input', (e) => { + const term = $(e.target).val().trim(); + // Clean previous search results + $('ul.emoji-menu-search, h5.emoji-search').remove(); + if (term.length > 0) { + // Generate a search result block + const h5 = $('<h5 class="emoji-search" />').text('Search results'); + const foundEmojis = this.searchEmojis(term).show(); + const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis); + $('.emoji-menu-content ul, .emoji-menu-content h5').hide(); + $('.emoji-menu-content').append(h5).append(ul); + } else { + $('.emoji-menu-content').children().show(); + } + }); +}; - $emoji.on('webkitAnimationEnd animationEnd', function() { - $(this).removeClass(className); - }); - }; +AwardsHandler.prototype.searchEmojis = function searchEmojis(term) { + const safeTerm = term.toLowerCase(); - AwardsHandler.prototype.createEmoji = function(votesBlock, emoji) { - if ($('.emoji-menu').length) { - return this.createEmoji_(votesBlock, emoji); - } - return this.createEmojiMenu(this.getAwardMenuUrl(), (function(_this) { - return function() { - return _this.createEmoji_(votesBlock, emoji); - }; - })(this)); - }; - - AwardsHandler.prototype.getAwardMenuUrl = function() { - return gon.award_menu_url; - }; - - AwardsHandler.prototype.resolveNameToCssClass = function(emoji) { - var emojiIcon, unicodeName; - emojiIcon = $(".emoji-menu-content [data-emoji='" + emoji + "']"); - if (emojiIcon.length > 0) { - unicodeName = emojiIcon.data('unicode-name'); - } else { - // Find by alias - unicodeName = $(".emoji-menu-content [data-aliases*=':" + emoji + ":']").data('unicode-name'); - } - return "emoji-" + unicodeName; - }; - - AwardsHandler.prototype.postEmoji = function(awardUrl, emoji, callback) { - return $.post(awardUrl, { - name: emoji - }, function(data) { - if (data.ok) { - return callback(); - } - }); - }; - - AwardsHandler.prototype.findEmojiIcon = function(votesBlock, emoji) { - return votesBlock.find(".js-emoji-btn [data-emoji='" + emoji + "']"); - }; - - AwardsHandler.prototype.scrollToAwards = function() { - var options; - options = { - scrollTop: $('.awards').offset().top - 110 - }; - return $('body, html').animate(options, 200); - }; - - AwardsHandler.prototype.normilizeEmojiName = function(emoji) { - return this.aliases[emoji] || emoji; - }; - - AwardsHandler.prototype.addEmojiToFrequentlyUsedList = function(emoji) { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - frequentlyUsedEmojis.push(emoji); - Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }); - }; - - AwardsHandler.prototype.getFrequentlyUsedEmojis = function() { - var frequentlyUsedEmojis; - frequentlyUsedEmojis = (Cookies.get('frequently_used_emojis') || '').split(','); - return _.compact(_.uniq(frequentlyUsedEmojis)); - }; - - AwardsHandler.prototype.renderFrequentlyUsedBlock = function() { - var emoji, frequentlyUsedEmojis, i, len, ul; - if (Cookies.get('frequently_used_emojis')) { - frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); - ul = $("<ul class='clearfix emoji-menu-list frequent-emojis'>"); - for (i = 0, len = frequentlyUsedEmojis.length; i < len; i += 1) { - emoji = frequentlyUsedEmojis[i]; - $(".emoji-menu-content [data-emoji='" + emoji + "']").closest('li').clone().appendTo(ul); - } - $('.emoji-menu-content').prepend(ul).prepend($('<h5>').text('Frequently used')); - } - return this.frequentEmojiBlockRendered = true; - }; - - AwardsHandler.prototype.setupSearch = function() { - return $('input.emoji-search').on('keyup', (function(_this) { - return function(ev) { - var found_emojis, h5, term, ul; - term = $(ev.target).val(); - // Clean previous search results - $('ul.emoji-menu-search, h5.emoji-search').remove(); - if (term) { - // Generate a search result block - h5 = $('<h5 class="emoji-search" />').text('Search results'); - found_emojis = _this.searchEmojis(term).show(); - ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(found_emojis); - $('.emoji-menu-content ul, .emoji-menu-content h5').hide(); - return $('.emoji-menu-content').append(h5).append(ul); - } else { - return $('.emoji-menu-content').children().show(); - } - }; - })(this)); - }; - - AwardsHandler.prototype.searchEmojis = function(term) { - return $(".emoji-menu-list:not(.frequent-emojis) [data-emoji*='" + term + "']").closest('li').clone(); - }; - - return AwardsHandler; - })(); -}).call(window); + const namesMatchingAlias = []; + Object.keys(emojiAliases).forEach((alias) => { + if (alias.indexOf(safeTerm) >= 0) { + namesMatchingAlias.push(emojiAliases[alias]); + } + }); + const $matchingElements = namesMatchingAlias.concat(safeTerm) + .reduce( + ($result, searchTerm) => + $result.add($(`.emoji-menu-list:not(.frequent-emojis) [data-name*="${searchTerm}"]`)), + $([]), + ); + return $matchingElements.closest('li').clone(); +}; + +AwardsHandler.prototype.destroy = function destroy() { + this.eventListeners.forEach((entry) => { + entry.element.off.call(entry.element, ...entry.args); + }); + $('.emoji-menu').remove(); +}; + +module.exports = AwardsHandler; diff --git a/app/assets/javascripts/behaviors/bind_in_out.js b/app/assets/javascripts/behaviors/bind_in_out.js new file mode 100644 index 00000000000..886f127b06b --- /dev/null +++ b/app/assets/javascripts/behaviors/bind_in_out.js @@ -0,0 +1,47 @@ +class BindInOut { + constructor(bindIn, bindOut) { + this.in = bindIn; + this.out = bindOut; + + this.eventWrapper = {}; + this.eventType = /(INPUT|TEXTAREA)/.test(bindIn.tagName) ? 'keyup' : 'change'; + } + + addEvents() { + this.eventWrapper.updateOut = this.updateOut.bind(this); + + this.in.addEventListener(this.eventType, this.eventWrapper.updateOut); + + return this; + } + + updateOut() { + this.out.textContent = this.in.value; + + return this; + } + + removeEvents() { + this.in.removeEventListener(this.eventType, this.eventWrapper.updateOut); + + return this; + } + + static initAll() { + const ins = document.querySelectorAll('*[data-bind-in]'); + + return [].map.call(ins, anIn => BindInOut.init(anIn)); + } + + static init(anIn, anOut) { + const out = anOut || document.querySelector(`*[data-bind-out="${anIn.dataset.bindIn}"]`); + + if (!out) return null; + + const bindInOut = new BindInOut(anIn, out); + + return bindInOut.addEvents().updateOut(); + } +} + +export default BindInOut; diff --git a/app/assets/javascripts/behaviors/gl_emoji.js b/app/assets/javascripts/behaviors/gl_emoji.js new file mode 100644 index 00000000000..d1d98c3919f --- /dev/null +++ b/app/assets/javascripts/behaviors/gl_emoji.js @@ -0,0 +1,217 @@ +const installCustomElements = require('document-register-element'); +const emojiMap = require('emoji-map'); +const emojiAliases = require('emoji-aliases'); +const generatedUnicodeSupportMap = require('./gl_emoji/unicode_support_map'); +const spreadString = require('./gl_emoji/spread_string'); + +installCustomElements(window); + +function emojiImageTag(name, src) { + return `<img class="emoji" title=":${name}:" alt=":${name}:" src="${src}" width="20" height="20" align="absmiddle" />`; +} + +function assembleFallbackImageSrc(inputName) { + const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ? + emojiAliases[inputName] : inputName; + const emojiInfo = emojiMap[name]; + const fallbackImageSrc = `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/emoji/${name}-${emojiInfo.digest}.png`; + + return fallbackImageSrc; +} +const glEmojiTagDefaults = { + sprite: false, + forceFallback: false, +}; +function glEmojiTag(inputName, options) { + const opts = Object.assign({}, glEmojiTagDefaults, options); + const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ? + emojiAliases[inputName] : inputName; + const emojiInfo = emojiMap[name]; + const fallbackImageSrc = assembleFallbackImageSrc(name); + const fallbackSpriteClass = `emoji-${name}`; + + const classList = []; + if (opts.forceFallback && opts.sprite) { + classList.push('emoji-icon'); + classList.push(fallbackSpriteClass); + } + const classAttribute = classList.length > 0 ? `class="${classList.join(' ')}"` : ''; + const fallbackSpriteAttribute = opts.sprite ? `data-fallback-sprite-class="${fallbackSpriteClass}"` : ''; + let contents = emojiInfo.moji; + if (opts.forceFallback && !opts.sprite) { + contents = emojiImageTag(name, fallbackImageSrc); + } + + return ` + <gl-emoji + ${classAttribute} + data-name="${name}" + data-fallback-src="${fallbackImageSrc}" + ${fallbackSpriteAttribute} + data-unicode-version="${emojiInfo.unicodeVersion}" + > + ${contents} + </gl-emoji> + `; +} + +// On Windows, flags render as two-letter country codes, see http://emojipedia.org/flags/ +const flagACodePoint = 127462; // parseInt('1F1E6', 16) +const flagZCodePoint = 127487; // parseInt('1F1FF', 16) +function isFlagEmoji(emojiUnicode) { + const cp = emojiUnicode.codePointAt(0); + // Length 4 because flags are made of 2 characters which are surrogate pairs + return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint; +} + +// Chrome <57 renders keycaps oddly +// See https://bugs.chromium.org/p/chromium/issues/detail?id=632294 +// Same issue on Windows also fixed in Chrome 57, http://i.imgur.com/rQF7woO.png +function isKeycapEmoji(emojiUnicode) { + return emojiUnicode.length === 3 && emojiUnicode[2] === '\u20E3'; +} + +// Check for a skin tone variation emoji which aren't always supported +const tone1 = 127995;// parseInt('1F3FB', 16) +const tone5 = 127999;// parseInt('1F3FF', 16) +function isSkinToneComboEmoji(emojiUnicode) { + return emojiUnicode.length > 2 && spreadString(emojiUnicode).some((char) => { + const cp = char.codePointAt(0); + return cp >= tone1 && cp <= tone5; + }); +} + +// macOS supports most skin tone emoji's but +// doesn't support the skin tone versions of horse racing +const horseRacingCodePoint = 127943;// parseInt('1F3C7', 16) +function isHorceRacingSkinToneComboEmoji(emojiUnicode) { + return spreadString(emojiUnicode)[0].codePointAt(0) === horseRacingCodePoint && + isSkinToneComboEmoji(emojiUnicode); +} + +// Check for `family_*`, `kiss_*`, `couple_*` +// For ex. Windows 8.1 Firefox 51.0.1, doesn't support these +const zwj = 8205; // parseInt('200D', 16) +const personStartCodePoint = 128102; // parseInt('1F466', 16) +const personEndCodePoint = 128105; // parseInt('1F469', 16) +function isPersonZwjEmoji(emojiUnicode) { + let hasPersonEmoji = false; + let hasZwj = false; + spreadString(emojiUnicode).forEach((character) => { + const cp = character.codePointAt(0); + if (cp === zwj) { + hasZwj = true; + } else if (cp >= personStartCodePoint && cp <= personEndCodePoint) { + hasPersonEmoji = true; + } + }); + + return hasPersonEmoji && hasZwj; +} + +// Helper so we don't have to run `isFlagEmoji` twice +// in `isEmojiUnicodeSupported` logic +function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) { + const isFlagResult = isFlagEmoji(emojiUnicode); + return ( + (unicodeSupportMap.flag && isFlagResult) || + !isFlagResult + ); +} + +// Helper so we don't have to run `isSkinToneComboEmoji` twice +// in `isEmojiUnicodeSupported` logic +function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) { + const isSkinToneResult = isSkinToneComboEmoji(emojiUnicode); + return ( + (unicodeSupportMap.skinToneModifier && isSkinToneResult) || + !isSkinToneResult + ); +} + +// Helper func so we don't have to run `isHorceRacingSkinToneComboEmoji` twice +// in `isEmojiUnicodeSupported` logic +function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) { + const isHorseRacingSkinToneResult = isHorceRacingSkinToneComboEmoji(emojiUnicode); + return ( + (unicodeSupportMap.horseRacing && isHorseRacingSkinToneResult) || + !isHorseRacingSkinToneResult + ); +} + +// Helper so we don't have to run `isPersonZwjEmoji` twice +// in `isEmojiUnicodeSupported` logic +function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) { + const isPersonZwjResult = isPersonZwjEmoji(emojiUnicode); + return ( + (unicodeSupportMap.personZwj && isPersonZwjResult) || + !isPersonZwjResult + ); +} + +// Takes in a support map and determines whether +// the given unicode emoji is supported on the platform. +// +// Combines all the edge case tests into a one-stop shop method +function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVersion) { + const isOlderThanChrome57 = unicodeSupportMap.meta && unicodeSupportMap.meta.isChrome && + unicodeSupportMap.meta.chromeVersion < 57; + + // For comments about each scenario, see the comments above each individual respective function + return unicodeSupportMap[unicodeVersion] && + !(isOlderThanChrome57 && isKeycapEmoji(emojiUnicode)) && + checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) && + checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) && + checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) && + checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode); +} + +const GlEmojiElementProto = Object.create(HTMLElement.prototype); +GlEmojiElementProto.createdCallback = function createdCallback() { + const emojiUnicode = this.textContent.trim(); + const { + name, + unicodeVersion, + fallbackSrc, + fallbackSpriteClass, + } = this.dataset; + + const isEmojiUnicode = this.childNodes && Array.prototype.every.call( + this.childNodes, + childNode => childNode.nodeType === 3, + ); + const hasImageFallback = fallbackSrc && fallbackSrc.length > 0; + const hasCssSpriteFalback = fallbackSpriteClass && fallbackSpriteClass.length > 0; + + if ( + isEmojiUnicode && + !isEmojiUnicodeSupported(generatedUnicodeSupportMap, emojiUnicode, unicodeVersion) + ) { + // CSS sprite fallback takes precedence over image fallback + if (hasCssSpriteFalback) { + // IE 11 doesn't like adding multiple at once :( + this.classList.add('emoji-icon'); + this.classList.add(fallbackSpriteClass); + } else if (hasImageFallback) { + this.innerHTML = emojiImageTag(name, fallbackSrc); + } else { + const src = assembleFallbackImageSrc(name); + this.innerHTML = emojiImageTag(name, src); + } + } +}; + +document.registerElement('gl-emoji', { + prototype: GlEmojiElementProto, +}); + +module.exports = { + emojiImageTag, + glEmojiTag, + isEmojiUnicodeSupported, + isFlagEmoji, + isKeycapEmoji, + isSkinToneComboEmoji, + isHorceRacingSkinToneComboEmoji, + isPersonZwjEmoji, +}; diff --git a/app/assets/javascripts/behaviors/gl_emoji/spread_string.js b/app/assets/javascripts/behaviors/gl_emoji/spread_string.js new file mode 100644 index 00000000000..2380349c4fa --- /dev/null +++ b/app/assets/javascripts/behaviors/gl_emoji/spread_string.js @@ -0,0 +1,50 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt#Fixing_charCodeAt()_to_handle_non-Basic-Multilingual-Plane_characters_if_their_presence_earlier_in_the_string_is_known +function knownCharCodeAt(givenString, index) { + const str = `${givenString}`; + const end = str.length; + + const surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; + let idx = index; + while ((surrogatePairs.exec(str)) != null) { + const li = surrogatePairs.lastIndex; + if (li - 2 < idx) { + idx += 1; + } else { + break; + } + } + + if (idx >= end || idx < 0) { + return NaN; + } + + const code = str.charCodeAt(idx); + + let high; + let low; + if (code >= 0xD800 && code <= 0xDBFF) { + high = code; + low = str.charCodeAt(idx + 1); + // Go one further, since one of the "characters" is part of a surrogate pair + return ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000; + } + return code; +} + +// See http://stackoverflow.com/a/38901550/796832 +// ES5/PhantomJS compatible version of spreading a string +// +// [...'foo'] -> ['f', 'o', 'o'] +// [...'🖐🏿'] -> ['🖐', '🏿'] +function spreadString(str) { + const arr = []; + let i = 0; + while (!isNaN(knownCharCodeAt(str, i))) { + const codePoint = knownCharCodeAt(str, i); + arr.push(String.fromCodePoint(codePoint)); + i += 1; + } + return arr; +} + +module.exports = spreadString; diff --git a/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js b/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js new file mode 100644 index 00000000000..f31716d4c07 --- /dev/null +++ b/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js @@ -0,0 +1,154 @@ +const unicodeSupportTestMap = { + // man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/ + // occupationZwj: '\u{1F468}\u{200D}\u{1F393}', + // woman, biking (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/ + // sexZwj: '\u{1F6B4}\u{200D}\u{2640}', + // family_mwgb + // Windows 8.1, Firefox 51.0.1 does not support `family_`, `kiss_`, `couple_` + personZwj: '\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}', + // horse_racing_tone5 + // Special case that is not supported on macOS 10.12 even though `skinToneModifier` succeeds + horseRacing: '\u{1F3C7}\u{1F3FF}', + // US flag, http://emojipedia.org/flags/ + flag: '\u{1F1FA}\u{1F1F8}', + // http://emojipedia.org/modifiers/ + skinToneModifier: [ + // spy_tone5 + '\u{1F575}\u{1F3FF}', + // person_with_ball_tone5 + '\u{26F9}\u{1F3FF}', + // angel_tone5 + '\u{1F47C}\u{1F3FF}', + ], + // rofl, http://emojipedia.org/unicode-9.0/ + '9.0': '\u{1F923}', + // metal, http://emojipedia.org/unicode-8.0/ + '8.0': '\u{1F918}', + // spy, http://emojipedia.org/unicode-7.0/ + '7.0': '\u{1F575}', + // expressionless, http://emojipedia.org/unicode-6.1/ + 6.1: '\u{1F611}', + // japanese_goblin, http://emojipedia.org/unicode-6.0/ + '6.0': '\u{1F47A}', + // sailboat, http://emojipedia.org/unicode-5.2/ + 5.2: '\u{26F5}', + // mahjong, http://emojipedia.org/unicode-5.1/ + 5.1: '\u{1F004}', + // gear, http://emojipedia.org/unicode-4.1/ + 4.1: '\u{2699}', + // zap, http://emojipedia.org/unicode-4.0/ + '4.0': '\u{26A1}', + // recycle, http://emojipedia.org/unicode-3.2/ + 3.2: '\u{267B}', + // information_source, http://emojipedia.org/unicode-3.0/ + '3.0': '\u{2139}', + // heart, http://emojipedia.org/unicode-1.1/ + 1.1: '\u{2764}', +}; + +function checkPixelInImageDataArray(pixelOffset, imageDataArray) { + // `4 *` because RGBA + const indexOffset = 4 * pixelOffset; + const hasColor = imageDataArray[indexOffset + 0] || + imageDataArray[indexOffset + 1] || + imageDataArray[indexOffset + 2]; + const isVisible = imageDataArray[indexOffset + 3]; + // Check for some sort of color other than black + if (hasColor && isVisible) { + return true; + } + return false; +} + +const chromeMatches = navigator.userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\./); +const isChrome = chromeMatches && chromeMatches.length > 0; +const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatches[1], 10); + +// We use 16px because mobile Safari (iOS 9.3) doesn't properly scale emojis :/ +// See 32px, https://i.imgur.com/htY6Zym.png +// See 16px, https://i.imgur.com/FPPsIF8.png +const fontSize = 16; +function testUnicodeSupportMap(testMap) { + const testMapKeys = Object.keys(testMap); + const numTestEntries = testMapKeys + .reduce((list, testKey) => list.concat(testMap[testKey]), []).length; + + const canvas = document.createElement('canvas'); + (window.gl || window).testEmojiUnicodeSupportMapCanvas = canvas; + const ctx = canvas.getContext('2d'); + canvas.width = (2 * fontSize); + canvas.height = (numTestEntries * fontSize); + ctx.fillStyle = '#000000'; + ctx.textBaseline = 'middle'; + ctx.font = `${fontSize}px "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`; + // Write each emoji to the canvas vertically + let writeIndex = 0; + testMapKeys.forEach((testKey) => { + const testEntry = testMap[testKey]; + [].concat(testEntry).forEach((emojiUnicode) => { + ctx.fillText(emojiUnicode, 0, (writeIndex * fontSize) + (fontSize / 2)); + writeIndex += 1; + }); + }); + + // Read from the canvas + const resultMap = {}; + let readIndex = 0; + testMapKeys.forEach((testKey) => { + const testEntry = testMap[testKey]; + // This needs to be a `reduce` instead of `every` because we need to + // keep the `readIndex` in sync from the writes by running all entries + const isTestSatisfied = [].concat(testEntry).reduce((isSatisfied) => { + // Sample along the vertical-middle for a couple of characters + const imageData = ctx.getImageData( + 0, + (readIndex * fontSize) + (fontSize / 2), + 2 * fontSize, + 1, + ).data; + + let isValidEmoji = false; + for (let currentPixel = 0; currentPixel < 64; currentPixel += 1) { + const isLookingAtFirstChar = currentPixel < fontSize; + const isLookingAtSecondChar = currentPixel >= (fontSize + (fontSize / 2)); + // Check for the emoji somewhere along the row + if (isLookingAtFirstChar && checkPixelInImageDataArray(currentPixel, imageData)) { + isValidEmoji = true; + + // Check to see that nothing is rendered next to the first character + // to ensure that the ZWJ sequence rendered as one piece + } else if (isLookingAtSecondChar && checkPixelInImageDataArray(currentPixel, imageData)) { + isValidEmoji = false; + break; + } + } + + readIndex += 1; + return isSatisfied && isValidEmoji; + }, true); + + resultMap[testKey] = isTestSatisfied; + }); + + resultMap.meta = { + isChrome, + chromeVersion, + }; + + return resultMap; +} + +let unicodeSupportMap; +const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent'); +try { + unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map')); +} catch (err) { + // swallow +} +if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) { + unicodeSupportMap = testUnicodeSupportMap(unicodeSupportTestMap); + window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent); + window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap)); +} + +module.exports = unicodeSupportMap; diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js index a7181904ac9..0726c6c9636 100644 --- a/app/assets/javascripts/behaviors/toggler_behavior.js +++ b/app/assets/javascripts/behaviors/toggler_behavior.js @@ -21,8 +21,7 @@ // %a.js-toggle-button // %div.js-toggle-content // - $('body').on('click', '.js-toggle-button', function(e) { - e.preventDefault(); + $('body').on('click', '.js-toggle-button', function() { toggleContainer($(this).closest('.js-toggle-container')); }); diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 b/app/assets/javascripts/blob/blob_ci_yaml.js index ec1c018424d..ec1c018424d 100644 --- a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 +++ b/app/assets/javascripts/blob/blob_ci_yaml.js diff --git a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selector.js index d4f60cc6ecd..d4f60cc6ecd 100644 --- a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 +++ b/app/assets/javascripts/blob/blob_dockerfile_selector.js diff --git a/app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selectors.js index 9cee79fa5d5..9cee79fa5d5 100644 --- a/app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6 +++ b/app/assets/javascripts/blob/blob_dockerfile_selectors.js diff --git a/app/assets/javascripts/blob/blob_license_selectors.js.es6 b/app/assets/javascripts/blob/blob_license_selectors.js index c5067b0feae..c5067b0feae 100644 --- a/app/assets/javascripts/blob/blob_license_selectors.js.es6 +++ b/app/assets/javascripts/blob/blob_license_selectors.js diff --git a/app/assets/javascripts/blob/template_selector.js.es6 b/app/assets/javascripts/blob/template_selector.js index 7e03ec3b391..7e03ec3b391 100644 --- a/app/assets/javascripts/blob/template_selector.js.es6 +++ b/app/assets/javascripts/blob/template_selector.js diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js index 55d13be6e5f..55d13be6e5f 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js index 18324de18b3..18324de18b3 100644 --- a/app/assets/javascripts/boards/components/board.js.es6 +++ b/app/assets/javascripts/boards/components/board.js diff --git a/app/assets/javascripts/boards/components/board_blank_state.js.es6 b/app/assets/javascripts/boards/components/board_blank_state.js index d76314c1892..d76314c1892 100644 --- a/app/assets/javascripts/boards/components/board_blank_state.js.es6 +++ b/app/assets/javascripts/boards/components/board_blank_state.js diff --git a/app/assets/javascripts/boards/components/board_delete.js.es6 b/app/assets/javascripts/boards/components/board_delete.js index 861600424a5..861600424a5 100644 --- a/app/assets/javascripts/boards/components/board_delete.js.es6 +++ b/app/assets/javascripts/boards/components/board_delete.js diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js index 2d52e96e7fb..2d52e96e7fb 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js diff --git a/app/assets/javascripts/boards/components/board_sidebar.js.es6 b/app/assets/javascripts/boards/components/board_sidebar.js index dfc6eed785c..dfc6eed785c 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js.es6 +++ b/app/assets/javascripts/boards/components/board_sidebar.js diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js.es6 b/app/assets/javascripts/boards/components/issue_card_inner.js index 22a8b971ff8..22a8b971ff8 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js.es6 +++ b/app/assets/javascripts/boards/components/issue_card_inner.js diff --git a/app/assets/javascripts/boards/components/modal/empty_state.js.es6 b/app/assets/javascripts/boards/components/modal/empty_state.js index 9538f5b69e9..9538f5b69e9 100644 --- a/app/assets/javascripts/boards/components/modal/empty_state.js.es6 +++ b/app/assets/javascripts/boards/components/modal/empty_state.js diff --git a/app/assets/javascripts/boards/components/modal/filters.js.es6 b/app/assets/javascripts/boards/components/modal/filters.js index 6de06811d94..6de06811d94 100644 --- a/app/assets/javascripts/boards/components/modal/filters.js.es6 +++ b/app/assets/javascripts/boards/components/modal/filters.js diff --git a/app/assets/javascripts/boards/components/modal/filters/label.js.es6 b/app/assets/javascripts/boards/components/modal/filters/label.js index 4fc8f72a145..4fc8f72a145 100644 --- a/app/assets/javascripts/boards/components/modal/filters/label.js.es6 +++ b/app/assets/javascripts/boards/components/modal/filters/label.js diff --git a/app/assets/javascripts/boards/components/modal/filters/milestone.js.es6 b/app/assets/javascripts/boards/components/modal/filters/milestone.js index d555599d300..d555599d300 100644 --- a/app/assets/javascripts/boards/components/modal/filters/milestone.js.es6 +++ b/app/assets/javascripts/boards/components/modal/filters/milestone.js diff --git a/app/assets/javascripts/boards/components/modal/filters/user.js.es6 b/app/assets/javascripts/boards/components/modal/filters/user.js index 8523028c29c..8523028c29c 100644 --- a/app/assets/javascripts/boards/components/modal/filters/user.js.es6 +++ b/app/assets/javascripts/boards/components/modal/filters/user.js diff --git a/app/assets/javascripts/boards/components/modal/footer.js.es6 b/app/assets/javascripts/boards/components/modal/footer.js index 1cbc422c961..1cbc422c961 100644 --- a/app/assets/javascripts/boards/components/modal/footer.js.es6 +++ b/app/assets/javascripts/boards/components/modal/footer.js diff --git a/app/assets/javascripts/boards/components/modal/header.js.es6 b/app/assets/javascripts/boards/components/modal/header.js index 70c088f9054..70c088f9054 100644 --- a/app/assets/javascripts/boards/components/modal/header.js.es6 +++ b/app/assets/javascripts/boards/components/modal/header.js diff --git a/app/assets/javascripts/boards/components/modal/index.js.es6 b/app/assets/javascripts/boards/components/modal/index.js index f290cd13763..f290cd13763 100644 --- a/app/assets/javascripts/boards/components/modal/index.js.es6 +++ b/app/assets/javascripts/boards/components/modal/index.js diff --git a/app/assets/javascripts/boards/components/modal/list.js.es6 b/app/assets/javascripts/boards/components/modal/list.js index 3730c1ecaeb..3730c1ecaeb 100644 --- a/app/assets/javascripts/boards/components/modal/list.js.es6 +++ b/app/assets/javascripts/boards/components/modal/list.js diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.js.es6 b/app/assets/javascripts/boards/components/modal/lists_dropdown.js index 3c05120a2da..3c05120a2da 100644 --- a/app/assets/javascripts/boards/components/modal/lists_dropdown.js.es6 +++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.js diff --git a/app/assets/javascripts/boards/components/modal/tabs.js.es6 b/app/assets/javascripts/boards/components/modal/tabs.js index e8cb43f3503..e8cb43f3503 100644 --- a/app/assets/javascripts/boards/components/modal/tabs.js.es6 +++ b/app/assets/javascripts/boards/components/modal/tabs.js diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 b/app/assets/javascripts/boards/components/new_list_dropdown.js index 556826a9148..556826a9148 100644 --- a/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 +++ b/app/assets/javascripts/boards/components/new_list_dropdown.js diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.js.es6 b/app/assets/javascripts/boards/components/sidebar/remove_issue.js index e74935e1cb0..e74935e1cb0 100644 --- a/app/assets/javascripts/boards/components/sidebar/remove_issue.js.es6 +++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.js diff --git a/app/assets/javascripts/boards/filters/due_date_filters.js.es6 b/app/assets/javascripts/boards/filters/due_date_filters.js index 03425bb145b..03425bb145b 100644 --- a/app/assets/javascripts/boards/filters/due_date_filters.js.es6 +++ b/app/assets/javascripts/boards/filters/due_date_filters.js diff --git a/app/assets/javascripts/boards/mixins/modal_mixins.js.es6 b/app/assets/javascripts/boards/mixins/modal_mixins.js index d378b7d4baf..d378b7d4baf 100644 --- a/app/assets/javascripts/boards/mixins/modal_mixins.js.es6 +++ b/app/assets/javascripts/boards/mixins/modal_mixins.js diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 b/app/assets/javascripts/boards/mixins/sortable_default_options.js index b6c6d17274f..b6c6d17274f 100644 --- a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 +++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js diff --git a/app/assets/javascripts/boards/models/issue.js.es6 b/app/assets/javascripts/boards/models/issue.js index 2d0a295ae4d..2d0a295ae4d 100644 --- a/app/assets/javascripts/boards/models/issue.js.es6 +++ b/app/assets/javascripts/boards/models/issue.js diff --git a/app/assets/javascripts/boards/models/label.js.es6 b/app/assets/javascripts/boards/models/label.js index 9af88d167d6..9af88d167d6 100644 --- a/app/assets/javascripts/boards/models/label.js.es6 +++ b/app/assets/javascripts/boards/models/label.js diff --git a/app/assets/javascripts/boards/models/list.js.es6 b/app/assets/javascripts/boards/models/list.js index 8158ed4ec2c..8158ed4ec2c 100644 --- a/app/assets/javascripts/boards/models/list.js.es6 +++ b/app/assets/javascripts/boards/models/list.js diff --git a/app/assets/javascripts/boards/models/milestone.js.es6 b/app/assets/javascripts/boards/models/milestone.js index c867b06d320..c867b06d320 100644 --- a/app/assets/javascripts/boards/models/milestone.js.es6 +++ b/app/assets/javascripts/boards/models/milestone.js diff --git a/app/assets/javascripts/boards/models/user.js.es6 b/app/assets/javascripts/boards/models/user.js index 8e9de4d4cbb..8e9de4d4cbb 100644 --- a/app/assets/javascripts/boards/models/user.js.es6 +++ b/app/assets/javascripts/boards/models/user.js diff --git a/app/assets/javascripts/boards/services/board_service.js.es6 b/app/assets/javascripts/boards/services/board_service.js index 065e90518df..065e90518df 100644 --- a/app/assets/javascripts/boards/services/board_service.js.es6 +++ b/app/assets/javascripts/boards/services/board_service.js diff --git a/app/assets/javascripts/boards/stores/boards_store.js.es6 b/app/assets/javascripts/boards/stores/boards_store.js index 56436c8fdc7..56436c8fdc7 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js.es6 +++ b/app/assets/javascripts/boards/stores/boards_store.js diff --git a/app/assets/javascripts/boards/stores/modal_store.js.es6 b/app/assets/javascripts/boards/stores/modal_store.js index 15fc6c79e8d..15fc6c79e8d 100644 --- a/app/assets/javascripts/boards/stores/modal_store.js.es6 +++ b/app/assets/javascripts/boards/stores/modal_store.js diff --git a/app/assets/javascripts/build_variables.js.es6 b/app/assets/javascripts/build_variables.js index 99082b412e2..99082b412e2 100644 --- a/app/assets/javascripts/build_variables.js.es6 +++ b/app/assets/javascripts/build_variables.js diff --git a/app/assets/javascripts/ci_lint_editor.js.es6 b/app/assets/javascripts/ci_lint_editor.js index 56ffaa765a8..56ffaa765a8 100644 --- a/app/assets/javascripts/ci_lint_editor.js.es6 +++ b/app/assets/javascripts/ci_lint_editor.js diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js index b5a988df897..b5a988df897 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js diff --git a/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_service.js index 8ae98f9bf97..8ae98f9bf97 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_service.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_service.js diff --git a/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_store.js index f1b80e45444..f1b80e45444 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_store.js diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_table.js index cd2bd883d32..631ed34851c 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_table.js @@ -39,15 +39,10 @@ const PipelineStore = require('./pipelines_store'); */ data() { const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset; - const svgsData = document.querySelector('.pipeline-svgs').dataset; const store = new PipelineStore(); - // Transform svgs DOMStringMap to a plain Object. - const svgsObject = gl.utils.DOMStringMapToObject(svgsData); - return { endpoint: pipelinesTableData.endpoint, - svgs: svgsObject, store, state: store.state, isLoading: false, @@ -101,10 +96,7 @@ const PipelineStore = require('./pipelines_store'); <div class="table-holder pipelines" v-if="!isLoading && state.pipelines.length > 0"> - <pipelines-table-component - :pipelines="state.pipelines" - :svgs="svgs"> - </pipelines-table-component> + <pipelines-table-component :pipelines="state.pipelines"/> </div> </div> `, diff --git a/app/assets/javascripts/commons/bootstrap.js b/app/assets/javascripts/commons/bootstrap.js new file mode 100644 index 00000000000..db0cbfd87c3 --- /dev/null +++ b/app/assets/javascripts/commons/bootstrap.js @@ -0,0 +1,10 @@ +import 'jquery'; + +// bootstrap jQuery plugins +import 'bootstrap-sass/assets/javascripts/bootstrap/affix'; +import 'bootstrap-sass/assets/javascripts/bootstrap/alert'; +import 'bootstrap-sass/assets/javascripts/bootstrap/dropdown'; +import 'bootstrap-sass/assets/javascripts/bootstrap/modal'; +import 'bootstrap-sass/assets/javascripts/bootstrap/tab'; +import 'bootstrap-sass/assets/javascripts/bootstrap/transition'; +import 'bootstrap-sass/assets/javascripts/bootstrap/tooltip'; diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js new file mode 100644 index 00000000000..72ede1d621a --- /dev/null +++ b/app/assets/javascripts/commons/index.js @@ -0,0 +1,2 @@ +import './jquery'; +import './bootstrap'; diff --git a/app/assets/javascripts/commons/jquery.js b/app/assets/javascripts/commons/jquery.js new file mode 100644 index 00000000000..b53f6284afc --- /dev/null +++ b/app/assets/javascripts/commons/jquery.js @@ -0,0 +1,11 @@ +import 'jquery'; + +// common jQuery plugins +import 'jquery-ujs'; +import 'vendor/jquery.endless-scroll'; +import 'vendor/jquery.caret'; +import 'vendor/jquery.atwho'; +import 'vendor/jquery.scrollTo'; +import 'vendor/jquery.nicescroll'; +import 'vendor/jquery.waitforimages'; +import 'select2/select2'; diff --git a/app/assets/javascripts/compare_autocomplete.js.es6 b/app/assets/javascripts/compare_autocomplete.js index 1eca973e069..1eca973e069 100644 --- a/app/assets/javascripts/compare_autocomplete.js.es6 +++ b/app/assets/javascripts/compare_autocomplete.js diff --git a/app/assets/javascripts/copy_as_gfm.js.es6 b/app/assets/javascripts/copy_as_gfm.js index 2bc3d85fba4..8883c339335 100644 --- a/app/assets/javascripts/copy_as_gfm.js.es6 +++ b/app/assets/javascripts/copy_as_gfm.js @@ -49,6 +49,9 @@ require('./lib/utils/common_utils'); 'img.emoji'(el, text) { return el.getAttribute('alt'); }, + 'gl-emoji'(el, text) { + return `:${el.getAttribute('data-name')}:`; + }, }, ImageLinkFilter: { 'a.no-attachment-icon'(el, text) { @@ -110,7 +113,7 @@ require('./lib/utils/common_utils'); return `<dl>\n${lines.join('\n')}\n</dl>`; }, - 'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr'(el, text) { + 'sub, dt, dd, kbd, q, samp, var, ruby, rt, rp, abbr, summary, details'(el, text) { const tag = el.nodeName.toLowerCase(); return `<${tag}>${text}</${tag}>`; }, diff --git a/app/assets/javascripts/create_label.js.es6 b/app/assets/javascripts/create_label.js index 85384d98126..85384d98126 100644 --- a/app/assets/javascripts/create_label.js.es6 +++ b/app/assets/javascripts/create_label.js diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_code_component.js index b83a4c63fad..b83a4c63fad 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.js diff --git a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js index cb1687dcc7a..cb1687dcc7a 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js index 8652479e7bf..42e1bbce744 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js @@ -1,5 +1,6 @@ /* eslint-disable no-param-reassign */ -/* global Vue */ +import Vue from 'vue'; +import iconCommit from '../svg/icon_commit.svg'; ((global) => { global.cycleAnalytics = global.cycleAnalytics || {}; @@ -9,6 +10,11 @@ items: Array, stage: Object, }, + + data() { + return { iconCommit }; + }, + template: ` <div> <div class="events-description"> @@ -31,7 +37,7 @@ </h5> <span> First - <span class="commit-icon">${global.cycleAnalytics.svgs.iconCommit}</span> + <span class="commit-icon">${iconCommit}</span> <a :href="commit.commitUrl" class="commit-hash-link monospace">{{ commit.shortSha }}</a> pushed by <a :href="commit.author.webUrl" class="commit-author-link"> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_production_component.js index 73f4205b578..73f4205b578 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_production_component.js diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_review_component.js index 501ffb1fac9..501ffb1fac9 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.js diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js index 82622232f64..8fa63734cf1 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.js @@ -1,5 +1,6 @@ /* eslint-disable no-param-reassign */ -/* global Vue */ +import Vue from 'vue'; +import iconBranch from '../svg/icon_branch.svg'; ((global) => { global.cycleAnalytics = global.cycleAnalytics || {}; @@ -9,6 +10,9 @@ items: Array, stage: Object, }, + data() { + return { iconBranch }; + }, template: ` <div> <div class="events-description"> @@ -22,7 +26,7 @@ <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> <i class="fa fa-code-fork"></i> <a :href="build.branch.url" class="branch-name monospace">{{ build.branch.name }}</a> - <span class="icon-branch">${global.cycleAnalytics.svgs.iconBranch}</span> + <span class="icon-branch">${iconBranch}</span> <a :href="build.commitUrl" class="short-sha monospace">{{ build.shortSha }}</a> </h5> <span> diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/stage_test_component.js index 4bfd363a1f1..0015249cfaa 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.js @@ -1,5 +1,7 @@ /* eslint-disable no-param-reassign */ -/* global Vue */ +import Vue from 'vue'; +import iconBuildStatus from '../svg/icon_build_status.svg'; +import iconBranch from '../svg/icon_branch.svg'; ((global) => { global.cycleAnalytics = global.cycleAnalytics || {}; @@ -9,6 +11,9 @@ items: Array, stage: Object, }, + data() { + return { iconBuildStatus, iconBranch }; + }, template: ` <div> <div class="events-description"> @@ -18,13 +23,13 @@ <li v-for="build in items" class="stage-event-item item-build-component"> <div class="item-details"> <h5 class="item-title"> - <span class="icon-build-status">${global.cycleAnalytics.svgs.iconBuildStatus}</span> + <span class="icon-build-status">${iconBuildStatus}</span> <a :href="build.url" class="item-build-name">{{ build.name }}</a> · <a :href="build.url" class="pipeline-id">#{{ build.id }}</a> <i class="fa fa-code-fork"></i> <a :href="build.branch.url" class="branch-name monospace">{{ build.branch.name }}</a> - <span class="icon-branch">${global.cycleAnalytics.svgs.iconBranch}</span> + <span class="icon-branch">${iconBranch}</span> <a :href="build.commitUrl" class="short-sha monospace">{{ build.shortSha }}</a> </h5> <span> diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.js.es6 b/app/assets/javascripts/cycle_analytics/components/total_time_component.js index 0d85e1a4678..0d85e1a4678 100644 --- a/app/assets/javascripts/cycle_analytics/components/total_time_component.js.es6 +++ b/app/assets/javascripts/cycle_analytics/components/total_time_component.js diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js index 411ac7b24b2..beff293b587 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js @@ -4,9 +4,6 @@ window.Vue = require('vue'); window.Cookies = require('js-cookie'); -require('./svg/icon_branch'); -require('./svg/icon_build_status'); -require('./svg/icon_commit'); require('./components/stage_code_component'); require('./components/stage_issue_component'); require('./components/stage_plan_component'); diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js index 9f74b14c4b9..9f74b14c4b9 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js index 7ae9de7297c..7ae9de7297c 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js diff --git a/app/assets/javascripts/cycle_analytics/default_event_objects.js.es6 b/app/assets/javascripts/cycle_analytics/default_event_objects.js index cfaf9835bf8..cfaf9835bf8 100644 --- a/app/assets/javascripts/cycle_analytics/default_event_objects.js.es6 +++ b/app/assets/javascripts/cycle_analytics/default_event_objects.js diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_branch.js.es6 b/app/assets/javascripts/cycle_analytics/svg/icon_branch.js.es6 deleted file mode 100644 index 5d486bcaf66..00000000000 --- a/app/assets/javascripts/cycle_analytics/svg/icon_branch.js.es6 +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable no-param-reassign */ -((global) => { - global.cycleAnalytics = global.cycleAnalytics || {}; - global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {}; - - global.cycleAnalytics.svgs.iconBranch = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><path fill="#8C8C8C" fill-rule="evenodd" d="M9.678 6.722C9.353 5.167 8.053 4 6.5 4S3.647 5.167 3.322 6.722h-2.6c-.397 0-.722.35-.722.778 0 .428.325.778.722.778h2.6C3.647 9.833 4.947 11 6.5 11s2.853-1.167 3.178-2.722h2.6c.397 0 .722-.35.722-.778 0-.428-.325-.778-.722-.778h-2.6zM4.694 7.5c0-1.09.795-1.944 1.806-1.944 1.01 0 1.806.855 1.806 1.944 0 1.09-.795 1.944-1.806 1.944-1.01 0-1.806-.855-1.806-1.944z"/></svg>'; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg b/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg new file mode 100644 index 00000000000..9f547d3d744 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><path fill="#8C8C8C" fill-rule="evenodd" d="M9.678 6.722C9.353 5.167 8.053 4 6.5 4S3.647 5.167 3.322 6.722h-2.6c-.397 0-.722.35-.722.778 0 .428.325.778.722.778h2.6C3.647 9.833 4.947 11 6.5 11s2.853-1.167 3.178-2.722h2.6c.397 0 .722-.35.722-.778 0-.428-.325-.778-.722-.778h-2.6zM4.694 7.5c0-1.09.795-1.944 1.806-1.944 1.01 0 1.806.855 1.806 1.944 0 1.09-.795 1.944-1.806 1.944-1.01 0-1.806-.855-1.806-1.944z"/></svg> diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_build_status.js.es6 b/app/assets/javascripts/cycle_analytics/svg/icon_build_status.js.es6 deleted file mode 100644 index 661bf9e9f1c..00000000000 --- a/app/assets/javascripts/cycle_analytics/svg/icon_build_status.js.es6 +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable no-param-reassign */ -((global) => { - global.cycleAnalytics = global.cycleAnalytics || {}; - global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {}; - - global.cycleAnalytics.svgs.iconBuildStatus = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><g fill="#31AF64" fill-rule="evenodd"><path d="M12.5 7c0-3.038-2.462-5.5-5.5-5.5S1.5 3.962 1.5 7s2.462 5.5 5.5 5.5 5.5-2.462 5.5-5.5zM0 7c0-3.866 3.134-7 7-7s7 3.134 7 7-3.134 7-7 7-7-3.134-7-7z"/><path d="M6.28 7.697L5.045 6.464c-.117-.117-.305-.117-.42-.002l-.614.614c-.11.113-.11.303.007.42l1.91 1.91c.19.19.51.197.703.004l.264-.265L9.997 6.04c.108-.107.107-.293-.01-.408l-.612-.614c-.114-.113-.298-.12-.41-.01L6.28 7.7z"/></g></svg>'; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg b/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg new file mode 100644 index 00000000000..b932d90618a --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><g fill="#31AF64" fill-rule="evenodd"><path d="M12.5 7c0-3.038-2.462-5.5-5.5-5.5S1.5 3.962 1.5 7s2.462 5.5 5.5 5.5 5.5-2.462 5.5-5.5zM0 7c0-3.866 3.134-7 7-7s7 3.134 7 7-3.134 7-7 7-7-3.134-7-7z"/><path d="M6.28 7.697L5.045 6.464c-.117-.117-.305-.117-.42-.002l-.614.614c-.11.113-.11.303.007.42l1.91 1.91c.19.19.51.197.703.004l.264-.265L9.997 6.04c.108-.107.107-.293-.01-.408l-.612-.614c-.114-.113-.298-.12-.41-.01L6.28 7.7z"/></g></svg> diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_commit.js.es6 b/app/assets/javascripts/cycle_analytics/svg/icon_commit.js.es6 deleted file mode 100644 index 2208c27a619..00000000000 --- a/app/assets/javascripts/cycle_analytics/svg/icon_commit.js.es6 +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable no-param-reassign */ -((global) => { - global.cycleAnalytics = global.cycleAnalytics || {}; - global.cycleAnalytics.svgs = global.cycleAnalytics.svgs || {}; - - global.cycleAnalytics.svgs.iconCommit = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path fill="#8F8F8F" fill-rule="evenodd" d="M28.777 18c-.91-4.008-4.494-7-8.777-7-4.283 0-7.868 2.992-8.777 7H4.01C2.9 18 2 18.895 2 20c0 1.112.9 2 2.01 2h7.213c.91 4.008 4.494 7 8.777 7 4.283 0 7.868-2.992 8.777-7h7.214C37.1 22 38 21.105 38 20c0-1.112-.9-2-2.01-2h-7.213zM20 25c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5z"/></svg>'; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg b/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg new file mode 100644 index 00000000000..6a517756058 --- /dev/null +++ b/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path fill="#8F8F8F" fill-rule="evenodd" d="M28.777 18c-.91-4.008-4.494-7-8.777-7-4.283 0-7.868 2.992-8.777 7H4.01C2.9 18 2 18.895 2 20c0 1.112.9 2 2.01 2h7.213c.91 4.008 4.494 7 8.777 7 4.283 0 7.868-2.992 8.777-7h7.214C37.1 22 38 21.105 38 20c0-1.112-.9-2-2.01-2h-7.213zM20 25c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5z"/></svg> diff --git a/app/assets/javascripts/diff.js.es6 b/app/assets/javascripts/diff.js index ccccd0a36ff..6829e8aeaea 100644 --- a/app/assets/javascripts/diff.js.es6 +++ b/app/assets/javascripts/diff.js @@ -25,6 +25,10 @@ require('./lib/utils/url_utility'); isBound = true; } + if (gl.utils.getLocationHash()) { + this.highlightSelectedLine(); + } + this.openAnchoredDiff(); } @@ -78,7 +82,7 @@ require('./lib/utils/url_utility'); if (nothingHereBlock.length) { const clickTarget = $('.js-file-title, .click-to-expand', diffFile); diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { - this.highlighSelectedLine(); + this.highlightSelectedLine(); if (cb) cb(); }); } else if (cb) { @@ -94,7 +98,7 @@ require('./lib/utils/url_utility'); } else { window.location.hash = hash; } - this.highlighSelectedLine(); + this.highlightSelectedLine(); } diffViewType() { @@ -108,7 +112,7 @@ require('./lib/utils/url_utility'); return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10)); } - highlighSelectedLine() { + highlightSelectedLine() { const hash = gl.utils.getLocationHash(); const $diffFiles = $('.diff-file'); $diffFiles.find('.hll').removeClass('hll'); diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6 b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js index d948dff58ec..d948dff58ec 100644 --- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6 +++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6 b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js index 283dc330cad..283dc330cad 100644 --- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6 +++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_btn.js index d1873d6c7a2..d1873d6c7a2 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6 +++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_count.js index de9367f2136..de9367f2136 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_count.js.es6 +++ b/app/assets/javascripts/diff_notes/components/resolve_count.js diff --git a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js index 7c5fcd04d2d..7c5fcd04d2d 100644 --- a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6 +++ b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js index cadf8b96b87..cadf8b96b87 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js.es6 b/app/assets/javascripts/diff_notes/mixins/discussion.js index 3c08c222f46..3c08c222f46 100644 --- a/app/assets/javascripts/diff_notes/mixins/discussion.js.es6 +++ b/app/assets/javascripts/diff_notes/mixins/discussion.js diff --git a/app/assets/javascripts/diff_notes/models/discussion.js.es6 b/app/assets/javascripts/diff_notes/models/discussion.js index fa518ba4d33..fa518ba4d33 100644 --- a/app/assets/javascripts/diff_notes/models/discussion.js.es6 +++ b/app/assets/javascripts/diff_notes/models/discussion.js diff --git a/app/assets/javascripts/diff_notes/models/note.js.es6 b/app/assets/javascripts/diff_notes/models/note.js index f3a7cba5ef6..f3a7cba5ef6 100644 --- a/app/assets/javascripts/diff_notes/models/note.js.es6 +++ b/app/assets/javascripts/diff_notes/models/note.js diff --git a/app/assets/javascripts/diff_notes/services/resolve.js.es6 b/app/assets/javascripts/diff_notes/services/resolve.js index 090c454e9e4..090c454e9e4 100644 --- a/app/assets/javascripts/diff_notes/services/resolve.js.es6 +++ b/app/assets/javascripts/diff_notes/services/resolve.js diff --git a/app/assets/javascripts/diff_notes/stores/comments.js.es6 b/app/assets/javascripts/diff_notes/stores/comments.js index c80d979b977..c80d979b977 100644 --- a/app/assets/javascripts/diff_notes/stores/comments.js.es6 +++ b/app/assets/javascripts/diff_notes/stores/comments.js diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js index fc25122aedc..31f10f89245 100644 --- a/app/assets/javascripts/dispatcher.js.es6 +++ b/app/assets/javascripts/dispatcher.js @@ -35,7 +35,9 @@ /* global Labels */ /* global Shortcuts */ +import BindInOut from './behaviors/bind_in_out'; import GroupsList from './groups_list'; +import ProjectsList from './projects_list'; const ShortcutsBlob = require('./shortcuts_blob'); const UserCallout = require('./user_callout'); @@ -98,6 +100,14 @@ const UserCallout = require('./user_callout'); case 'dashboard:todos:index': new gl.Todos(); break; + case 'dashboard:projects:index': + case 'dashboard:projects:starred': + case 'explore:projects:index': + case 'explore:projects:trending': + case 'explore:projects:starred': + case 'admin:projects:index': + new ProjectsList(); + break; case 'dashboard:groups:index': case 'explore:groups:index': new GroupsList(); @@ -163,9 +173,6 @@ const UserCallout = require('./user_callout'); case 'dashboard:activity': new gl.Activities(); break; - case 'dashboard:projects:starred': - new gl.Activities(); - break; case 'projects:commit:show': new Commit(); new gl.Diff(); @@ -208,6 +215,7 @@ const UserCallout = require('./user_callout'); shortcut_handler = new ShortcutsNavigation(); new NotificationsForm(); new NotificationsDropdown(); + new ProjectsList(); break; case 'groups:group_members:index': new gl.MemberExpirationDate(); @@ -222,9 +230,14 @@ const UserCallout = require('./user_callout'); new UsersSelect(); break; case 'groups:new': + case 'admin:groups:new': + case 'groups:create': + case 'admin:groups:create': + BindInOut.initAll(); + case 'groups:new': + case 'admin:groups:new': case 'groups:edit': case 'admin:groups:edit': - case 'admin:groups:new': new GroupAvatar(); break; case 'projects:tree:show': diff --git a/app/assets/javascripts/due_date_select.js.es6 b/app/assets/javascripts/due_date_select.js index 9169fcd7328..9169fcd7328 100644 --- a/app/assets/javascripts/due_date_select.js.es6 +++ b/app/assets/javascripts/due_date_select.js diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js index 5869323d1e2..2cb48dde628 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js @@ -35,9 +35,6 @@ module.exports = Vue.component('environment-component', { projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath, newEnvironmentPath: environmentsData.newEnvironmentPath, helpPagePath: environmentsData.helpPagePath, - commitIconSvg: environmentsData.commitIconSvg, - playIconSvg: environmentsData.playIconSvg, - terminalIconSvg: environmentsData.terminalIconSvg, // Pagination Properties, paginationInformation: {}, @@ -78,7 +75,7 @@ module.exports = Vue.component('environment-component', { this.isLoading = true; - return service.all() + return service.get() .then(resp => ({ headers: resp.headers, body: resp.json(), @@ -176,11 +173,7 @@ module.exports = Vue.component('environment-component', { <environment-table :environments="state.environments" :can-create-deployment="canCreateDeploymentParsed" - :can-read-environment="canReadEnvironmentParsed" - :play-icon-svg="playIconSvg" - :terminal-icon-svg="terminalIconSvg" - :commit-icon-svg="commitIconSvg"> - </environment-table> + :can-read-environment="canReadEnvironmentParsed"/> </div> <table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1" diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js index 978d4dd8b6b..15e3f8823d2 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js @@ -1,4 +1,5 @@ const Vue = require('vue'); +const playIconSvg = require('icons/_icon_play.svg'); module.exports = Vue.component('actions-component', { props: { @@ -7,11 +8,10 @@ module.exports = Vue.component('actions-component', { required: false, default: () => [], }, + }, - playIconSvg: { - type: String, - required: false, - }, + data() { + return { playIconSvg }; }, template: ` @@ -28,9 +28,7 @@ module.exports = Vue.component('actions-component', { data-method="post" rel="nofollow" class="js-manual-action-link"> - - <span class="js-action-play-icon-container" v-html="playIconSvg"></span> - + ${playIconSvg} <span> {{action.name}} </span> diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js index 2599bba3c59..2599bba3c59 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ b/app/assets/javascripts/environments/components/environment_external_url.js diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js index 3f782742c56..7f4e070b229 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js @@ -46,21 +46,6 @@ module.exports = Vue.component('environment-item', { required: false, default: false, }, - - commitIconSvg: { - type: String, - required: false, - }, - - playIconSvg: { - type: String, - required: false, - }, - - terminalIconSvg: { - type: String, - required: false, - }, }, computed: { @@ -487,9 +472,7 @@ module.exports = Vue.component('environment-item', { :commit-url="commitUrl" :short-sha="commitShortSha" :title="commitTitle" - :author="commitAuthor" - :commit-icon-svg="commitIconSvg"> - </commit-component> + :author="commitAuthor"/> </div> <p v-if="!model.isFolder && !hasLastDeploymentKey" class="commit-title"> No deployments yet @@ -506,27 +489,20 @@ module.exports = Vue.component('environment-item', { <td class="environments-actions"> <div v-if="!model.isFolder" class="btn-group pull-right" role="group"> <actions-component v-if="hasManualActions && canCreateDeployment" - :play-icon-svg="playIconSvg" - :actions="manualActions"> - </actions-component> + :actions="manualActions"/> <external-url-component v-if="externalURL && canReadEnvironment" - :external-url="externalURL"> - </external-url-component> + :external-url="externalURL"/> <stop-component v-if="hasStopAction && canCreateDeployment" - :stop-url="model.stop_path"> - </stop-component> + :stop-url="model.stop_path"/> <terminal-button-component v-if="model && model.terminal_path" - :terminal-icon-svg="terminalIconSvg" - :terminal-path="model.terminal_path"> - </terminal-button-component> + :terminal-path="model.terminal_path"/> <rollback-component v-if="canRetry && canCreateDeployment" :is-last-deployment="isLastDeployment" - :retry-url="retryUrl"> - </rollback-component> + :retry-url="retryUrl"/> </div> </td> </tr> diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js index daf126eb4e8..daf126eb4e8 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.js.es6 +++ b/app/assets/javascripts/environments/components/environment_rollback.js diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js index 96983a19568..96983a19568 100644 --- a/app/assets/javascripts/environments/components/environment_stop.js.es6 +++ b/app/assets/javascripts/environments/components/environment_stop.js diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 b/app/assets/javascripts/environments/components/environment_terminal_button.js index 481e0d15e7a..e86607e78f4 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 +++ b/app/assets/javascripts/environments/components/environment_terminal_button.js @@ -3,6 +3,7 @@ * Used in environments table. */ const Vue = require('vue'); +const terminalIconSvg = require('icons/_icon_terminal.svg'); module.exports = Vue.component('terminal-button-component', { props: { @@ -10,16 +11,16 @@ module.exports = Vue.component('terminal-button-component', { type: String, default: '', }, - terminalIconSvg: { - type: String, - default: '', - }, + }, + + data() { + return { terminalIconSvg }; }, template: ` <a class="btn terminal-button" :href="terminalPath"> - <span class="js-terminal-icon-container" v-html="terminalIconSvg"></span> + ${terminalIconSvg} </a> `, }); diff --git a/app/assets/javascripts/environments/components/environments_table.js.es6 b/app/assets/javascripts/environments/components/environments_table.js index 33ebca19f5d..4088d63be80 100644 --- a/app/assets/javascripts/environments/components/environments_table.js.es6 +++ b/app/assets/javascripts/environments/components/environments_table.js @@ -28,21 +28,6 @@ module.exports = Vue.component('environment-table-component', { required: false, default: false, }, - - commitIconSvg: { - type: String, - required: false, - }, - - playIconSvg: { - type: String, - required: false, - }, - - terminalIconSvg: { - type: String, - required: false, - }, }, template: ` @@ -63,10 +48,7 @@ module.exports = Vue.component('environment-table-component', { <tr is="environment-item" :model="model" :can-create-deployment="canCreateDeployment" - :can-read-environment="canReadEnvironment" - :play-icon-svg="playIconSvg" - :terminal-icon-svg="terminalIconSvg" - :commit-icon-svg="commitIconSvg"></tr> + :can-read-environment="canReadEnvironment"></tr> </template> </tbody> </table> diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js index 7bbba91bc10..7bbba91bc10 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6 b/app/assets/javascripts/environments/folder/environments_folder_bundle.js index d2ca465351a..d2ca465351a 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js.es6 +++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.js.es6 b/app/assets/javascripts/environments/folder/environments_folder_view.js index 53d52965758..2a9d0492d7a 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.js.es6 +++ b/app/assets/javascripts/environments/folder/environments_folder_view.js @@ -92,7 +92,7 @@ module.exports = Vue.component('environment-folder-view', { this.isLoading = true; - return service.all() + return service.get() .then(resp => ({ headers: resp.headers, body: resp.json(), diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js index 9cef335868e..effc6c4c838 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js @@ -5,7 +5,7 @@ class EnvironmentsService { this.environments = Vue.resource(endpoint); } - all() { + get() { return this.environments.get(); } } diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js index 15cd9bde08e..15cd9bde08e 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environments_store.js diff --git a/app/assets/javascripts/extensions/array.js.es6 b/app/assets/javascripts/extensions/array.js index f8256a8d26d..f8256a8d26d 100644 --- a/app/assets/javascripts/extensions/array.js.es6 +++ b/app/assets/javascripts/extensions/array.js diff --git a/app/assets/javascripts/extensions/custom_event.js.es6 b/app/assets/javascripts/extensions/custom_event.js index abedae4c1c7..abedae4c1c7 100644 --- a/app/assets/javascripts/extensions/custom_event.js.es6 +++ b/app/assets/javascripts/extensions/custom_event.js diff --git a/app/assets/javascripts/extensions/element.js.es6 b/app/assets/javascripts/extensions/element.js index 90ab79305a7..90ab79305a7 100644 --- a/app/assets/javascripts/extensions/element.js.es6 +++ b/app/assets/javascripts/extensions/element.js diff --git a/app/assets/javascripts/extensions/object.js.es6 b/app/assets/javascripts/extensions/object.js index 70a2d765abd..70a2d765abd 100644 --- a/app/assets/javascripts/extensions/object.js.es6 +++ b/app/assets/javascripts/extensions/object.js diff --git a/app/assets/javascripts/extensions/string.js b/app/assets/javascripts/extensions/string.js new file mode 100644 index 00000000000..fe23be0bbc1 --- /dev/null +++ b/app/assets/javascripts/extensions/string.js @@ -0,0 +1,2 @@ +require('string.prototype.codepointat'); +require('string.fromcodepoint'); diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js new file mode 100644 index 00000000000..47a40e28461 --- /dev/null +++ b/app/assets/javascripts/filterable_list.js @@ -0,0 +1,45 @@ +/** + * Makes search request for content when user types a value in the search input. + * Updates the html content of the page with the received one. + */ +export default class FilterableList { + constructor(form, filter, holder) { + this.filterForm = form; + this.listFilterElement = filter; + this.listHolderElement = holder; + } + + initSearch() { + this.debounceFilter = _.debounce(this.filterResults.bind(this), 500); + + this.listFilterElement.removeEventListener('input', this.debounceFilter); + this.listFilterElement.addEventListener('input', this.debounceFilter); + } + + filterResults() { + const form = this.filterForm; + const filterUrl = `${form.getAttribute('action')}?${$(form).serialize()}`; + + $(this.listHolderElement).fadeTo(250, 0.5); + + return $.ajax({ + url: form.getAttribute('action'), + data: $(form).serialize(), + type: 'GET', + dataType: 'json', + context: this, + complete() { + $(this.listHolderElement).fadeTo(250, 1); + }, + success(data) { + this.listHolderElement.innerHTML = data.html; + + // Change url so if user reload a page - search results are saved + return window.history.replaceState({ + page: filterUrl, + + }, document.title, filterUrl); + }, + }); + } +} diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js index 9e92d544bef..9e92d544bef 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_non_user.js index b3dc3e502c5..b3dc3e502c5 100644 --- a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_user.js index 7e9c6f74aa5..7e9c6f74aa5 100644 --- a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_user.js diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 b/app/assets/javascripts/filtered_search/dropdown_utils.js index de3fa116717..de3fa116717 100644 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js index dd565da507e..dd565da507e 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js index cecd3518ce3..cecd3518ce3 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js index bbafead0305..bbafead0305 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js index e6b53cd4b55..e6b53cd4b55 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js index 9bf1b1ced88..9bf1b1ced88 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js index 60d6658dc16..1bc04a5ad96 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.es6 +++ b/app/assets/javascripts/gfm_auto_complete.js @@ -1,5 +1,11 @@ /* eslint-disable func-names, space-before-function-paren, no-template-curly-in-string, comma-dangle, object-shorthand, quotes, dot-notation, no-else-return, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-param-reassign, no-useless-escape, prefer-template, consistent-return, wrap-iife, prefer-arrow-callback, camelcase, no-unused-vars, no-useless-return, vars-on-top, max-len */ +const emojiMap = require('emoji-map'); +const emojiAliases = require('emoji-aliases'); +const glEmoji = require('./behaviors/gl_emoji'); + +const glEmojiTag = glEmoji.glEmojiTag; + // Creates the variables for setting up GFM auto-completion (function() { if (window.gl == null) { @@ -26,7 +32,12 @@ }, // Emoji Emoji: { - template: '<li>${name} <img alt="${name}" height="20" src="${path}" width="20" /></li>' + templateFunction: function(name) { + return `<li> + ${name} ${glEmojiTag(name)} + </li> + `; + } }, // Team Members Members: { @@ -113,7 +124,7 @@ $input.atwho({ at: ':', displayTpl: function(value) { - return value.path != null ? this.Emoji.template : this.Loading.template; + return value && value.name ? this.Emoji.templateFunction(value.name) : this.Loading.template; }.bind(this), insertTpl: ':${name}:', skipSpecialCharacterTest: true, @@ -355,6 +366,8 @@ this.isLoadingData[at] = true; if (this.cachedData[at]) { this.loadData($input, at, this.cachedData[at]); + } else if (this.atTypeMap[at] === 'emojis') { + this.loadData($input, at, Object.keys(emojiMap).concat(Object.keys(emojiAliases))); } else { $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => { this.loadData($input, at, data); diff --git a/app/assets/javascripts/gl_field_error.js.es6 b/app/assets/javascripts/gl_field_error.js index f7cbecc0385..f7cbecc0385 100644 --- a/app/assets/javascripts/gl_field_error.js.es6 +++ b/app/assets/javascripts/gl_field_error.js diff --git a/app/assets/javascripts/gl_field_errors.js.es6 b/app/assets/javascripts/gl_field_errors.js index e9add115429..e9add115429 100644 --- a/app/assets/javascripts/gl_field_errors.js.es6 +++ b/app/assets/javascripts/gl_field_errors.js diff --git a/app/assets/javascripts/gl_form.js.es6 b/app/assets/javascripts/gl_form.js index 0b446ff364a..0b446ff364a 100644 --- a/app/assets/javascripts/gl_form.js.es6 +++ b/app/assets/javascripts/gl_form.js diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index ea5afbd9d29..a433c7ba8f0 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -1,4 +1,6 @@ +import Chart from 'vendor/Chart'; import ContributorsStatGraph from './stat_graph_contributors'; // export to global scope +window.Chart = Chart; window.ContributorsStatGraph = ContributorsStatGraph; diff --git a/app/assets/javascripts/group_label_subscription.js.es6 b/app/assets/javascripts/group_label_subscription.js index 15e695e81cf..15e695e81cf 100644 --- a/app/assets/javascripts/group_label_subscription.js.es6 +++ b/app/assets/javascripts/group_label_subscription.js diff --git a/app/assets/javascripts/groups_list.js b/app/assets/javascripts/groups_list.js index 0ef81e49444..56a8cbf6d03 100644 --- a/app/assets/javascripts/groups_list.js +++ b/app/assets/javascripts/groups_list.js @@ -1,47 +1,18 @@ +import FilterableList from './filterable_list'; + /** - * Based on project list search. * Makes search request for groups when user types a value in the search input. * Updates the html content of the page with the received one. */ export default class GroupsList { constructor() { - this.groupsListFilterElement = document.querySelector('.js-groups-list-filter'); - this.groupsListHolderElement = document.querySelector('.js-groups-list-holder'); - - this.initSearch(); - } - - initSearch() { - this.debounceFilter = _.debounce(this.filterResults.bind(this), 500); - - this.groupsListFilterElement.removeEventListener('input', this.debounceFilter); - this.groupsListFilterElement.addEventListener('input', this.debounceFilter); - } - - filterResults() { const form = document.querySelector('form#group-filter-form'); - const groupFilterUrl = `${form.getAttribute('action')}?${$(form).serialize()}`; - - $(this.groupsListHolderElement).fadeTo(250, 0.5); - - return $.ajax({ - url: form.getAttribute('action'), - data: $(form).serialize(), - type: 'GET', - dataType: 'json', - context: this, - complete() { - $(this.groupsListHolderElement).fadeTo(250, 1); - }, - success(data) { - this.groupsListHolderElement.innerHTML = data.html; - - // Change url so if user reload a page - search results are saved - return window.history.replaceState({ - page: groupFilterUrl, + const filter = document.querySelector('.js-groups-list-filter'); + const holder = document.querySelector('.js-groups-list-holder'); - }, document.title, groupFilterUrl); - }, - }); + if (form && filter && holder) { + const list = new FilterableList(form, filter, holder); + list.initSearch(); + } } } diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js index 3bfce32768a..3bfce32768a 100644 --- a/app/assets/javascripts/issuable.js.es6 +++ b/app/assets/javascripts/issuable.js diff --git a/app/assets/javascripts/issuable/issuable_bundle.js.es6 b/app/assets/javascripts/issuable/issuable_bundle.js index e927cc0077c..e927cc0077c 100644 --- a/app/assets/javascripts/issuable/issuable_bundle.js.es6 +++ b/app/assets/javascripts/issuable/issuable_bundle.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js index bf27fbac5d7..357b3487ca9 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js @@ -1,4 +1,6 @@ /* global Vue */ +import stopwatchSvg from 'icons/_icon_stopwatch.svg'; + require('../../../lib/utils/pretty_time'); (() => { @@ -11,7 +13,6 @@ require('../../../lib/utils/pretty_time'); 'showNoTimeTrackingState', 'timeSpentHumanReadable', 'timeEstimateHumanReadable', - 'stopwatchSvg', ], methods: { abbreviateTime(timeStr) { @@ -20,7 +21,7 @@ require('../../../lib/utils/pretty_time'); }, template: ` <div class='sidebar-collapsed-icon'> - <div v-html='stopwatchSvg'></div> + ${stopwatchSvg} <div class='time-tracking-collapsed-summary'> <div class='compare' v-if='showComparisonState'> <span>{{ abbreviateTime(timeSpentHumanReadable) }} / {{ abbreviateTime(timeEstimateHumanReadable) }}</span> diff --git a/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js index 750468c679b..750468c679b 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js index 309e9f2f9ef..309e9f2f9ef 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/help_state.js index d7ced6d7151..d7ced6d7151 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/help_state.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js index 1d2ca643b5b..1d2ca643b5b 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js index ed283fec3c3..ed283fec3c3 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js diff --git a/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js index b271ea83330..1fae2d62b14 100644 --- a/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js @@ -15,7 +15,6 @@ require('./comparison_pane'); 'time_spent', 'human_time_estimate', 'human_time_spent', - 'stopwatchSvg', 'docsUrl', ], data() { @@ -71,8 +70,7 @@ require('./comparison_pane'); :show-spent-only-state='showSpentOnlyState' :show-estimate-only-state='showEstimateOnlyState' :time-spent-human-readable='timeSpentHumanReadable' - :time-estimate-human-readable='timeEstimateHumanReadable' - :stopwatch-svg='stopwatchSvg'> + :time-estimate-human-readable='timeEstimateHumanReadable'> </time-tracking-collapsed-state> <div class='title hide-collapsed'> Time tracking diff --git a/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6 b/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js index 958a0cc6d50..0134b7cb6f3 100644 --- a/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6 +++ b/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js @@ -1,5 +1,7 @@ /* global Vue */ +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); require('./components/time_tracker'); require('../../smart_interval'); require('../../subbable_resource'); diff --git a/app/assets/javascripts/issues_bulk_assignment.js.es6 b/app/assets/javascripts/issues_bulk_assignment.js index e0ebd36a65c..e0ebd36a65c 100644 --- a/app/assets/javascripts/issues_bulk_assignment.js.es6 +++ b/app/assets/javascripts/issues_bulk_assignment.js diff --git a/app/assets/javascripts/label_manager.js.es6 b/app/assets/javascripts/label_manager.js index 38b2eb9ff14..38b2eb9ff14 100644 --- a/app/assets/javascripts/label_manager.js.es6 +++ b/app/assets/javascripts/label_manager.js diff --git a/app/assets/javascripts/lib/chart.js b/app/assets/javascripts/lib/chart.js deleted file mode 100644 index 9b011d89e93..00000000000 --- a/app/assets/javascripts/lib/chart.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren */ - -window.Chart = require('vendor/Chart'); diff --git a/app/assets/javascripts/lib/cropper.js b/app/assets/javascripts/lib/cropper.js deleted file mode 100644 index 7862c6797c3..00000000000 --- a/app/assets/javascripts/lib/cropper.js +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren */ - -/*= require cropper */ - -(function() { - -}).call(window); diff --git a/app/assets/javascripts/lib/d3.js b/app/assets/javascripts/lib/d3.js deleted file mode 100644 index a9dd32edbed..00000000000 --- a/app/assets/javascripts/lib/d3.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren */ - -window.d3 = require('d3'); diff --git a/app/assets/javascripts/lib/raphael.js b/app/assets/javascripts/lib/raphael.js deleted file mode 100644 index ebe1e2ae98d..00000000000 --- a/app/assets/javascripts/lib/raphael.js +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren */ - -/*= require raphael */ -/*= require g.raphael */ -/*= require g.bar */ - -(function() { - -}).call(window); diff --git a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js index 2955bda1a36..2955bda1a36 100644 --- a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 +++ b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js diff --git a/app/assets/javascripts/lib/utils/common_utils.js.es6 b/app/assets/javascripts/lib/utils/common_utils.js index 0242350f718..a1423b6fda5 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js.es6 +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -247,17 +247,6 @@ }); /** - * Transforms a DOMStringMap into a plain object. - * - * @param {DOMStringMap} DOMStringMapObject - * @returns {Object} - */ - w.gl.utils.DOMStringMapToObject = DOMStringMapObject => Object.keys(DOMStringMapObject).reduce((acc, element) => { - acc[element] = DOMStringMapObject[element]; - return acc; - }, {}); - - /** * Updates the search parameter of a URL given the parameter and values provided. * * If no search params are present we'll add it. diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js.es6 b/app/assets/javascripts/lib/utils/datetime_utility.js index 82dcbdc26c8..82dcbdc26c8 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js.es6 +++ b/app/assets/javascripts/lib/utils/datetime_utility.js diff --git a/app/assets/javascripts/lib/utils/pretty_time.js.es6 b/app/assets/javascripts/lib/utils/pretty_time.js index ae397212e55..ae397212e55 100644 --- a/app/assets/javascripts/lib/utils/pretty_time.js.es6 +++ b/app/assets/javascripts/lib/utils/pretty_time.js diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 579d322e3fb..2e5f8a09fc1 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -65,9 +65,10 @@ require('vendor/latinise'); } }; gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) { - var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine; + var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine; removedLastNewLine = false; removedFirstNewLine = false; + currentLineEmpty = false; // Remove the first newline if (selected.indexOf('\n') === 0) { @@ -82,7 +83,17 @@ require('vendor/latinise'); } selectedSplit = selected.split('\n'); - startChar = !wrap && textArea.selectionStart > 0 ? '\n' : ''; + + if (!wrap) { + lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n'); + + // Check whether the current line is empty or consists only of spaces(=handle as empty) + if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) { + currentLineEmpty = true; + } + } + + startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : ''; if (selectedSplit.length > 1 && (!wrap || (blockTag != null))) { if (blockTag != null) { @@ -142,9 +153,8 @@ require('vendor/latinise'); } }; gl.text.updateText = function(textArea, tag, blockTag, wrap) { - var $textArea, oldVal, selected, text; + var $textArea, selected, text; $textArea = $(textArea); - oldVal = $textArea.val(); textArea = $textArea.get(0); text = $textArea.val(); selected = this.selectedText(text, textArea); diff --git a/app/assets/javascripts/lib/utils/url_utility.js.es6 b/app/assets/javascripts/lib/utils/url_utility.js index 1bc81d2e4a4..1bc81d2e4a4 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js.es6 +++ b/app/assets/javascripts/lib/utils/url_utility.js diff --git a/app/assets/javascripts/lib/vue_resource.js.es6 b/app/assets/javascripts/lib/vue_resource.js.es6 deleted file mode 100644 index 49babdea2e1..00000000000 --- a/app/assets/javascripts/lib/vue_resource.js.es6 +++ /dev/null @@ -1,2 +0,0 @@ -window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/main.js index c51860d1604..ae4dd64424c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/main.js @@ -3,43 +3,45 @@ /* global Cookies */ /* global Flash */ /* global ConfirmDangerModal */ -/* global AwardsHandler */ /* global Aside */ -window.$ = window.jQuery = require('jquery'); -require('jquery-ujs'); -require('vendor/jquery.endless-scroll'); -require('vendor/jquery.highlight'); -require('vendor/jquery.waitforimages'); -require('vendor/jquery.caret'); -require('vendor/jquery.atwho'); -require('vendor/jquery.scrollTo'); -window.Cookies = require('js-cookie'); -require('./autosave'); -require('bootstrap/js/affix'); -require('bootstrap/js/alert'); -require('bootstrap/js/button'); -require('bootstrap/js/collapse'); -require('bootstrap/js/dropdown'); -require('bootstrap/js/modal'); -require('bootstrap/js/scrollspy'); -require('bootstrap/js/tab'); -require('bootstrap/js/transition'); -require('bootstrap/js/tooltip'); -require('bootstrap/js/popover'); -require('select2/select2.js'); -window.Pikaday = require('pikaday'); -window._ = require('underscore'); -window.Dropzone = require('dropzone'); -window.Sortable = require('vendor/Sortable'); +import jQuery from 'jquery'; +import _ from 'underscore'; +import Cookies from 'js-cookie'; +import Pikaday from 'pikaday'; +import Dropzone from 'dropzone'; +import Sortable from 'vendor/Sortable'; + +// libraries with import side-effects require('mousetrap'); require('mousetrap/plugins/pause/mousetrap-pause'); +require('vendor/fuzzaldrin-plus'); +require('es6-promise').polyfill(); + +// extensions +require('./extensions/string'); +require('./extensions/array'); +require('./extensions/custom_event'); +require('./extensions/element'); +require('./extensions/jquery'); +require('./extensions/object'); +require('es6-promise').polyfill(); + +// expose common libraries as globals (TODO: remove these) +window.jQuery = jQuery; +window.$ = jQuery; +window._ = _; +window.Cookies = Cookies; +window.Pikaday = Pikaday; +window.Dropzone = Dropzone; +window.Sortable = Sortable; + +// shortcuts require('./shortcuts'); require('./shortcuts_navigation'); require('./shortcuts_dashboard_navigation'); require('./shortcuts_issuable'); require('./shortcuts_network'); -require('vendor/jquery.nicescroll'); // behaviors require('./behaviors/autosize'); @@ -47,6 +49,7 @@ require('./behaviors/details_behavior'); require('./behaviors/quick_submit'); require('./behaviors/requires_input'); require('./behaviors/toggler_behavior'); +require('./behaviors/bind_in_out'); // blob require('./blob/blob_ci_yaml'); @@ -67,13 +70,6 @@ require('./templates/issuable_template_selectors'); require('./commit/file.js'); require('./commit/image_file.js'); -// extensions -require('./extensions/array'); -require('./extensions/custom_event'); -require('./extensions/element'); -require('./extensions/jquery'); -require('./extensions/object'); - // lib/utils require('./lib/utils/animate'); require('./lib/utils/bootstrap_linked_tabs'); @@ -105,7 +101,7 @@ require('./ajax_loading_spinner'); require('./api'); require('./aside'); require('./autosave'); -require('./awards_handler'); +const AwardsHandler = require('./awards_handler'); require('./breakpoints'); require('./broadcast_message'); require('./build'); @@ -210,9 +206,6 @@ require('./visibility_select'); require('./wikis'); require('./zen_mode'); -require('vendor/fuzzaldrin-plus'); -require('es6-promise').polyfill(); - (function () { document.addEventListener('beforeunload', function () { // Unbind scroll events @@ -290,7 +283,7 @@ require('es6-promise').polyfill(); $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; $body.tooltip({ selector: '.has-tooltip, [data-toggle="tooltip"]', - placement: function (_, el) { + placement: function (tip, el) { return $(el).data('placement') || 'bottom'; } }); diff --git a/app/assets/javascripts/member_expiration_date.js.es6 b/app/assets/javascripts/member_expiration_date.js index 129d2dc5f0a..129d2dc5f0a 100644 --- a/app/assets/javascripts/member_expiration_date.js.es6 +++ b/app/assets/javascripts/member_expiration_date.js diff --git a/app/assets/javascripts/members.js.es6 b/app/assets/javascripts/members.js index e3f367a11eb..e3f367a11eb 100644 --- a/app/assets/javascripts/members.js.es6 +++ b/app/assets/javascripts/members.js diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6 b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js index c7e78fed8fe..c7e78fed8fe 100644 --- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6 +++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js diff --git a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6 b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js index 240c8f98932..240c8f98932 100644 --- a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6 +++ b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js diff --git a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6 b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js index 97753c50b60..97753c50b60 100644 --- a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6 +++ b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflict_service.js index c012b77e0bf..c012b77e0bf 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6 +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_service.js diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index 74587df22c5..74587df22c5 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6 +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js index 653e52fb6bf..653e52fb6bf 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 +++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js diff --git a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6 b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js index 53e000d7e9e..53e000d7e9e 100644 --- a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6 +++ b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js diff --git a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6 b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js index 0f475f62ee6..0f475f62ee6 100644 --- a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6 +++ b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js index 190336dbd20..190336dbd20 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js index 00c6c050612..5f1bd474a0c 100644 --- a/app/assets/javascripts/merge_request_widget.js.es6 +++ b/app/assets/javascripts/merge_request_widget.js @@ -129,8 +129,9 @@ require('./smart_interval'); }; MergeRequestWidget.prototype.getMergeStatus = function() { - return $.get(this.opts.merge_check_url, function(data) { + return $.get(this.opts.merge_check_url, (data) => { var $html = $(data); + this.updateMergeButton(this.status, this.hasCi, $html); $('.mr-widget-body').replaceWith($html.find('.mr-widget-body')); $('.mr-widget-footer').replaceWith($html.find('.mr-widget-footer')); }); @@ -154,9 +155,9 @@ require('./smart_interval'); return $.getJSON(this.opts.ci_status_url, (function(_this) { return function(data) { var message, status, title; - if (!data.status) { - return; - } + _this.status = data.status; + _this.hasCi = data.has_ci; + _this.updateMergeButton(_this.status, _this.hasCi); if (data.environments && data.environments.length) _this.renderEnvironments(data.environments); if (data.status !== _this.opts.ci_status || data.sha !== _this.opts.ci_sha || @@ -232,36 +233,45 @@ require('./smart_interval'); return; } $('.ci_widget').hide(); - allowed_states = ["failed", "canceled", "running", "pending", "success", "success_with_warnings", "skipped", "not_found"]; - if (indexOf.call(allowed_states, state) !== -1) { - $('.ci_widget.ci-' + state).show(); + $('.ci_widget.ci-' + state).show(); + + this.initMiniPipelineGraph(); + }; + + MergeRequestWidget.prototype.showCICoverage = function(coverage) { + var text = `Coverage ${coverage}%`; + return $('.ci_widget:visible .ci-coverage').text(text); + }; + + MergeRequestWidget.prototype.updateMergeButton = function(state, hasCi, $html) { + const allowed_states = ["failed", "canceled", "running", "pending", "success", "success_with_warnings", "skipped", "not_found"]; + let stateClass = 'btn-danger'; + if (!hasCi) { + stateClass = 'btn-create'; + } else if (indexOf.call(allowed_states, state) !== -1) { switch (state) { case "failed": case "canceled": case "not_found": - this.setMergeButtonClass('btn-danger'); + stateClass = 'btn-danger'; break; case "running": - this.setMergeButtonClass('btn-info'); + stateClass = 'btn-info'; break; case "success": case "success_with_warnings": - this.setMergeButtonClass('btn-create'); + stateClass = 'btn-create'; } } else { $('.ci_widget.ci-error').show(); - this.setMergeButtonClass('btn-danger'); + stateClass = 'btn-danger'; } - }; - MergeRequestWidget.prototype.showCICoverage = function(coverage) { - var text; - text = 'Coverage ' + coverage + '%'; - return $('.ci_widget:visible .ci-coverage').text(text); + this.setMergeButtonClass(stateClass, $html); }; - MergeRequestWidget.prototype.setMergeButtonClass = function(css_class) { - return $('.js-merge-button,.accept-action .dropdown-toggle').removeClass('btn-danger btn-info btn-create').addClass(css_class); + MergeRequestWidget.prototype.setMergeButtonClass = function(css_class, $html = $('.mr-state-widget')) { + return $html.find('.js-merge-button').removeClass('btn-danger btn-info btn-create').addClass(css_class); }; MergeRequestWidget.prototype.updatePipelineUrls = function(id) { diff --git a/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 b/app/assets/javascripts/merge_request_widget/ci_bundle.js index 547dfa9e677..21d7c3e168e 100644 --- a/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 +++ b/app/assets/javascripts/merge_request_widget/ci_bundle.js @@ -15,14 +15,14 @@ }); $(document) - .off('click', '.accept_merge_request') - .on('click', '.accept_merge_request', () => { - $('.js-merge-button').html('<i class="fa fa-spinner fa-spin"></i> Merge in progress'); + .off('click', '.accept-merge-request') + .on('click', '.accept-merge-request', () => { + $('.js-merge-button, .js-merge-when-pipeline-succeeds-button').html('<i class="fa fa-spinner fa-spin"></i> Merge in progress'); }); $(document) - .off('click', '.merge_when_pipeline_succeeds') - .on('click', '.merge_when_pipeline_succeeds', () => { + .off('click', '.merge-when-pipeline-succeeds') + .on('click', '.merge-when-pipeline-succeeds', () => { $('#merge_when_pipeline_succeeds').val('1'); }); diff --git a/app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6 b/app/assets/javascripts/mini_pipeline_graph_dropdown.js index 2145e531331..2145e531331 100644 --- a/app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6 +++ b/app/assets/javascripts/mini_pipeline_graph_dropdown.js diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js index 43dc9838977..5aad3908eb6 100644 --- a/app/assets/javascripts/network/branch_graph.js +++ b/app/assets/javascripts/network/branch_graph.js @@ -1,424 +1,347 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, new-cap, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */ -/* global Raphael */ +/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len */ -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; +import Raphael from './raphael'; - this.BranchGraph = (function() { - function BranchGraph(element1, options1) { - this.element = element1; - this.options = options1; - this.scrollTop = bind(this.scrollTop, this); - this.scrollBottom = bind(this.scrollBottom, this); - this.scrollRight = bind(this.scrollRight, this); - this.scrollLeft = bind(this.scrollLeft, this); - this.scrollUp = bind(this.scrollUp, this); - this.scrollDown = bind(this.scrollDown, this); - this.preparedCommits = {}; - this.mtime = 0; - this.mspace = 0; - this.parents = {}; - this.colors = ["#000"]; - this.offsetX = 150; - this.offsetY = 20; - this.unitTime = 30; - this.unitSpace = 10; - this.prev_start = -1; - this.load(); - } - - BranchGraph.prototype.load = function() { - return $.ajax({ - url: this.options.url, - method: "get", - dataType: "json", - success: $.proxy(function(data) { - $(".loading", this.element).hide(); - this.prepareData(data.days, data.commits); - return this.buildGraph(); - }, this) - }); - }; +export default (function() { + function BranchGraph(element1, options1) { + this.element = element1; + this.options = options1; + this.scrollTop = this.scrollTop.bind(this); + this.scrollBottom = this.scrollBottom.bind(this); + this.scrollRight = this.scrollRight.bind(this); + this.scrollLeft = this.scrollLeft.bind(this); + this.scrollUp = this.scrollUp.bind(this); + this.scrollDown = this.scrollDown.bind(this); + this.preparedCommits = {}; + this.mtime = 0; + this.mspace = 0; + this.parents = {}; + this.colors = ["#000"]; + this.offsetX = 150; + this.offsetY = 20; + this.unitTime = 30; + this.unitSpace = 10; + this.prev_start = -1; + this.load(); + } - BranchGraph.prototype.prepareData = function(days, commits) { - var c, ch, cw, j, len, ref; - this.days = days; - this.commits = commits; - this.collectParents(); - this.graphHeight = $(this.element).height(); - this.graphWidth = $(this.element).width(); - ch = Math.max(this.graphHeight, this.offsetY + this.unitTime * this.mtime + 150); - cw = Math.max(this.graphWidth, this.offsetX + this.unitSpace * this.mspace + 300); - this.r = Raphael(this.element.get(0), cw, ch); - this.top = this.r.set(); - this.barHeight = Math.max(this.graphHeight, this.unitTime * this.days.length + 320); - ref = this.commits; - for (j = 0, len = ref.length; j < len; j += 1) { - c = ref[j]; - if (c.id in this.parents) { - c.isParent = true; - } - this.preparedCommits[c.id] = c; - this.markCommit(c); - } - return this.collectColors(); - }; - - BranchGraph.prototype.collectParents = function() { - var c, j, len, p, ref, results; - ref = this.commits; - results = []; - for (j = 0, len = ref.length; j < len; j += 1) { - c = ref[j]; - this.mtime = Math.max(this.mtime, c.time); - this.mspace = Math.max(this.mspace, c.space); - results.push((function() { - var l, len1, ref1, results1; - ref1 = c.parents; - results1 = []; - for (l = 0, len1 = ref1.length; l < len1; l += 1) { - p = ref1[l]; - this.parents[p[0]] = true; - results1.push(this.mspace = Math.max(this.mspace, p[1])); - } - return results1; - }).call(this)); - } - return results; - }; + BranchGraph.prototype.load = function() { + return $.ajax({ + url: this.options.url, + method: "get", + dataType: "json", + success: $.proxy(function(data) { + $(".loading", this.element).hide(); + this.prepareData(data.days, data.commits); + return this.buildGraph(); + }, this) + }); + }; - BranchGraph.prototype.collectColors = function() { - var k, results; - k = 0; - results = []; - while (k < this.mspace) { - this.colors.push(Raphael.getColor(.8)); - // Skipping a few colors in the spectrum to get more contrast between colors - Raphael.getColor(); - Raphael.getColor(); - results.push(k += 1); + BranchGraph.prototype.prepareData = function(days, commits) { + var c, ch, cw, j, len, ref; + this.days = days; + this.commits = commits; + this.collectParents(); + this.graphHeight = $(this.element).height(); + this.graphWidth = $(this.element).width(); + ch = Math.max(this.graphHeight, this.offsetY + this.unitTime * this.mtime + 150); + cw = Math.max(this.graphWidth, this.offsetX + this.unitSpace * this.mspace + 300); + this.r = Raphael(this.element.get(0), cw, ch); + this.top = this.r.set(); + this.barHeight = Math.max(this.graphHeight, this.unitTime * this.days.length + 320); + ref = this.commits; + for (j = 0, len = ref.length; j < len; j += 1) { + c = ref[j]; + if (c.id in this.parents) { + c.isParent = true; } - return results; - }; + this.preparedCommits[c.id] = c; + this.markCommit(c); + } + return this.collectColors(); + }; - BranchGraph.prototype.buildGraph = function() { - var cuday, cumonth, day, j, len, mm, r, ref; - r = this.r; - cuday = 0; - cumonth = ""; - r.rect(0, 0, 40, this.barHeight).attr({ - fill: "#222" - }); - r.rect(40, 0, 30, this.barHeight).attr({ - fill: "#444" - }); - ref = this.days; - for (mm = j = 0, len = ref.length; j < len; mm = (j += 1)) { - day = ref[mm]; - if (cuday !== day[0] || cumonth !== day[1]) { - // Dates - r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({ - font: "12px Monaco, monospace", - fill: "#BBB" - }); - cuday = day[0]; - } - if (cumonth !== day[1]) { - // Months - r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({ - font: "12px Monaco, monospace", - fill: "#EEE" - }); - cumonth = day[1]; + BranchGraph.prototype.collectParents = function() { + var c, j, len, p, ref, results; + ref = this.commits; + results = []; + for (j = 0, len = ref.length; j < len; j += 1) { + c = ref[j]; + this.mtime = Math.max(this.mtime, c.time); + this.mspace = Math.max(this.mspace, c.space); + results.push((function() { + var l, len1, ref1, results1; + ref1 = c.parents; + results1 = []; + for (l = 0, len1 = ref1.length; l < len1; l += 1) { + p = ref1[l]; + this.parents[p[0]] = true; + results1.push(this.mspace = Math.max(this.mspace, p[1])); } - } - this.renderPartialGraph(); - return this.bindEvents(); - }; + return results1; + }).call(this)); + } + return results; + }; - BranchGraph.prototype.renderPartialGraph = function() { - var commit, end, i, isGraphEdge, start, x, y; - start = Math.floor((this.element.scrollTop() - this.offsetY) / this.unitTime) - 10; - if (start < 0) { - isGraphEdge = true; - start = 0; + BranchGraph.prototype.collectColors = function() { + var k, results; + k = 0; + results = []; + while (k < this.mspace) { + this.colors.push(Raphael.getColor(.8)); + // Skipping a few colors in the spectrum to get more contrast between colors + Raphael.getColor(); + Raphael.getColor(); + results.push(k += 1); + } + return results; + }; + + BranchGraph.prototype.buildGraph = function() { + var cuday, cumonth, day, j, len, mm, r, ref; + r = this.r; + cuday = 0; + cumonth = ""; + r.rect(0, 0, 40, this.barHeight).attr({ + fill: "#222" + }); + r.rect(40, 0, 30, this.barHeight).attr({ + fill: "#444" + }); + ref = this.days; + for (mm = j = 0, len = ref.length; j < len; mm = (j += 1)) { + day = ref[mm]; + if (cuday !== day[0] || cumonth !== day[1]) { + // Dates + r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({ + font: "12px Monaco, monospace", + fill: "#BBB" + }); + cuday = day[0]; } - end = start + 40; - if (this.commits.length < end) { - isGraphEdge = true; - end = this.commits.length; + if (cumonth !== day[1]) { + // Months + r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({ + font: "12px Monaco, monospace", + fill: "#EEE" + }); + cumonth = day[1]; } - if (this.prev_start === -1 || Math.abs(this.prev_start - start) > 10 || isGraphEdge) { - i = start; - this.prev_start = start; - while (i < end) { - commit = this.commits[i]; - i += 1; - if (commit.hasDrawn !== true) { - x = this.offsetX + this.unitSpace * (this.mspace - commit.space); - y = this.offsetY + this.unitTime * commit.time; - this.drawDot(x, y, commit); - this.drawLines(x, y, commit); - this.appendLabel(x, y, commit); - this.appendAnchor(x, y, commit); - commit.hasDrawn = true; - } + } + this.renderPartialGraph(); + return this.bindEvents(); + }; + + BranchGraph.prototype.renderPartialGraph = function() { + var commit, end, i, isGraphEdge, start, x, y; + start = Math.floor((this.element.scrollTop() - this.offsetY) / this.unitTime) - 10; + if (start < 0) { + isGraphEdge = true; + start = 0; + } + end = start + 40; + if (this.commits.length < end) { + isGraphEdge = true; + end = this.commits.length; + } + if (this.prev_start === -1 || Math.abs(this.prev_start - start) > 10 || isGraphEdge) { + i = start; + this.prev_start = start; + while (i < end) { + commit = this.commits[i]; + i += 1; + if (commit.hasDrawn !== true) { + x = this.offsetX + this.unitSpace * (this.mspace - commit.space); + y = this.offsetY + this.unitTime * commit.time; + this.drawDot(x, y, commit); + this.drawLines(x, y, commit); + this.appendLabel(x, y, commit); + this.appendAnchor(x, y, commit); + commit.hasDrawn = true; } - return this.top.toFront(); } - }; - - BranchGraph.prototype.bindEvents = function() { - var element; - element = this.element; - return $(element).scroll((function(_this) { - return function(event) { - return _this.renderPartialGraph(); - }; - })(this)); - }; - - BranchGraph.prototype.scrollDown = function() { - this.element.scrollTop(this.element.scrollTop() + 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollUp = function() { - this.element.scrollTop(this.element.scrollTop() - 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollLeft = function() { - this.element.scrollLeft(this.element.scrollLeft() - 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollRight = function() { - this.element.scrollLeft(this.element.scrollLeft() + 50); - return this.renderPartialGraph(); - }; - - BranchGraph.prototype.scrollBottom = function() { - return this.element.scrollTop(this.element.find('svg').height()); - }; + return this.top.toFront(); + } + }; - BranchGraph.prototype.scrollTop = function() { - return this.element.scrollTop(0); - }; + BranchGraph.prototype.bindEvents = function() { + var element; + element = this.element; + return $(element).scroll((function(_this) { + return function(event) { + return _this.renderPartialGraph(); + }; + })(this)); + }; - BranchGraph.prototype.appendLabel = function(x, y, commit) { - var label, r, rect, shortrefs, text, textbox, triangle; - if (!commit.refs) { - return; - } - r = this.r; - shortrefs = commit.refs; - // Truncate if longer than 15 chars - if (shortrefs.length > 17) { - shortrefs = shortrefs.substr(0, 15) + "…"; - } - text = r.text(x + 4, y, shortrefs).attr({ - "text-anchor": "start", - font: "10px Monaco, monospace", - fill: "#FFF", - title: commit.refs - }); - textbox = text.getBBox(); - // Create rectangle based on the size of the textbox - rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - label = r.set(rect, text); - label.transform(["t", -rect.getBBox().width - 15, 0]); - // Set text to front - return text.toFront(); - }; + BranchGraph.prototype.scrollDown = function() { + this.element.scrollTop(this.element.scrollTop() + 50); + return this.renderPartialGraph(); + }; - BranchGraph.prototype.appendAnchor = function(x, y, commit) { - var anchor, options, r, top; - r = this.r; - top = this.top; - options = this.options; - anchor = r.circle(x, y, 10).attr({ - fill: "#000", - opacity: 0, - cursor: "pointer" - }).click(function() { - return window.open(options.commit_url.replace("%s", commit.id), "_blank"); - }).hover(function() { - this.tooltip = r.commitTooltip(x + 5, y, commit); - return top.push(this.tooltip.insertBefore(this)); - }, function() { - return this.tooltip && this.tooltip.remove() && delete this.tooltip; - }); - return top.push(anchor); - }; + BranchGraph.prototype.scrollUp = function() { + this.element.scrollTop(this.element.scrollTop() - 50); + return this.renderPartialGraph(); + }; - BranchGraph.prototype.drawDot = function(x, y, commit) { - var avatar_box_x, avatar_box_y, r; - r = this.r; - r.circle(x, y, 3).attr({ - fill: this.colors[commit.space], - stroke: "none" - }); - avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10; - avatar_box_y = y - 10; - r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({ - stroke: this.colors[commit.space], - "stroke-width": 2 - }); - r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20); - return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({ - "text-anchor": "start", - font: "14px Monaco, monospace" - }); - }; + BranchGraph.prototype.scrollLeft = function() { + this.element.scrollLeft(this.element.scrollLeft() - 50); + return this.renderPartialGraph(); + }; - BranchGraph.prototype.drawLines = function(x, y, commit) { - var arrow, color, i, j, len, offset, parent, parentCommit, parentX1, parentX2, parentY, r, ref, results, route; - r = this.r; - ref = commit.parents; - results = []; - for (i = j = 0, len = ref.length; j < len; i = (j += 1)) { - parent = ref[i]; - parentCommit = this.preparedCommits[parent[0]]; - parentY = this.offsetY + this.unitTime * parentCommit.time; - parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space); - parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]); - // Set line color - if (parentCommit.space <= commit.space) { - color = this.colors[commit.space]; - } else { - color = this.colors[parentCommit.space]; - } - // Build line shape - if (parent[1] === commit.space) { - offset = [0, 5]; - arrow = "l-2,5,4,0,-2,-5,0,5"; - } else if (parent[1] < commit.space) { - offset = [3, 3]; - arrow = "l5,0,-2,4,-3,-4,4,2"; - } else { - offset = [-3, 3]; - arrow = "l-5,0,2,4,3,-4,-4,2"; - } - // Start point - route = ["M", x + offset[0], y + offset[1]]; - // Add arrow if not first parent - if (i > 0) { - route.push(arrow); - } - // Circumvent if overlap - if (commit.space !== parentCommit.space || commit.space !== parent[1]) { - route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5); - } - // End point - route.push("L", parentX1, parentY); - results.push(r.path(route).attr({ - stroke: color, - "stroke-width": 2 - })); - } - return results; - }; + BranchGraph.prototype.scrollRight = function() { + this.element.scrollLeft(this.element.scrollLeft() + 50); + return this.renderPartialGraph(); + }; - BranchGraph.prototype.markCommit = function(commit) { - var r, x, y; - if (commit.id === this.options.commit_id) { - r = this.r; - x = this.offsetX + this.unitSpace * (this.mspace - commit.space); - y = this.offsetY + this.unitTime * commit.time; - r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({ - fill: "#000", - "fill-opacity": .5, - stroke: "none" - }); - // Displayed in the center - return this.element.scrollTop(y - this.graphHeight / 2); - } - }; + BranchGraph.prototype.scrollBottom = function() { + return this.element.scrollTop(this.element.find('svg').height()); + }; - return BranchGraph; - })(); + BranchGraph.prototype.scrollTop = function() { + return this.element.scrollTop(0); + }; - Raphael.prototype.commitTooltip = function(x, y, commit) { - var boxHeight, boxWidth, icon, idText, messageText, nameText, rect, textSet, tooltip; - boxWidth = 300; - boxHeight = 200; - icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20); - nameText = this.text(x + 25, y + 10, commit.author.name); - idText = this.text(x, y + 35, commit.id); - messageText = this.text(x, y + 50, commit.message.replace(/\r?\n/g, " \n ")); - textSet = this.set(icon, nameText, idText, messageText).attr({ + BranchGraph.prototype.appendLabel = function(x, y, commit) { + var label, r, rect, shortrefs, text, textbox, triangle; + if (!commit.refs) { + return; + } + r = this.r; + shortrefs = commit.refs; + // Truncate if longer than 15 chars + if (shortrefs.length > 17) { + shortrefs = shortrefs.substr(0, 15) + "…"; + } + text = r.text(x + 4, y, shortrefs).attr({ "text-anchor": "start", - font: "12px Monaco, monospace" - }); - nameText.attr({ - font: "14px Arial", - "font-weight": "bold" + font: "10px Monaco, monospace", + fill: "#FFF", + title: commit.refs }); - idText.attr({ - fill: "#AAA" + textbox = text.getBBox(); + // Create rectangle based on the size of the textbox + rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" }); - messageText.node.style["white-space"] = "pre"; - this.textWrap(messageText, boxWidth - 50); - rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ - fill: "#FFF", - stroke: "#000", - "stroke-linecap": "round", - "stroke-width": 2 + triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" }); - tooltip = this.set(rect, textSet); - rect.attr({ - height: tooltip.getBBox().height + 10, - width: tooltip.getBBox().width + 10 + label = r.set(rect, text); + label.transform(["t", -rect.getBBox().width - 15, 0]); + // Set text to front + return text.toFront(); + }; + + BranchGraph.prototype.appendAnchor = function(x, y, commit) { + var anchor, options, r, top; + r = this.r; + top = this.top; + options = this.options; + anchor = r.circle(x, y, 10).attr({ + fill: "#000", + opacity: 0, + cursor: "pointer" + }).click(function() { + return window.open(options.commit_url.replace("%s", commit.id), "_blank"); + }).hover(function() { + this.tooltip = r.commitTooltip(x + 5, y, commit); + return top.push(this.tooltip.insertBefore(this)); + }, function() { + return this.tooltip && this.tooltip.remove() && delete this.tooltip; }); - tooltip.transform(["t", 20, 20]); - return tooltip; + return top.push(anchor); }; - Raphael.prototype.textWrap = function(t, width) { - var abc, b, content, h, j, len, letterWidth, s, word, words, x; - content = t.attr("text"); - abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - t.attr({ - text: abc + BranchGraph.prototype.drawDot = function(x, y, commit) { + var avatar_box_x, avatar_box_y, r; + r = this.r; + r.circle(x, y, 3).attr({ + fill: this.colors[commit.space], + stroke: "none" }); - letterWidth = t.getBBox().width / abc.length; - t.attr({ - text: content + avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10; + avatar_box_y = y - 10; + r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({ + stroke: this.colors[commit.space], + "stroke-width": 2 }); - words = content.split(" "); - x = 0; - s = []; - for (j = 0, len = words.length; j < len; j += 1) { - word = words[j]; - if (x + (word.length * letterWidth) > width) { - s.push("\n"); - x = 0; + r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20); + return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({ + "text-anchor": "start", + font: "14px Monaco, monospace" + }); + }; + + BranchGraph.prototype.drawLines = function(x, y, commit) { + var arrow, color, i, j, len, offset, parent, parentCommit, parentX1, parentX2, parentY, r, ref, results, route; + r = this.r; + ref = commit.parents; + results = []; + for (i = j = 0, len = ref.length; j < len; i = (j += 1)) { + parent = ref[i]; + parentCommit = this.preparedCommits[parent[0]]; + parentY = this.offsetY + this.unitTime * parentCommit.time; + parentX1 = this.offsetX + this.unitSpace * (this.mspace - parentCommit.space); + parentX2 = this.offsetX + this.unitSpace * (this.mspace - parent[1]); + // Set line color + if (parentCommit.space <= commit.space) { + color = this.colors[commit.space]; + } else { + color = this.colors[parentCommit.space]; } - if (word === "\n") { - s.push("\n"); - x = 0; + // Build line shape + if (parent[1] === commit.space) { + offset = [0, 5]; + arrow = "l-2,5,4,0,-2,-5,0,5"; + } else if (parent[1] < commit.space) { + offset = [3, 3]; + arrow = "l5,0,-2,4,-3,-4,4,2"; } else { - s.push(word + " "); - x += word.length * letterWidth; + offset = [-3, 3]; + arrow = "l-5,0,2,4,3,-4,-4,2"; + } + // Start point + route = ["M", x + offset[0], y + offset[1]]; + // Add arrow if not first parent + if (i > 0) { + route.push(arrow); + } + // Circumvent if overlap + if (commit.space !== parentCommit.space || commit.space !== parent[1]) { + route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5); } + // End point + route.push("L", parentX1, parentY); + results.push(r.path(route).attr({ + stroke: color, + "stroke-width": 2 + })); + } + return results; + }; + + BranchGraph.prototype.markCommit = function(commit) { + var r, x, y; + if (commit.id === this.options.commit_id) { + r = this.r; + x = this.offsetX + this.unitSpace * (this.mspace - commit.space); + y = this.offsetY + this.unitTime * commit.time; + r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({ + fill: "#000", + "fill-opacity": .5, + stroke: "none" + }); + // Displayed in the center + return this.element.scrollTop(y - this.graphHeight / 2); } - t.attr({ - text: s.join("").trim() - }); - b = t.getBBox(); - h = Math.abs(b.y2) + 1; - return t.attr({ - y: h - }); }; -}).call(window); + + return BranchGraph; +})(); diff --git a/app/assets/javascripts/network/network.js b/app/assets/javascripts/network/network.js index 8e7027b44e7..a3fd22aff2a 100644 --- a/app/assets/javascripts/network/network.js +++ b/app/assets/javascripts/network/network.js @@ -1,20 +1,19 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, quote-props, prefer-template, comma-dangle, max-len */ -/* global BranchGraph */ -(function() { - this.Network = (function() { - function Network(opts) { - var vph; - $("#filter_ref").click(function() { - return $(this).closest('form').submit(); - }); - this.branch_graph = new BranchGraph($(".network-graph"), opts); - vph = $(window).height() - 250; - $('.network-graph').css({ - 'height': vph + 'px' - }); - } +import BranchGraph from './branch_graph'; - return Network; - })(); -}).call(window); +export default (function() { + function Network(opts) { + var vph; + $("#filter_ref").click(function() { + return $(this).closest('form').submit(); + }); + this.branch_graph = new BranchGraph($(".network-graph"), opts); + vph = $(window).height() - 250; + $('.network-graph').css({ + 'height': vph + 'px' + }); + } + + return Network; +})(); diff --git a/app/assets/javascripts/network/network_bundle.js b/app/assets/javascripts/network/network_bundle.js index e5947586583..8aae2ad201c 100644 --- a/app/assets/javascripts/network/network_bundle.js +++ b/app/assets/javascripts/network/network_bundle.js @@ -1,21 +1,17 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, camelcase, comma-dangle, consistent-return, max-len */ -/* global Network */ /* global ShortcutsNetwork */ -require('./branch_graph'); -require('./network'); +import Network from './network'; -(function() { - $(function() { - if (!$(".network-graph").length) return; +$(function() { + if (!$(".network-graph").length) return; - var network_graph; - network_graph = new Network({ - url: $(".network-graph").attr('data-url'), - commit_url: $(".network-graph").attr('data-commit-url'), - ref: $(".network-graph").attr('data-ref'), - commit_id: $(".network-graph").attr('data-commit-id') - }); - return new ShortcutsNetwork(network_graph.branch_graph); + var network_graph; + network_graph = new Network({ + url: $(".network-graph").attr('data-url'), + commit_url: $(".network-graph").attr('data-commit-url'), + ref: $(".network-graph").attr('data-ref'), + commit_id: $(".network-graph").attr('data-commit-id') }); -}).call(window); + return new ShortcutsNetwork(network_graph.branch_graph); +}); diff --git a/app/assets/javascripts/network/raphael.js b/app/assets/javascripts/network/raphael.js new file mode 100644 index 00000000000..09dcf716148 --- /dev/null +++ b/app/assets/javascripts/network/raphael.js @@ -0,0 +1,74 @@ +import Raphael from 'raphael/raphael'; + +Raphael.prototype.commitTooltip = function commitTooltip(x, y, commit) { + const boxWidth = 300; + const icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20); + const nameText = this.text(x + 25, y + 10, commit.author.name); + const idText = this.text(x, y + 35, commit.id); + const messageText = this.text(x, y + 50, commit.message.replace(/\r?\n/g, ' \n ')); + const textSet = this.set(icon, nameText, idText, messageText).attr({ + 'text-anchor': 'start', + font: '12px Monaco, monospace', + }); + nameText.attr({ + font: '14px Arial', + 'font-weight': 'bold', + }); + idText.attr({ + fill: '#AAA', + }); + messageText.node.style['white-space'] = 'pre'; + this.textWrap(messageText, boxWidth - 50); + const rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ + fill: '#FFF', + stroke: '#000', + 'stroke-linecap': 'round', + 'stroke-width': 2, + }); + const tooltip = this.set(rect, textSet); + rect.attr({ + height: tooltip.getBBox().height + 10, + width: tooltip.getBBox().width + 10, + }); + tooltip.transform(['t', 20, 20]); + return tooltip; +}; + +Raphael.prototype.textWrap = function testWrap(t, width) { + const content = t.attr('text'); + const abc = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + t.attr({ + text: abc, + }); + const letterWidth = t.getBBox().width / abc.length; + t.attr({ + text: content, + }); + const words = content.split(' '); + let x = 0; + const s = []; + for (let j = 0, len = words.length; j < len; j += 1) { + const word = words[j]; + if (x + (word.length * letterWidth) > width) { + s.push('\n'); + x = 0; + } + if (word === '\n') { + s.push('\n'); + x = 0; + } else { + s.push(`${word} `); + x += word.length * letterWidth; + } + } + t.attr({ + text: s.join('').trim(), + }); + const b = t.getBBox(); + const h = Math.abs(b.y2) + 1; + return t.attr({ + y: h, + }); +}; + +export default Raphael; diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 47fa0f2eb96..df7a7d2a459 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -198,7 +198,7 @@ require('./task_list'); this.refreshing = true; return $.ajax({ url: this.notes_url, - data: "last_fetched_at=" + this.last_fetched_at, + headers: { "X-Last-Fetched-At": this.last_fetched_at }, dataType: "json", success: (function(_this) { return function(data) { diff --git a/app/assets/javascripts/pager.js.es6 b/app/assets/javascripts/pager.js index e35cf6d295e..e35cf6d295e 100644 --- a/app/assets/javascripts/pager.js.es6 +++ b/app/assets/javascripts/pager.js diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js index 9203abefbbc..9203abefbbc 100644 --- a/app/assets/javascripts/pipelines.js.es6 +++ b/app/assets/javascripts/pipelines.js diff --git a/app/assets/javascripts/profile/gl_crop.js.es6 b/app/assets/javascripts/profile/gl_crop.js index 192b1192d07..cf1566eeb87 100644 --- a/app/assets/javascripts/profile/gl_crop.js.es6 +++ b/app/assets/javascripts/profile/gl_crop.js @@ -1,5 +1,7 @@ /* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */ +import 'vendor/cropper'; + ((global) => { // Matches everything but the file name const FILENAMEREGEX = /^.*[\\\/]/; diff --git a/app/assets/javascripts/profile/profile.js.es6 b/app/assets/javascripts/profile/profile.js index 4ccea0624ee..4ccea0624ee 100644 --- a/app/assets/javascripts/profile/profile.js.es6 +++ b/app/assets/javascripts/profile/profile.js diff --git a/app/assets/javascripts/project_label_subscription.js.es6 b/app/assets/javascripts/project_label_subscription.js index 0a811627600..0a811627600 100644 --- a/app/assets/javascripts/project_label_subscription.js.es6 +++ b/app/assets/javascripts/project_label_subscription.js diff --git a/app/assets/javascripts/project_variables.js.es6 b/app/assets/javascripts/project_variables.js index 4ee2e49306d..4ee2e49306d 100644 --- a/app/assets/javascripts/project_variables.js.es6 +++ b/app/assets/javascripts/project_variables.js diff --git a/app/assets/javascripts/projects_list.js b/app/assets/javascripts/projects_list.js index acdf9b7eb5a..c67d59d2be5 100644 --- a/app/assets/javascripts/projects_list.js +++ b/app/assets/javascripts/projects_list.js @@ -1,50 +1,18 @@ -/* eslint-disable func-names, space-before-function-paren, object-shorthand, quotes, no-var, one-var, one-var-declaration-per-line, prefer-arrow-callback, consistent-return, no-unused-vars, camelcase, prefer-template, comma-dangle, max-len */ +import FilterableList from './filterable_list'; -(function() { - window.ProjectsList = { - init: function() { - $(".projects-list-filter").off('keyup'); - this.initSearch(); - return this.initPagination(); - }, - initSearch: function() { - var debounceFilter, projectsListFilter; - projectsListFilter = $('.projects-list-filter'); - debounceFilter = _.debounce(window.ProjectsList.filterResults, 500); - return projectsListFilter.on('keyup', function(e) { - if (projectsListFilter.val() !== '') { - return debounceFilter(); - } - }); - }, - filterResults: function() { - var form, project_filter_url, search; - $('.projects-list-holder').fadeTo(250, 0.5); - form = null; - form = $("form#project-filter-form"); - search = $(".projects-list-filter").val(); - project_filter_url = form.attr('action') + '?' + form.serialize(); - return $.ajax({ - type: "GET", - url: form.attr('action'), - data: form.serialize(), - complete: function() { - return $('.projects-list-holder').fadeTo(250, 1); - }, - success: function(data) { - $('.projects-list-holder').replaceWith(data.html); - return history.replaceState({ - page: project_filter_url - // Change url so if user reload a page - search results are saved - }, document.title, project_filter_url); - }, - dataType: "json" - }); - }, - initPagination: function() { - return $('.projects-list-holder .pagination').on('ajax:success', function(e, data) { - return $('.projects-list-holder').replaceWith(data.html); - }); +/** + * Makes search request for projects when user types a value in the search input. + * Updates the html content of the page with the received one. + */ +export default class ProjectsList { + constructor() { + const form = document.querySelector('form#project-filter-form'); + const filter = document.querySelector('.js-projects-list-filter'); + const holder = document.querySelector('.js-projects-list-holder'); + + if (form && filter && holder) { + const list = new FilterableList(form, filter, holder); + list.initSearch(); } - }; -}).call(window); + } +} diff --git a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js index e7fff57ff45..e7fff57ff45 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6 +++ b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_create.js index 57ea2f52814..57ea2f52814 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_create.js.es6 +++ b/app/assets/javascripts/protected_branches/protected_branch_create.js diff --git a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js index 5cf28aa7a73..5cf28aa7a73 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6 +++ b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit.js index 6ef59e94384..6ef59e94384 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6 +++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js index 336fa6c57a7..336fa6c57a7 100644 --- a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6 +++ b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js diff --git a/app/assets/javascripts/search_autocomplete.js.es6 b/app/assets/javascripts/search_autocomplete.js index 6fd5345a0a6..6fd5345a0a6 100644 --- a/app/assets/javascripts/search_autocomplete.js.es6 +++ b/app/assets/javascripts/search_autocomplete.js diff --git a/app/assets/javascripts/shortcuts_blob.js.es6 b/app/assets/javascripts/shortcuts_blob.js index bfe90aef71e..bfe90aef71e 100644 --- a/app/assets/javascripts/shortcuts_blob.js.es6 +++ b/app/assets/javascripts/shortcuts_blob.js diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index 542cd586df0..09a58cad2b2 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -32,7 +32,7 @@ require('./shortcuts'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-network'); }); Mousetrap.bind('g g', function() { - return ShortcutsNavigation.findAndFollowLink('.shortcuts-graphs'); + return ShortcutsNavigation.findAndFollowLink('.shortcuts-repository-charts'); }); Mousetrap.bind('g i', function() { return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'); diff --git a/app/assets/javascripts/signin_tabs_memoizer.js.es6 b/app/assets/javascripts/signin_tabs_memoizer.js index d811d1cd53a..d811d1cd53a 100644 --- a/app/assets/javascripts/signin_tabs_memoizer.js.es6 +++ b/app/assets/javascripts/signin_tabs_memoizer.js diff --git a/app/assets/javascripts/smart_interval.js.es6 b/app/assets/javascripts/smart_interval.js index d1bdc353be2..d1bdc353be2 100644 --- a/app/assets/javascripts/smart_interval.js.es6 +++ b/app/assets/javascripts/smart_interval.js diff --git a/app/assets/javascripts/snippets_list.js.es6 b/app/assets/javascripts/snippets_list.js index 2128007113f..2128007113f 100644 --- a/app/assets/javascripts/snippets_list.js.es6 +++ b/app/assets/javascripts/snippets_list.js diff --git a/app/assets/javascripts/subbable_resource.js.es6 b/app/assets/javascripts/subbable_resource.js index d8191605128..d8191605128 100644 --- a/app/assets/javascripts/subbable_resource.js.es6 +++ b/app/assets/javascripts/subbable_resource.js diff --git a/app/assets/javascripts/subscription.js.es6 b/app/assets/javascripts/subscription.js index 62d1604fe9e..62d1604fe9e 100644 --- a/app/assets/javascripts/subscription.js.es6 +++ b/app/assets/javascripts/subscription.js diff --git a/app/assets/javascripts/templates/issuable_template_selector.js.es6 b/app/assets/javascripts/templates/issuable_template_selector.js index e9e9aafd71a..e9e9aafd71a 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js.es6 +++ b/app/assets/javascripts/templates/issuable_template_selector.js diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 b/app/assets/javascripts/templates/issuable_template_selectors.js index 97f6d37364d..97f6d37364d 100644 --- a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 +++ b/app/assets/javascripts/templates/issuable_template_selectors.js diff --git a/app/assets/javascripts/terminal/terminal.js.es6 b/app/assets/javascripts/terminal/terminal.js index 6b9422b1816..6b9422b1816 100644 --- a/app/assets/javascripts/terminal/terminal.js.es6 +++ b/app/assets/javascripts/terminal/terminal.js diff --git a/app/assets/javascripts/terminal/terminal_bundle.js.es6 b/app/assets/javascripts/terminal/terminal_bundle.js index 13cf3a10a38..13cf3a10a38 100644 --- a/app/assets/javascripts/terminal/terminal_bundle.js.es6 +++ b/app/assets/javascripts/terminal/terminal_bundle.js diff --git a/app/assets/javascripts/todos.js.es6 b/app/assets/javascripts/todos.js index e9513725d9d..e9513725d9d 100644 --- a/app/assets/javascripts/todos.js.es6 +++ b/app/assets/javascripts/todos.js diff --git a/app/assets/javascripts/u2f/authenticate.js.es6 b/app/assets/javascripts/u2f/authenticate.js index 500b78fc5d8..500b78fc5d8 100644 --- a/app/assets/javascripts/u2f/authenticate.js.es6 +++ b/app/assets/javascripts/u2f/authenticate.js diff --git a/app/assets/javascripts/user.js.es6 b/app/assets/javascripts/user.js index 059e6c628b3..059e6c628b3 100644 --- a/app/assets/javascripts/user.js.es6 +++ b/app/assets/javascripts/user.js diff --git a/app/assets/javascripts/user_callout.js b/app/assets/javascripts/user_callout.js index 74b869502a4..99419e85b20 100644 --- a/app/assets/javascripts/user_callout.js +++ b/app/assets/javascripts/user_callout.js @@ -43,6 +43,8 @@ class UserCallout { this.userCalloutBody.append($template); $template.find(closeButton).on('click', e => this.dismissCallout(e)); $template.find(userCalloutBtn).on('click', e => this.dismissCallout(e)); + } else { + this.userCalloutBody.remove(); } } @@ -50,7 +52,7 @@ class UserCallout { Cookies.set(USER_CALLOUT_COOKIE, 'true'); const $currentTarget = $(e.currentTarget); if ($currentTarget.hasClass('close-user-callout')) { - this.userCalloutBody.empty(); + this.userCalloutBody.remove(); } } } diff --git a/app/assets/javascripts/user_tabs.js.es6 b/app/assets/javascripts/user_tabs.js index 465618e3d53..465618e3d53 100644 --- a/app/assets/javascripts/user_tabs.js.es6 +++ b/app/assets/javascripts/user_tabs.js diff --git a/app/assets/javascripts/username_validator.js.es6 b/app/assets/javascripts/username_validator.js index 137cefa3b8e..137cefa3b8e 100644 --- a/app/assets/javascripts/username_validator.js.es6 +++ b/app/assets/javascripts/username_validator.js diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js index 5111b260e1c..754d448564f 100644 --- a/app/assets/javascripts/users/calendar.js +++ b/app/assets/javascripts/users/calendar.js @@ -1,5 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len */ -/* global d3 */ + +import d3 from 'd3'; (function() { var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index de33a31b411..27af859f7d8 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -60,6 +60,15 @@ }); }; + $('.assign-to-me-link').on('click', (e) => { + e.preventDefault(); + $(e.currentTarget).hide(); + const $input = $(`input[name="${$dropdown.data('field-name')}"]`); + $input.val(gon.current_user_id); + selectedId = $input.val(); + $dropdown.find('.dropdown-toggle-text').text(gon.current_user_fullname).removeClass('is-default'); + }); + $block.on('click', '.js-assign-yourself', function(e) { e.preventDefault(); @@ -199,6 +208,11 @@ if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { e.preventDefault(); selectedId = user.id; + if (selectedId === gon.current_user_id) { + $('.assign-to-me-link').hide(); + } else { + $('.assign-to-me-link').show(); + } return; } if ($el.closest('.add-issues-modal').length) { @@ -234,11 +248,16 @@ id: function (user) { return user.id; }, + opened: function(e) { + const $el = $(e.currentTarget); + $el.find('.is-active').removeClass('is-active'); + $el.find(`li[data-user-id="${selectedId}"] .dropdown-menu-user-link`).addClass('is-active'); + }, renderRow: function(user) { var avatar, img, listClosingTags, listWithName, listWithUserName, selected, username; username = user.username ? "@" + user.username : ""; avatar = user.avatar_url ? user.avatar_url : false; - selected = user.id === selectedId ? "is-active" : ""; + selected = user.id === parseInt(selectedId, 10) ? "is-active" : ""; img = ""; if (user.beforeDivider != null) { "<li> <a href='#' class='" + selected + "'> " + user.name + " </a> </li>"; @@ -248,7 +267,7 @@ } } // split into three parts so we can remove the username section if nessesary - listWithName = "<li> <a href='#' class='dropdown-menu-user-link " + selected + "'> " + img + " <strong class='dropdown-menu-user-full-name'> " + user.name + " </strong>"; + listWithName = "<li data-user-id=" + user.id + "> <a href='#' class='dropdown-menu-user-link " + selected + "'> " + img + " <strong class='dropdown-menu-user-full-name'> " + user.name + " </strong>"; listWithUserName = "<span class='dropdown-menu-user-username'> " + username + " </span>"; listClosingTags = "</a> </li>"; if (username === '') { diff --git a/app/assets/javascripts/version_check_image.js.es6 b/app/assets/javascripts/version_check_image.js index d4f716acb72..d4f716acb72 100644 --- a/app/assets/javascripts/version_check_image.js.es6 +++ b/app/assets/javascripts/version_check_image.js diff --git a/app/assets/javascripts/visibility_select.js.es6 b/app/assets/javascripts/visibility_select.js index f712d7ba930..f712d7ba930 100644 --- a/app/assets/javascripts/visibility_select.js.es6 +++ b/app/assets/javascripts/visibility_select.js diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js index e7432afb56e..a90bd1518e9 100644 --- a/app/assets/javascripts/vue_pipelines_index/index.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/index.js @@ -11,15 +11,10 @@ $(() => new Vue({ data() { const project = document.querySelector('.pipelines'); - const svgs = document.querySelector('.pipeline-svgs').dataset; - - // Transform svgs DOMStringMap to a plain Object. - const svgsObject = gl.utils.DOMStringMapToObject(svgs); return { scope: project.dataset.url, store: new gl.PipelineStore(), - svgs: svgsObject, }; }, components: { @@ -27,10 +22,8 @@ $(() => new Vue({ }, template: ` <vue-pipelines - :scope='scope' - :store='store' - :svgs='svgs' - > + :scope="scope" + :store="store"> </vue-pipelines> `, })); diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js index b50afe7c594..891f1f17fb3 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js @@ -1,9 +1,10 @@ /* global Vue, Flash, gl */ -/* eslint-disable no-param-reassign, no-alert */ +/* eslint-disable no-param-reassign, no-alert */ +const playIconSvg = require('icons/_icon_play.svg'); ((gl) => { gl.VuePipelineActions = Vue.extend({ - props: ['pipeline', 'svgs'], + props: ['pipeline'], computed: { actions() { return this.pipeline.details.manual_actions.length > 0; @@ -31,6 +32,11 @@ } }, }, + + data() { + return { playIconSvg }; + }, + template: ` <td class="pipeline-actions"> <div class="pull-right"> @@ -42,7 +48,7 @@ title="Manual job" data-placement="top" aria-label="Manual job"> - <span v-html="svgs.iconPlay" aria-hidden="true"></span> + <span v-html="playIconSvg" aria-hidden="true"></span> <i class="fa fa-caret-down" aria-hidden="true"></i> </button> <ul class="dropdown-menu dropdown-menu-align-right"> @@ -50,8 +56,8 @@ <a rel="nofollow" data-method="post" - :href="action.path"> - <span v-html="svgs.iconPlay" aria-hidden="true"></span> + :href="action.path" > + <span v-html="playIconSvg" aria-hidden="true"></span> <span>{{action.name}}</span> </a> </li> diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_url.js index ae5649f0519..ae5649f0519 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipeline_url.js diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js index 9275cdf78f7..601ef41e917 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js @@ -27,7 +27,7 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s pageRequest: false, }; }, - props: ['scope', 'store', 'svgs'], + props: ['scope', 'store'], created() { const pagenum = gl.utils.getParameterByName('page'); const scope = gl.utils.getParameterByName('scope'); @@ -70,10 +70,7 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s </div> <div class="table-holder" v-if='!pageRequest && pipelines.length'> - <pipelines-table-component - :pipelines='pipelines' - :svgs='svgs'> - </pipelines-table-component> + <pipelines-table-component :pipelines='pipelines'/> </div> <gl-pagination diff --git a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 b/app/assets/javascripts/vue_pipelines_index/stage.js index 67fdd729e41..f67ebd6a265 100644 --- a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/stage.js @@ -1,27 +1,42 @@ /* global Vue, Flash, gl */ /* eslint-disable no-param-reassign */ +import canceledSvg from 'icons/_icon_status_canceled_borderless.svg'; +import createdSvg from 'icons/_icon_status_created_borderless.svg'; +import failedSvg from 'icons/_icon_status_failed_borderless.svg'; +import manualSvg from 'icons/_icon_status_manual_borderless.svg'; +import pendingSvg from 'icons/_icon_status_pending_borderless.svg'; +import runningSvg from 'icons/_icon_status_running_borderless.svg'; +import skippedSvg from 'icons/_icon_status_skipped_borderless.svg'; +import successSvg from 'icons/_icon_status_success_borderless.svg'; +import warningSvg from 'icons/_icon_status_warning_borderless.svg'; ((gl) => { gl.VueStage = Vue.extend({ data() { + const svgsDictionary = { + icon_status_canceled: canceledSvg, + icon_status_created: createdSvg, + icon_status_failed: failedSvg, + icon_status_manual: manualSvg, + icon_status_pending: pendingSvg, + icon_status_running: runningSvg, + icon_status_skipped: skippedSvg, + icon_status_success: successSvg, + icon_status_warning: warningSvg, + }; + return { builds: '', spinner: '<span class="fa fa-spinner fa-spin"></span>', + svg: svgsDictionary[this.stage.status.icon], }; }, + props: { stage: { type: Object, required: true, }, - svgs: { - type: Object, - required: true, - }, - match: { - type: Function, - required: true, - }, }, updated() { @@ -73,11 +88,6 @@ tooltip() { return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`; }, - svg() { - const { icon } = this.stage.status; - const stageIcon = icon.replace(/icon/i, 'stage_icon'); - return this.svgs[this.match(stageIcon)]; - }, triggerButtonClass() { return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`; }, @@ -91,8 +101,7 @@ data-placement="top" data-toggle="dropdown" type="button" - :aria-label="stage.title" - > + :aria-label="stage.title"> <span v-html="svg" aria-hidden="true"></span> <i class="fa fa-caret-down" aria-hidden="true"></i> </button> @@ -101,8 +110,7 @@ <div :class="dropdownClass" class="js-builds-dropdown-list scrollable-menu" - v-html="buildsOrSpinner" - > + v-html="buildsOrSpinner"> </div> </ul> </div> diff --git a/app/assets/javascripts/vue_pipelines_index/status.js b/app/assets/javascripts/vue_pipelines_index/status.js new file mode 100644 index 00000000000..8d9f83ac113 --- /dev/null +++ b/app/assets/javascripts/vue_pipelines_index/status.js @@ -0,0 +1,64 @@ +/* global Vue, gl */ +/* eslint-disable no-param-reassign */ + +import canceledSvg from 'icons/_icon_status_canceled.svg'; +import createdSvg from 'icons/_icon_status_created.svg'; +import failedSvg from 'icons/_icon_status_failed.svg'; +import manualSvg from 'icons/_icon_status_manual.svg'; +import pendingSvg from 'icons/_icon_status_pending.svg'; +import runningSvg from 'icons/_icon_status_running.svg'; +import skippedSvg from 'icons/_icon_status_skipped.svg'; +import successSvg from 'icons/_icon_status_success.svg'; +import warningSvg from 'icons/_icon_status_warning.svg'; + +((gl) => { + gl.VueStatusScope = Vue.extend({ + props: [ + 'pipeline', + ], + + data() { + const svgsDictionary = { + icon_status_canceled: canceledSvg, + icon_status_created: createdSvg, + icon_status_failed: failedSvg, + icon_status_manual: manualSvg, + icon_status_pending: pendingSvg, + icon_status_running: runningSvg, + icon_status_skipped: skippedSvg, + icon_status_success: successSvg, + icon_status_warning: warningSvg, + }; + + return { + svg: svgsDictionary[this.pipeline.details.status.icon], + }; + }, + + computed: { + cssClasses() { + const cssObject = { 'ci-status': true }; + cssObject[`ci-${this.pipeline.details.status.group}`] = true; + return cssObject; + }, + + detailsPath() { + const { status } = this.pipeline.details; + return status.has_details ? status.details_path : false; + }, + + content() { + return `${this.svg} ${this.pipeline.details.status.text}`; + }, + }, + template: ` + <td class="commit-link"> + <a + :class="cssClasses" + :href="detailsPath" + v-html="content"> + </a> + </td> + `, + }); +})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/vue_pipelines_index/status.js.es6 b/app/assets/javascripts/vue_pipelines_index/status.js.es6 deleted file mode 100644 index 05175082704..00000000000 --- a/app/assets/javascripts/vue_pipelines_index/status.js.es6 +++ /dev/null @@ -1,34 +0,0 @@ -/* global Vue, gl */ -/* eslint-disable no-param-reassign */ - -((gl) => { - gl.VueStatusScope = Vue.extend({ - props: [ - 'pipeline', 'svgs', 'match', - ], - computed: { - cssClasses() { - const cssObject = { 'ci-status': true }; - cssObject[`ci-${this.pipeline.details.status.group}`] = true; - return cssObject; - }, - svg() { - return this.svgs[this.match(this.pipeline.details.status.icon)]; - }, - detailsPath() { - const { status } = this.pipeline.details; - return status.has_details ? status.details_path : false; - }, - }, - template: ` - <td class="commit-link"> - <a - :class='cssClasses' - :href='detailsPath' - v-html='svg + pipeline.details.status.text' - > - </a> - </td> - `, - }); -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/vue_pipelines_index/store.js.es6 b/app/assets/javascripts/vue_pipelines_index/store.js index 909007267b9..909007267b9 100644 --- a/app/assets/javascripts/vue_pipelines_index/store.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/store.js diff --git a/app/assets/javascripts/vue_pipelines_index/time_ago.js.es6 b/app/assets/javascripts/vue_pipelines_index/time_ago.js index 6048fa691dc..a383570857d 100644 --- a/app/assets/javascripts/vue_pipelines_index/time_ago.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/time_ago.js @@ -4,14 +4,17 @@ window.Vue = require('vue'); require('../lib/utils/datetime_utility'); +const iconTimerSvg = require('../../../views/shared/icons/_icon_timer.svg'); + ((gl) => { gl.VueTimeAgo = Vue.extend({ data() { return { currentTime: new Date(), + iconTimerSvg, }; }, - props: ['pipeline', 'svgs'], + props: ['pipeline'], computed: { timeAgo() { return gl.utils.getTimeago(); @@ -56,7 +59,7 @@ require('../lib/utils/datetime_utility'); template: ` <td class="pipelines-time-ago"> <p class="duration" v-if='duration'> - <span v-html='svgs.iconTimer'></span> + <span v-html="iconTimerSvg"></span> {{duration}} </p> <p class="finished-at" v-if='timeStopped'> diff --git a/app/assets/javascripts/vue_realtime_listener/index.js.es6 b/app/assets/javascripts/vue_realtime_listener/index.js index 30f6680a673..30f6680a673 100644 --- a/app/assets/javascripts/vue_realtime_listener/index.js.es6 +++ b/app/assets/javascripts/vue_realtime_listener/index.js diff --git a/app/assets/javascripts/vue_shared/components/commit.js.es6 b/app/assets/javascripts/vue_shared/components/commit.js index ff88e236829..4381487b79e 100644 --- a/app/assets/javascripts/vue_shared/components/commit.js.es6 +++ b/app/assets/javascripts/vue_shared/components/commit.js @@ -1,5 +1,6 @@ /* global Vue */ window.Vue = require('vue'); +const commitIconSvg = require('icons/_icon_commit.svg'); (() => { window.gl = window.gl || {}; @@ -69,11 +70,6 @@ window.Vue = require('vue'); required: false, default: () => ({}), }, - - commitIconSvg: { - type: String, - required: false, - }, }, computed: { @@ -116,6 +112,10 @@ window.Vue = require('vue'); }, }, + data() { + return { commitIconSvg }; + }, + template: ` <div class="branch-commit"> diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 b/app/assets/javascripts/vue_shared/components/pipelines_table.js index 34d3bbdd80d..0d8f85db965 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 +++ b/app/assets/javascripts/vue_shared/components/pipelines_table.js @@ -21,14 +21,6 @@ require('./pipelines_table_row'); default: () => ([]), }, - /** - * TODO: Remove this when we have webpack. - */ - svgs: { - type: Object, - required: true, - default: () => ({}), - }, }, components: { @@ -51,8 +43,7 @@ require('./pipelines_table_row'); <template v-for="model in pipelines" v-bind:model="model"> <tr is="pipelines-table-row-component" - :pipeline="model" - :svgs="svgs"></tr> + :pipeline="model"></tr> </template> </tbody> </table> diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 b/app/assets/javascripts/vue_shared/components/pipelines_table_row.js index 61c1b72d9d2..e5e88186a85 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 +++ b/app/assets/javascripts/vue_shared/components/pipelines_table_row.js @@ -25,14 +25,6 @@ require('./commit'); default: () => ({}), }, - /** - * TODO: Remove this when we have webpack; - */ - svgs: { - type: Object, - required: true, - default: () => ({}), - }, }, components: { @@ -174,30 +166,9 @@ require('./commit'); }, }, - methods: { - /** - * FIXME: This should not be in this component but in the components that - * need this function. - * - * Used to render SVGs in the following components: - * - status-scope - * - dropdown-stage - * - * @param {String} string - * @return {String} - */ - match(string) { - return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase()); - }, - }, - template: ` <tr class="commit"> - <status-scope - :pipeline="pipeline" - :svgs="svgs" - :match="match"> - </status-scope> + <status-scope :pipeline="pipeline"/> <pipeline-url :pipeline="pipeline"></pipeline-url> @@ -208,26 +179,20 @@ require('./commit'); :commit-url="commitUrl" :short-sha="commitShortSha" :title="commitTitle" - :author="commitAuthor" - :commit-icon-svg="svgs.commitIconSvg"> - </commit-component> + :author="commitAuthor"/> </td> <td class="stage-cell"> <div class="stage-container dropdown js-mini-pipeline-graph" v-if="pipeline.details.stages.length > 0" v-for="stage in pipeline.details.stages"> - <dropdown-stage - :stage="stage" - :svgs="svgs" - :match="match"> - </dropdown-stage> + <dropdown-stage :stage="stage"/> </div> </td> - <time-ago :pipeline="pipeline" :svgs="svgs"></time-ago> + <time-ago :pipeline="pipeline"/> - <pipeline-actions :pipeline="pipeline" :svgs="svgs"></pipeline-actions> + <pipeline-actions :pipeline="pipeline" /> </tr> `, }); diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.js.es6 b/app/assets/javascripts/vue_shared/components/table_pagination.js index dd046405575..8943b850a72 100644 --- a/app/assets/javascripts/vue_shared/components/table_pagination.js.es6 +++ b/app/assets/javascripts/vue_shared/components/table_pagination.js @@ -19,7 +19,6 @@ window.Vue = require('vue'); /** This function will take the information given by the pagination component - And make a new Turbolinks call Here is an example `change` method: diff --git a/app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6 b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js index d3229f9f730..d3229f9f730 100644 --- a/app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6 +++ b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js diff --git a/app/assets/javascripts/wikis.js.es6 b/app/assets/javascripts/wikis.js index 75fd1394a03..75fd1394a03 100644 --- a/app/assets/javascripts/wikis.js.es6 +++ b/app/assets/javascripts/wikis.js |