From 424a3b042ae445de3a1507ff24564a0733d2956b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Sat, 14 Mar 2015 01:18:05 +0100 Subject: [PATCH] FEATURE: unified UI for pinning/banner topics REFACTOR: ES6ified all the modals --- .../{ => modals}/admin-agree-flag.js.es6 | 0 .../{ => modals}/admin-badge-preview.js.es6 | 0 .../{ => modals}/admin-delete-flag.js.es6 | 0 .../admin-edit-badge-groupings.js.es6 | 0 .../admin-staff-action-log-details.js.es6 | 0 .../{ => modals}/admin-suspend-user.js.es6 | 1 - .../change-site-customization-details.js.es6 | 0 .../delete-site-customization-details.js.es6 | 4 +- .../admin/routes/admin-badges-show.js.es6 | 4 +- .../admin/routes/admin-flags-list.js.es6 | 4 +- .../admin-logs-staff-action-logs.js.es6 | 5 +- .../admin/routes/admin-user-index.js.es6 | 2 +- ...e_flag_view.js => admin-agree-flag.js.es6} | 4 +- ...iew_view.js => admin-badge-preview.js.es6} | 3 +- .../views/modals/admin-delete-flag.js.es6 | 6 ++ ...w.js => admin-edit-badge-groupings.js.es6} | 3 +- .../admin-staff-action-log-details.js.es6 | 6 ++ ...ckup_view.js => admin-start-backup.js.es6} | 4 +- .../views/modals/admin-suspend-user.js.es6 | 6 ++ .../views/modals/admin_delete_flag_view.js | 12 --- .../admin_staff_action_log_details_view.js | 12 --- .../views/modals/admin_suspend_user_view.js | 12 --- .../change-site-customization-details.js.es6 | 6 ++ .../change_site_customization_details_view.js | 13 ---- .../delete-site-customization-details.js.es6 | 6 ++ .../delete_site_customization_details_view.js | 13 ---- .../controllers/feature-topic.js.es6 | 77 +++++++++++++++++++ .../discourse/controllers/topic.js.es6 | 38 +++++++-- .../discourse/lib/show-modal.js.es6 | 12 +-- .../javascripts/discourse/models/topic.js.es6 | 12 +-- .../discourse/routes/application.js.es6 | 2 +- .../javascripts/discourse/routes/topic.js.es6 | 5 ++ .../templates/modal/feature-topic.hbs | 62 +++++++++++++++ .../discourse/templates/topic-admin-menu.hbs | 25 ++---- .../views/archetype-options-modal.js.es6 | 4 +- .../discourse/views/avatar-selector.js.es6 | 10 +-- .../discourse/views/change-owner.js.es6 | 4 +- .../discourse/views/create-account.js.es6 | 6 +- .../discourse/views/edit-category.js.es6 | 4 +- .../views/edit-topic-auto-close.js.es6 | 4 +- .../discourse/views/feature-topic.js.es6 | 6 ++ .../javascripts/discourse/views/flag.js.es6 | 11 ++- .../discourse/views/forgot-password.js.es6 | 4 +- .../discourse/views/history.js.es6 | 6 +- .../discourse/views/invite-private.js.es6 | 4 +- .../javascripts/discourse/views/invite.js.es6 | 14 ++-- .../views/keyboard-shortcuts-help.js.es6 | 4 +- .../javascripts/discourse/views/login.js.es6 | 12 +-- .../discourse/views/merge-topic.js.es6 | 4 +- .../discourse/views/modal-body.js.es6 | 30 ++++++++ .../javascripts/discourse/views/modal.js.es6 | 10 +-- .../discourse/views/modal_body_view.js | 48 ------------ .../discourse/views/not-activated.js.es6 | 4 +- .../javascripts/discourse/views/raw-email.es6 | 6 +- .../discourse/views/search-help.js.es6 | 4 +- .../discourse/views/split-topic.js.es6 | 4 +- .../discourse/views/topic-bulk-actions.js.es6 | 4 +- .../discourse/views/upload-selector.js.es6 | 25 +++--- app/assets/javascripts/main_include.js | 2 +- app/assets/javascripts/main_include_admin.js | 1 - app/controllers/topics_controller.rb | 15 +++- config/locales/client.en.yml | 28 ++++++- config/routes.rb | 1 + .../javascripts/integration/modal-test.js.es6 | 2 +- 64 files changed, 410 insertions(+), 230 deletions(-) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-agree-flag.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-badge-preview.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-delete-flag.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-edit-badge-groupings.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-staff-action-log-details.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-suspend-user.js.es6 (99%) rename app/assets/javascripts/admin/controllers/{ => modals}/change-site-customization-details.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/delete-site-customization-details.js.es6 (65%) rename app/assets/javascripts/admin/views/modals/{admin_agree_flag_view.js => admin-agree-flag.js.es6} (54%) rename app/assets/javascripts/admin/views/modals/{admin_badge_preview_view.js => admin-badge-preview.js.es6} (55%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 rename app/assets/javascripts/admin/views/modals/{admin_edit_badge_groupings_view.js => admin-edit-badge-groupings.js.es6} (58%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 rename app/assets/javascripts/admin/views/modals/{admin_start_backup_view.js => admin-start-backup.js.es6} (56%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js delete mode 100644 app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js delete mode 100644 app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js create mode 100644 app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js create mode 100644 app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js create mode 100644 app/assets/javascripts/discourse/controllers/feature-topic.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/modal/feature-topic.hbs create mode 100644 app/assets/javascripts/discourse/views/feature-topic.js.es6 create mode 100644 app/assets/javascripts/discourse/views/modal-body.js.es6 delete mode 100644 app/assets/javascripts/discourse/views/modal_body_view.js diff --git a/app/assets/javascripts/admin/controllers/admin-agree-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-agree-flag.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-badge-preview.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-badge-preview.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-delete-flag.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-staff-action-log-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-staff-action-log-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 similarity index 99% rename from app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 index b2d30f96d..49999aa09 100644 --- a/app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 @@ -1,5 +1,4 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; - import ObjectController from 'discourse/controllers/object'; export default ObjectController.extend(ModalFunctionality, { diff --git a/app/assets/javascripts/admin/controllers/change-site-customization-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/change-site-customization-details.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/change-site-customization-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/change-site-customization-details.js.es6 diff --git a/app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 similarity index 65% rename from app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 index 57e3c9652..d38c396ce 100644 --- a/app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 @@ -1,7 +1,7 @@ -import ChangeSiteCustomizationDetailsController from "admin/controllers/change-site-customization-details"; +import ChangeSiteCustomizationDetailsController from "admin/controllers/modals/change-site-customization-details"; export default ChangeSiteCustomizationDetailsController.extend({ onShow: function() { - this.selectPrevious(); + this.send("selectPrevious"); } }); diff --git a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 index 3d2ac3445..56d0f93da 100644 --- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 @@ -25,7 +25,7 @@ export default Ember.Route.extend({ editGroupings() { const groupings = this.controllerFor('admin-badges').get('badgeGroupings'); - showModal('admin_edit_badge_groupings', groupings); + showModal('modals/admin-edit-badge-groupings', groupings); }, preview(badge, explain) { @@ -40,7 +40,7 @@ export default Ember.Route.extend({ } }).then(function(json) { badge.set('preview_loading', false); - showModal('admin_badge_preview', json); + showModal('modals/admin-badge-preview', json); }).catch(function(error) { badge.set('preview_loading', false); Em.Logger.error(error); diff --git a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 index afe3d8ab4..99ceba771 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 @@ -13,12 +13,12 @@ export default Discourse.Route.extend({ actions: { showAgreeFlagModal(flaggedPost) { - showModal('admin_agree_flag', flaggedPost); + showModal('modals/admin-agree-flag', flaggedPost); this.controllerFor('modal').set('modalClass', 'agree-flag-modal'); }, showDeleteFlagModal(flaggedPost) { - showModal('admin_delete_flag', flaggedPost); + showModal('modals/admin-delete-flag', flaggedPost); this.controllerFor('modal').set('modalClass', 'delete-flag-modal'); } diff --git a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 index 29a40ed77..f0f08ab2f 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 @@ -13,12 +13,13 @@ export default Discourse.Route.extend({ actions: { showDetailsModal(logRecord) { - showModal('admin_staff_action_log_details', logRecord); + showModal('modals/admin-staff-action-log-details', logRecord); this.controllerFor('modal').set('modalClass', 'log-details-modal'); }, showCustomDetailsModal(logRecord) { - showModal(logRecord.action_name + '_details', logRecord); + const modalName = "modals/" + (logRecord.action_name + '_details').replace("_", "-"); + showModal(modalName, logRecord); this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal'); } } diff --git a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 index e9c084ab3..07cbfa8fc 100644 --- a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 @@ -25,7 +25,7 @@ export default Discourse.Route.extend({ actions: { showSuspendModal(user) { - showModal('admin_suspend_user', user); + showModal('modals/admin-suspend-user', user); this.controllerFor('modal').set('modalClass', 'suspend-user-modal'); } } diff --git a/app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js b/app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 similarity index 54% rename from app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js rename to app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 index cabb3c7fd..0a4aba513 100644 --- a/app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 @@ -1,4 +1,6 @@ -Discourse.AdminAgreeFlagView = Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_agree_flag', title: I18n.t('admin.flags.agree_flag_modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js b/app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 similarity index 55% rename from app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js rename to app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 index 0d890b3d6..6431ba936 100644 --- a/app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 @@ -1,5 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; -Discourse.AdminBadgePreviewView = Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_badge_preview', title: I18n.t('admin.badges.preview.modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 new file mode 100644 index 000000000..379b2ef77 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/modal/admin_delete_flag', + title: I18n.t('admin.flags.delete_flag_modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js b/app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 similarity index 58% rename from app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js rename to app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 index cf2227f35..ccc5f49a3 100644 --- a/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 @@ -1,5 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; -Discourse.AdminEditBadgeGroupingsView = Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_edit_badge_groupings', title: I18n.t('admin.badges.badge_groupings.modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 b/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 new file mode 100644 index 000000000..a31a61e0c --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/details_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_start_backup_view.js b/app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 similarity index 56% rename from app/assets/javascripts/admin/views/modals/admin_start_backup_view.js rename to app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 index b59207f26..e363ee1a1 100644 --- a/app/assets/javascripts/admin/views/modals/admin_start_backup_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 @@ -1,4 +1,6 @@ -Discourse.AdminStartBackupView = Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_start_backup', title: I18n.t('admin.backups.operations.backup.confirm') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 new file mode 100644 index 000000000..9f3dcb163 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/modal/admin_suspend_user', + title: I18n.t('admin.user.suspend_modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js b/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js deleted file mode 100644 index 204e7b382..000000000 --- a/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for deleting a flag. - - @class AdminDeleteFlagView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminDeleteFlagView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/modal/admin_delete_flag', - title: I18n.t('admin.flags.delete_flag_modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js b/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js deleted file mode 100644 index 7e6e623e3..000000000 --- a/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal. - - @class AdminStaffActionLogDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminStaffActionLogDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/details_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js b/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js deleted file mode 100644 index 102a5e765..000000000 --- a/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for suspending a user. - - @class AdminSuspendUserView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminSuspendUserView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/modal/admin_suspend_user', - title: I18n.t('admin.user.suspend_modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 b/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 new file mode 100644 index 000000000..28cc323e4 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/site_customization_change_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js b/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js deleted file mode 100644 index 7728bf777..000000000 --- a/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal - for when a site customization is created or changed. - - @class ChangeSiteCustomizationDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.ChangeSiteCustomizationDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/site_customization_change_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 b/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 new file mode 100644 index 000000000..28cc323e4 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/site_customization_change_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js b/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js deleted file mode 100644 index a4670c697..000000000 --- a/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal - for when a site customization is deleted. - - @class DeleteSiteCustomizationDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.DeleteSiteCustomizationDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/site_customization_change_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 new file mode 100644 index 000000000..f7ae397e8 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 @@ -0,0 +1,77 @@ +import ModalFunctionality from 'discourse/mixins/modal-functionality'; +import ObjectController from 'discourse/controllers/object'; +import { categoryLinkHTML } from 'discourse/helpers/category-link'; + +export default ObjectController.extend(ModalFunctionality, { + needs: ["topic"], + + loading: true, + pinnedInCategoryCount: 0, + pinnedGloballyCount: 0, + bannerCount: 0, + + categoryLink: function() { + return categoryLinkHTML(this.get("category"), { allowUncategorized: true }); + }.property("category"), + + unPinMessage: function() { + return this.get("pinned_globally") ? + I18n.t("topic.feature_topic.unpin_globally") : + I18n.t("topic.feature_topic.unpin", { categoryLink: this.get("categoryLink") }); + }.property("categoryLink", "pinned_globally"), + + pinMessage: function() { + return I18n.t("topic.feature_topic.pin", { categoryLink: this.get("categoryLink") }); + }.property("categoryLink"), + + alreadyPinnedMessage: function() { + return I18n.t("topic.feature_topic.already_pinned", { categoryLink: this.get("categoryLink"), count: this.get("pinnedInCategoryCount") }); + }.property("categoryLink", "pinnedInCategoryCount"), + + onShow() { + const self = this; + + this.set("loading", true); + + return Discourse.ajax("/topics/feature_stats.json", { + data: { category_id: this.get("category.id") } + }).then(function(result) { + if (result) { + self.setProperties({ + pinnedInCategoryCount: result.pinned_in_category_count, + pinnedGloballyCount: result.pinned_globally_count, + bannerCount: result.banner_count, + }); + } + }).finally(function() { + self.set("loading", false); + }); + }, + + _forwardAction(name) { + this.get("controllers.topic").send(name); + this.send("closeModal"); + }, + + _confirmBeforePinning(count, name, action) { + if (count < 4) { + this._forwardAction(action); + } else { + this.send("hideModal"); + const message = I18n.t("topic.feature_topic.confirm_" + name, { count: count }); + bootbox.confirm( + message, I18n.t("no_value"), I18n.t("yes_value"), + (confirmed) => confirmed ? this._forwardAction(action) : this.send("reopenModal") + ); + } + }, + + actions: { + pin() { this._confirmBeforePinning(this.get("pinnedInCategoryCount"), "pin", "togglePinned"); }, + pinGlobally() { this._confirmBeforePinning(this.get("pinnedGloballyCount"), "pin_globally", "pinGlobally"); }, + unpin() { this._forwardAction("togglePinned"); }, + makeBanner() { this._forwardAction("makeBanner"); }, + removeBanner() { this._forwardAction("removeBanner"); }, + } + +}); diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index e0da67fe6..c99a98655 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -94,6 +94,19 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon this.set('selectedReplies', []); }.on('init'), + _togglePinnedStates(property) { + const value = this.get('pinned_at') ? false : true, + topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: value, + pinned_globally: value + }); + + return topic.saveStatus(property, value); + }, + actions: { deleteTopic() { this.deleteTopic(); @@ -352,13 +365,28 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon }, togglePinned() { - // Note that this is different than clearPin - this.get('content').setStatus('pinned', this.get('pinned_at') ? false : true); + const value = this.get('pinned_at') ? false : true, + topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: value ? moment() : null, + pinned_globally: false + }); + + return topic.saveStatus("pinned", value); }, - togglePinnedGlobally() { - // Note that this is different than clearPin - this.get('content').setStatus('pinned_globally', this.get('pinned_at') ? false : true); + pinGlobally() { + const topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: moment(), + pinned_globally: true + }); + + return topic.saveStatus("pinned_globally", true); }, toggleArchived() { diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index f12435c49..667a344dd 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,19 +1,15 @@ export default function showModal(name, model) { - // We use the container here because modals are like singletons // in Discourse. Only one can be shown with a particular state. const route = Discourse.__container__.lookup('route:application'); route.controllerFor('modal').set('modalClass', null); - route.render(name, {into: 'modal', outlet: 'modalBody'}); + route.render(name, { into: 'modal', outlet: 'modalBody' }); + const controller = route.controllerFor(name); if (controller) { - if (model) { - controller.set('model', model); - } - if (controller.onShow) { - controller.onShow(); - } + if (model) { controller.set('model', model); } + if (controller.onShow) { controller.onShow(); } controller.set('flashMessage', null); } return controller; diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 5ae5ee7ec..93ff2850d 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -145,24 +145,16 @@ const Topic = Discourse.Model.extend({ toggleStatus(property) { this.toggleProperty(property); - this.saveStatus(property, this.get(property) ? true : false); - }, - - setStatus(property, value) { - this.set(property, value); - this.saveStatus(property, value); + this.saveStatus(property, !this.get(property)); }, saveStatus(property, value) { if (property === 'closed' && value === true) { this.set('details.auto_close_at', null); } - if (property === 'pinned') { - this.set('pinned_at', value ? moment() : null); - } return Discourse.ajax(this.get('url') + "/status", { type: 'PUT', - data: {status: property, enabled: value ? 'true' : 'false' } + data: { status: property, enabled: !!value } }); }, diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 681a097cb..3ba76b649 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -102,7 +102,7 @@ const ApplicationRoute = Discourse.Route.extend({ // Close the current modal, and destroy its state. closeModal() { - this.render('hide-modal', {into: 'modal', outlet: 'modalBody'}); + this.render('hide-modal', { into: 'modal', outlet: 'modalBody' }); }, /** diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 1b1474286..d7948ce3a 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -59,6 +59,11 @@ const TopicRoute = Discourse.Route.extend(ShowFooter, { this.controllerFor('modal').set('modalClass', 'edit-auto-close-modal'); }, + showFeatureTopic() { + showModal('featureTopic', this.modelFor('topic')); + this.controllerFor('modal').set('modalClass', 'feature-topic-modal'); + }, + showInvite() { showModal('invite', this.modelFor('topic')); this.controllerFor('invite').reset(); diff --git a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs new file mode 100644 index 000000000..b517a3762 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs @@ -0,0 +1,62 @@ + + diff --git a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs index ef204205e..0840dfc34 100644 --- a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs +++ b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs @@ -27,26 +27,11 @@ {{#unless isPrivateMessage}} -
  • - {{#if isBanner}} - {{d-button action="removeBanner" icon="bullhorn" label="topic.actions.remove_banner" class="btn-admin"}} - {{else}} - {{#if visible}} - {{d-button action="makeBanner" icon="bullhorn" label="topic.actions.make_banner" class="btn-admin"}} - {{/if}} - {{/if}} -
  • - -
  • - {{#if pinned_at}} - {{d-button action="togglePinned" icon="thumb-tack" label="topic.actions.unpin" class="btn-admin"}} - {{else}} - {{#if visible}} - {{d-button action="togglePinned" icon="thumb-tack" label="topic.actions.pin" class="btn-admin"}} - {{d-button action="togglePinnedGlobally" icon="thumb-tack" label="topic.actions.pin_globally" class="btn-admin"}} - {{/if}} - {{/if}} -
  • + {{#if visible}} +
  • + {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.feature" class="btn-admin"}} +
  • + {{/if}} {{/unless}}
  • diff --git a/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 b/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 index 2daa63756..d6ebb0c27 100644 --- a/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 +++ b/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/archetype_options', title: I18n.t('topic.options') }); diff --git a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 index c87e91fcd..40414660a 100644 --- a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/avatar_selector', classNames: ['avatar-selector'], title: I18n.t('user.change_avatar.title'), @@ -9,10 +11,6 @@ export default Discourse.ModalBodyView.extend({ // *HACK* used to select the proper radio button, cause {{action}} // stops the default behavior selectedChanged: function() { - var self = this; - Em.run.next(function() { - var value = self.get('controller.selected'); - $('input:radio[name="avatar"]').val([value]); - }); + Em.run.next(() => $('input:radio[name="avatar"]').val([this.get('controller.selected')]) ); }.observes('controller.selected') }); diff --git a/app/assets/javascripts/discourse/views/change-owner.js.es6 b/app/assets/javascripts/discourse/views/change-owner.js.es6 index afce839d6..604dfbe56 100644 --- a/app/assets/javascripts/discourse/views/change-owner.js.es6 +++ b/app/assets/javascripts/discourse/views/change-owner.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/change_owner', title: I18n.t('topic.change_owner.title') }); diff --git a/app/assets/javascripts/discourse/views/create-account.js.es6 b/app/assets/javascripts/discourse/views/create-account.js.es6 index 8de0a1864..da0e28158 100644 --- a/app/assets/javascripts/discourse/views/create-account.js.es6 +++ b/app/assets/javascripts/discourse/views/create-account.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/create-account', title: I18n.t('create_account.title'), classNames: ['create-account'], @@ -6,7 +8,7 @@ export default Discourse.ModalBodyView.extend({ _setup: function() { // allows the submission the form when pressing 'ENTER' on *any* text input field // but only when the submit button is enabled - var createAccountController = this.get('controller'); + const createAccountController = this.get('controller'); Em.run.schedule('afterRender', function() { $("input[type='text'], input[type='password']").keydown(function(e) { if (createAccountController.get('submitDisabled') === false && e.keyCode === 13) { diff --git a/app/assets/javascripts/discourse/views/edit-category.js.es6 b/app/assets/javascripts/discourse/views/edit-category.js.es6 index 6d0fb05a5..ea93cc99b 100644 --- a/app/assets/javascripts/discourse/views/edit-category.js.es6 +++ b/app/assets/javascripts/discourse/views/edit-category.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/edit-category', _initializePanels: function() { diff --git a/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 b/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 index 57d7e55f6..b5b5c3328 100644 --- a/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 +++ b/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/auto_close', title: I18n.t('topic.auto_close_title') }); diff --git a/app/assets/javascripts/discourse/views/feature-topic.js.es6 b/app/assets/javascripts/discourse/views/feature-topic.js.es6 new file mode 100644 index 000000000..2a106541e --- /dev/null +++ b/app/assets/javascripts/discourse/views/feature-topic.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'modal/feature-topic', + title: I18n.t('topic.feature_topic.title') +}); diff --git a/app/assets/javascripts/discourse/views/flag.js.es6 b/app/assets/javascripts/discourse/views/flag.js.es6 index a819d7efb..b948c35f0 100644 --- a/app/assets/javascripts/discourse/views/flag.js.es6 +++ b/app/assets/javascripts/discourse/views/flag.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/flag', title: function() { @@ -6,12 +8,13 @@ export default Discourse.ModalBodyView.extend({ }.property('controller.flagTopic'), selectedChanged: function() { - var self = this; + const self = this; + Em.run.next(function() { self.$("input[type='radio']").prop('checked', false); - var nameKey = self.get('controller.selected.name_key'); - if (!nameKey) return; + const nameKey = self.get('controller.selected.name_key'); + if (!nameKey) { return; } self.$('#radio_' + nameKey).prop('checked', 'true'); }); diff --git a/app/assets/javascripts/discourse/views/forgot-password.js.es6 b/app/assets/javascripts/discourse/views/forgot-password.js.es6 index 5bb6b40ee..40f4094b0 100644 --- a/app/assets/javascripts/discourse/views/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/views/forgot-password.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/forgot_password', title: I18n.t('forgot_password.title'), }); diff --git a/app/assets/javascripts/discourse/views/history.js.es6 b/app/assets/javascripts/discourse/views/history.js.es6 index f88b3f178..7bec4d846 100644 --- a/app/assets/javascripts/discourse/views/history.js.es6 +++ b/app/assets/javascripts/discourse/views/history.js.es6 @@ -1,9 +1,11 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/history', title: I18n.t('history'), resizeModal: function(){ - var viewPortHeight = $(window).height(); + const viewPortHeight = $(window).height(); this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); }.on("didInsertElement") }); diff --git a/app/assets/javascripts/discourse/views/invite-private.js.es6 b/app/assets/javascripts/discourse/views/invite-private.js.es6 index 0b827d29b..461a6e102 100644 --- a/app/assets/javascripts/discourse/views/invite-private.js.es6 +++ b/app/assets/javascripts/discourse/views/invite-private.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/invite_private', title: I18n.t('topic.invite_private.title') }); diff --git a/app/assets/javascripts/discourse/views/invite.js.es6 b/app/assets/javascripts/discourse/views/invite.js.es6 index 6f8a2e8f1..03f4a72c4 100644 --- a/app/assets/javascripts/discourse/views/invite.js.es6 +++ b/app/assets/javascripts/discourse/views/invite.js.es6 @@ -1,10 +1,12 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/invite', + title: function() { - if (this.get('controller.invitingToTopic')) { - return I18n.t('topic.invite_reply.title'); - } else { - return I18n.t('user.invited.create'); - } + return this.get('controller.invitingToTopic') ? + I18n.t('topic.invite_reply.title') : + I18n.t('user.invited.create'); }.property('controller.invitingToTopic') + }); diff --git a/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 b/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 index 33ed36151..eeb174f62 100644 --- a/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 +++ b/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/keyboard_shortcuts_help', title: I18n.t('keyboard_shortcuts_help.title') }); diff --git a/app/assets/javascripts/discourse/views/login.js.es6 b/app/assets/javascripts/discourse/views/login.js.es6 index 334e91774..f2b61efb5 100644 --- a/app/assets/javascripts/discourse/views/login.js.es6 +++ b/app/assets/javascripts/discourse/views/login.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/login', title: I18n.t('login.title'), classNames: ['login-modal'], @@ -9,7 +11,7 @@ export default Discourse.ModalBodyView.extend({ }, _setup: function() { - var loginController = this.get('controller'); + const loginController = this.get('controller'); // Get username and password from the browser's password manager, // if it filled the hidden static login form: @@ -18,10 +20,8 @@ export default Discourse.ModalBodyView.extend({ Em.run.schedule('afterRender', function() { $('#login-account-password, #login-account-name').keydown(function(e) { - if (e.keyCode === 13) { - if (!loginController.get('loginDisabled')) { - loginController.send('login'); - } + if (e.keyCode === 13 && !loginController.get('loginDisabled')) { + loginController.send('login'); } }); }); diff --git a/app/assets/javascripts/discourse/views/merge-topic.js.es6 b/app/assets/javascripts/discourse/views/merge-topic.js.es6 index b4394c57b..bf31e0060 100644 --- a/app/assets/javascripts/discourse/views/merge-topic.js.es6 +++ b/app/assets/javascripts/discourse/views/merge-topic.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/merge_topic', title: I18n.t('topic.merge_topic.title') }); diff --git a/app/assets/javascripts/discourse/views/modal-body.js.es6 b/app/assets/javascripts/discourse/views/modal-body.js.es6 new file mode 100644 index 000000000..720e95516 --- /dev/null +++ b/app/assets/javascripts/discourse/views/modal-body.js.es6 @@ -0,0 +1,30 @@ +export default Discourse.View.extend({ + focusInput: true, + + _setupModal: function() { + $('#modal-alert').hide(); + $('#discourse-modal').modal('show'); + + // Focus on first element + if (!Discourse.Mobile.mobileView && this.get('focusInput')) { + Em.run.schedule('afterRender', () => this.$('input:first').focus() ); + } + + const title = this.get('title'); + if (title) { + this.set('controller.controllers.modal.title', title); + } + }.on('didInsertElement'), + + flashMessageChanged: function() { + const flashMessage = this.get('controller.flashMessage'); + if (flashMessage) { + const messageClass = flashMessage.get('messageClass') || 'success'; + $('#modal-alert').hide() + .removeClass('alert-error', 'alert-success') + .addClass("alert alert-" + messageClass).html(flashMessage.get('message')) + .fadeIn(); + } + }.observes('controller.flashMessage') + +}); diff --git a/app/assets/javascripts/discourse/views/modal.js.es6 b/app/assets/javascripts/discourse/views/modal.js.es6 index 8da41fcc3..4621445dc 100644 --- a/app/assets/javascripts/discourse/views/modal.js.es6 +++ b/app/assets/javascripts/discourse/views/modal.js.es6 @@ -4,13 +4,13 @@ export default Ember.View.extend({ classNameBindings: [':modal', ':hidden', 'controller.modalClass'], click: function(e) { - var $target = $(e.target); + const $target = $(e.target); if ($target.hasClass("modal-middle-container") || $target.hasClass("modal-outer-container")) { - // Delegate click to modal backdrop if clicked outside. We do this - // because some CSS of ours seems to cover the backdrop and makes it - // unclickable. - $('.modal-backdrop').click(); + // Delegate click to modal close if clicked outside. + // We do this because some CSS of ours seems to cover + // the backdrop and makes it unclickable. + $('.modal-header a.close').click(); } } }); diff --git a/app/assets/javascripts/discourse/views/modal_body_view.js b/app/assets/javascripts/discourse/views/modal_body_view.js deleted file mode 100644 index 10eec8f6c..000000000 --- a/app/assets/javascripts/discourse/views/modal_body_view.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - A base class for helping us display modal content - - @class ModalBodyView - @extends Discourse.View - @namespace Discourse - @module Discourse -**/ -Discourse.ModalBodyView = Discourse.View.extend({ - focusInput: true, - - _setupModal: function() { - var self = this, - $discourseModal = $('#discourse-modal'); - - $discourseModal.modal('show'); - $discourseModal.one("hide", function () { - self.get("controller").send("closeModal"); - }); - - $('#modal-alert').hide(); - - // Focus on first element - if (!Discourse.Mobile.mobileView && self.get('focusInput')) { - Em.run.schedule('afterRender', function() { - self.$('input:first').focus(); - }); - } - - var title = this.get('title'); - if (title) { - this.set('controller.controllers.modal.title', title); - } - }.on('didInsertElement'), - - flashMessageChanged: function() { - var flashMessage = this.get('controller.flashMessage'); - if (flashMessage) { - var messageClass = flashMessage.get('messageClass') || 'success'; - var $alert = $('#modal-alert').hide().removeClass('alert-error', 'alert-success'); - $alert.addClass("alert alert-" + messageClass).html(flashMessage.get('message')); - $alert.fadeIn(); - } - }.observes('controller.flashMessage') - -}); - - diff --git a/app/assets/javascripts/discourse/views/not-activated.js.es6 b/app/assets/javascripts/discourse/views/not-activated.js.es6 index 30f4da117..86e942fc3 100644 --- a/app/assets/javascripts/discourse/views/not-activated.js.es6 +++ b/app/assets/javascripts/discourse/views/not-activated.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/not_activated', title: I18n.t('log_in') }); diff --git a/app/assets/javascripts/discourse/views/raw-email.es6 b/app/assets/javascripts/discourse/views/raw-email.es6 index d529b1063..c14d201f3 100644 --- a/app/assets/javascripts/discourse/views/raw-email.es6 +++ b/app/assets/javascripts/discourse/views/raw-email.es6 @@ -1,9 +1,11 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/raw_email', title: I18n.t('raw_email.title'), resizeModal: function(){ - var viewPortHeight = $(window).height(); + const viewPortHeight = $(window).height(); this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); }.on("didInsertElement") }); diff --git a/app/assets/javascripts/discourse/views/search-help.js.es6 b/app/assets/javascripts/discourse/views/search-help.js.es6 index 888c48bb4..d16b2fc79 100644 --- a/app/assets/javascripts/discourse/views/search-help.js.es6 +++ b/app/assets/javascripts/discourse/views/search-help.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/search_help', title: I18n.t('search_help.title'), focusInput: false diff --git a/app/assets/javascripts/discourse/views/split-topic.js.es6 b/app/assets/javascripts/discourse/views/split-topic.js.es6 index b4be70f88..1c5be40e9 100644 --- a/app/assets/javascripts/discourse/views/split-topic.js.es6 +++ b/app/assets/javascripts/discourse/views/split-topic.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend(Discourse.SelectedPostsCount, { +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend(Discourse.SelectedPostsCount, { templateName: 'modal/split_topic', title: I18n.t('topic.split_topic.title') }); diff --git a/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 b/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 index dd6490a71..8b8b693fb 100644 --- a/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 +++ b/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/topic-bulk-actions', title: I18n.t('topics.bulk.actions') }); diff --git a/app/assets/javascripts/discourse/views/upload-selector.js.es6 b/app/assets/javascripts/discourse/views/upload-selector.js.es6 index 50b46b696..2a4697333 100644 --- a/app/assets/javascripts/discourse/views/upload-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/upload-selector.js.es6 @@ -1,10 +1,12 @@ +import ModalBodyView from "discourse/views/modal-body"; + function uploadTranslate(key, options) { - var opts = options || {}; + const opts = options || {}; if (Discourse.Utilities.allowsAttachments()) { key += "_with_attachments"; } return I18n.t("upload_selector." + key, opts); } -export default Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'modal/upload_selector', classNames: ['upload-selector'], @@ -12,17 +14,16 @@ export default Discourse.ModalBodyView.extend({ uploadIcon: function() { return Discourse.Utilities.allowsAttachments() ? "fa-upload" : "fa-picture-o"; }.property(), tip: function() { - var source = this.get("controller.local") ? "local" : "remote"; - var opts = { authorized_extensions: Discourse.Utilities.authorizedExtensions() }; + const source = this.get("controller.local") ? "local" : "remote", + opts = { authorized_extensions: Discourse.Utilities.authorizedExtensions() }; return uploadTranslate(source + "_tip", opts); }.property("controller.local"), hint: function() { // cf. http://stackoverflow.com/a/9851769/11983 - var isChrome = !!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0); - var isFirefox = typeof InstallTrigger !== 'undefined'; - var isSupported = isChrome || isFirefox; - + const isChrome = !!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0), + isFirefox = typeof InstallTrigger !== 'undefined', + isSupported = isChrome || isFirefox; // chrome is the only browser that support copy & paste of images. return I18n.t("upload_selector.hint" + (isSupported ? "_for_supported_browsers" : "")); }.property(), @@ -32,7 +33,7 @@ export default Discourse.ModalBodyView.extend({ }.on('didInsertElement'), selectedChanged: function() { - var self = this; + const self = this; Em.run.next(function() { // *HACK* to select the proper radio button var value = self.get('controller.local') ? 'local' : 'remote'; @@ -47,9 +48,9 @@ export default Discourse.ModalBodyView.extend({ if (this.get("controller.local")) { $('#reply-control').fileupload('add', { fileInput: $('#filename-input') }); } else { - var imageUrl = $('#fileurl-input').val(); - var imageLink = $('#link-input').val(); - var composerView = this.get('controller.composerView'); + const imageUrl = $('#fileurl-input').val(), + imageLink = $('#link-input').val(), + composerView = this.get('controller.composerView'); if (this.get("controller.showMore") && imageLink.length > 3) { composerView.addMarkdown("[![](" + imageUrl +")](" + imageLink + ")"); } else { diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index b6dad34de..489ed3c13 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -36,7 +36,7 @@ //= require ./discourse/controllers/navigation/default //= require ./discourse/views/view //= require ./discourse/views/container -//= require ./discourse/views/modal_body_view +//= require ./discourse/views/modal-body //= require ./discourse/views/flag //= require ./discourse/views/combo-box //= require ./discourse/views/button diff --git a/app/assets/javascripts/main_include_admin.js b/app/assets/javascripts/main_include_admin.js index 9a66a6965..6ba3cb51e 100644 --- a/app/assets/javascripts/main_include_admin.js +++ b/app/assets/javascripts/main_include_admin.js @@ -2,7 +2,6 @@ //= require admin/models/user-field //= require admin/models/site-setting //= require admin/controllers/admin-email-skipped -//= require admin/controllers/change-site-customization-details //= require discourse/lib/export-result //= require_tree ./admin diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index 0f76977cc..cdc7a2819 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -158,6 +158,19 @@ class TopicsController < ApplicationController render_serialized(topics, BasicTopicSerializer) end + def feature_stats + params.require(:category_id) + category_id = params[:category_id].to_i + + topics = Topic.listable_topics.visible + + render json: { + pinned_in_category_count: topics.where(category_id: category_id).where(pinned_globally: false).where.not(pinned_at: nil).count, + pinned_globally_count: topics.where(pinned_globally: true).where.not(pinned_at: nil).count, + banner_count: topics.where(archetype: Archetype.banner).count, + } + end + def status params.require(:status) params.require(:enabled) @@ -492,7 +505,7 @@ class TopicsController < ApplicationController end def check_for_status_presence(key, attr) - invalid_param(key) unless %w(pinned_globally visible closed pinned archived).include?(attr) + invalid_param(key) unless %w(pinned pinned_globally visible closed archived).include?(attr) end def invalid_param(key) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 71609c40e..07738bf14 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -973,10 +973,11 @@ en: open: "Open Topic" close: "Close Topic" auto_close: "Auto Close" + feature: "Feature Topic" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" - unpin: "Un-Pin Topic" pin: "Pin Topic" + unpin: "Un-Pin Topic" pin_globally: "Pin Topic Globally" unarchive: "Unarchive Topic" archive: "Archive Topic" @@ -1002,6 +1003,31 @@ en: help: 'privately flag this topic for attention or send a private notification about it' success_message: 'You successfully flagged this topic.' + feature_topic: + title: "Feature this topic" + pin: "Make this topic appear at the top of the {{categoryLink}} category." + confirm_pin: "Are you sure? You already have {{count}} pinned topics -- too many pinned topics can obscure other active topics." + unpin: "Remove this topic from the topic of the {{categoryLink}} category." + pin_note: "Users can unpin the topic individually for themselves." + already_pinned: + zero: "No topic currently pinned in {{categoryLink}}." + one: "Topic currently pinned in {{categoryLink}}: 1." + other: "Topics currently pinned in {{categoryLink}}: {{count}}." + pin_globally: "Make this topic appear at the top of all topic lists, until a staff member unpins it." + confirm_pin_globally: "Are you sure? You already have {{count}} globally pinned topics -- too many pinned topics can obscure other active topics." + unpin_globally: "Remove this topic from the top of all topic lists." + global_pin_note: "Users can unpin the topic individually for themselves." + already_pinned_globally: + zero: "No topic currently pinned globally." + one: "Topic currently pinned globally: 1." + other: "Topics currently pinned globally: {{count}}." + make_banner: "Make this topic into a banner that appears at the top of all pages." + remove_banner: "Remove the banner that appears at the top of all pages." + banner_note: "Users can dismiss the banner by closing it. Only one topic can be bannered at any given time." + already_banner: + zero: "There is currently no banner topic." + one: "There is currently a banner topic." + inviting: "Inviting..." automatically_add_to_groups_optional: "This invite also includes access to these groups: (optional, admin only)" automatically_add_to_groups_required: "This invite also includes access to these groups: (Required, admin only)" diff --git a/config/routes.rb b/config/routes.rb index c4b3851b2..427a31960 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -392,6 +392,7 @@ Discourse::Application.routes.draw do put "topics/reset-new" => 'topics#reset_new' post "topics/timings" get "topics/similar_to" + get "topics/feature_stats" get "topics/created-by/:username" => "list#topics_by", as: "topics_by", constraints: {username: USERNAME_ROUTE_FORMAT} get "topics/private-messages/:username" => "list#private_messages", as: "topics_private_messages", constraints: {username: USERNAME_ROUTE_FORMAT} get "topics/private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", constraints: {username: USERNAME_ROUTE_FORMAT} diff --git a/test/javascripts/integration/modal-test.js.es6 b/test/javascripts/integration/modal-test.js.es6 index 0a7fc9288..e89dce2b9 100644 --- a/test/javascripts/integration/modal-test.js.es6 +++ b/test/javascripts/integration/modal-test.js.es6 @@ -19,7 +19,7 @@ test("modal", function() { click('.login-button'); andThen(function() { - ok(find('#discourse-modal:visible').length === 1, 'modal should appear'); + ok(find('#discourse-modal:visible').length === 1, 'modal should reappear'); }); keyEvent('#main-outlet', 'keyup', 27);