diff --git a/Gemfile b/Gemfile index fe9faf36a4..f728eef550 100644 --- a/Gemfile +++ b/Gemfile @@ -36,21 +36,12 @@ gem 'mail', require: false gem 'mini_mime' gem 'mini_suffix' -gem 'hiredis' - -# holding off redis upgrade temporarily as it is having issues with our current -# freedom patch, we will follow this up. -# -# FrozenError: can't modify frozen Hash -# /var/www/discourse/vendor/bundle/ruby/2.5.0/gems/redis-4.1.0/lib/redis/client.rb:93:in `delete' -# /var/www/discourse/vendor/bundle/ruby/2.5.0/gems/redis-4.1.0/lib/redis/client.rb:93:in `initialize' -# /var/www/discourse/lib/freedom_patches/redis.rb:7:in `initialize' -gem 'redis', '4.0.1', require: ["redis", "redis/connection/hiredis"] +gem 'redis', '4.1.3' gem 'redis-namespace' gem 'active_model_serializers', '~> 0.8.3' -gem 'onebox', '1.9.17' +gem 'onebox', '1.9.21' gem 'http_accept_language', '~>2.0.5', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 89de47af23..4176a30f6e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -143,7 +143,6 @@ GEM hashdiff (0.3.9) hashie (3.6.0) highline (1.7.10) - hiredis (0.6.3) hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) @@ -173,7 +172,7 @@ GEM logstash-event (1.2.02) logstash-logger (0.26.1) logstash-event (~> 1.2) - logster (2.3.3) + logster (2.4.1) loofah (2.2.3) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -183,7 +182,7 @@ GEM mini_mime (>= 0.1.1) maxminddb (0.1.22) memory_profiler (0.9.13) - message_bus (2.2.2) + message_bus (2.2.3) rack (>= 1.1.3) metaclass (0.0.4) method_source (0.9.2) @@ -200,7 +199,6 @@ GEM mocha (1.8.0) metaclass (~> 0.0.1) mock_redis (0.19.0) - moneta (1.1.1) msgpack (1.2.10) multi_json (1.13.1) multi_xml (0.6.0) @@ -245,9 +243,8 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - onebox (1.9.17) + onebox (1.9.21) htmlentities (~> 4.3) - moneta (~> 1.0) multi_json (~> 1.11) mustache nokogiri (~> 1.7) @@ -274,7 +271,7 @@ GEM puma (3.12.1) r2 (0.2.7) rack (2.0.7) - rack-mini-profiler (1.1.0) + rack-mini-profiler (1.1.3) rack (>= 1.2.0) rack-openid (1.3.1) rack (>= 1.1.0) @@ -310,7 +307,7 @@ GEM msgpack (>= 0.4.3) optimist (>= 3.0.0) rchardet (1.8.0) - redis (4.0.1) + redis (4.1.3) redis-namespace (1.6.0) redis (>= 3.0.4) request_store (1.4.1) @@ -467,7 +464,6 @@ DEPENDENCIES flamegraph gc_tracer highline (~> 1.7.0) - hiredis htmlentities http_accept_language (~> 2.0.5) listen @@ -501,7 +497,7 @@ DEPENDENCIES omniauth-oauth2 omniauth-openid omniauth-twitter - onebox (= 1.9.17) + onebox (= 1.9.21) openid-redis-store parallel_tests pg @@ -518,7 +514,7 @@ DEPENDENCIES rb-inotify (~> 0.9) rbtrace rchardet - redis (= 4.0.1) + redis (= 4.1.3) redis-namespace rinku rotp diff --git a/app/assets/javascripts/admin/adapters/api-key.js.es6 b/app/assets/javascripts/admin/adapters/api-key.js.es6 new file mode 100644 index 0000000000..a473f66e08 --- /dev/null +++ b/app/assets/javascripts/admin/adapters/api-key.js.es6 @@ -0,0 +1,11 @@ +import RESTAdapter from "discourse/adapters/rest"; + +export default RESTAdapter.extend({ + basePath() { + return "/admin/api/"; + }, + + apiNameFor() { + return "key"; + } +}); diff --git a/app/assets/javascripts/admin/adapters/tag-group.js.es6 b/app/assets/javascripts/admin/adapters/tag-group.js.es6 new file mode 100644 index 0000000000..2e950aa2c1 --- /dev/null +++ b/app/assets/javascripts/admin/adapters/tag-group.js.es6 @@ -0,0 +1,5 @@ +import RestAdapter from "discourse/adapters/rest"; + +export default RestAdapter.extend({ + jsonMode: true +}); diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index 8fd9089b2e..60498a0bdb 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -1,7 +1,9 @@ +import Component from "@ember/component"; import loadScript from "discourse/lib/load-script"; import { observes } from "ember-addons/ember-computed-decorators"; +import { on } from "@ember/object/evented"; -export default Ember.Component.extend({ +export default Component.extend({ mode: "css", classNames: ["ace-wrapper"], _editor: null, @@ -48,7 +50,7 @@ export default Ember.Component.extend({ } }, - _destroyEditor: function() { + _destroyEditor: on("willDestroyElement", function() { if (this._editor) { this._editor.destroy(); this._editor = null; @@ -59,7 +61,7 @@ export default Ember.Component.extend({ } $(window).off("ace:resize"); - }.on("willDestroyElement"), + }), resize() { if (this._editor) { diff --git a/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 index 5112564eec..ccacb2e705 100644 --- a/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/components/admin-backups-logs.js.es6 @@ -1,10 +1,12 @@ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import debounce from "discourse/lib/debounce"; import { renderSpinner } from "discourse/helpers/loading-spinner"; import { escapeExpression } from "discourse/lib/utilities"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { observes, on } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNames: ["admin-backups-logs"], @@ -52,7 +54,7 @@ export default Ember.Component.extend( // force rerender this.rerenderBuffer(); - Ember.run.scheduleOnce("afterRender", this, this._scrollDown); + scheduleOnce("afterRender", this, this._scrollDown); }, 150), buildBuffer(buffer) { diff --git a/app/assets/javascripts/admin/components/admin-directory-toggle.js.es6 b/app/assets/javascripts/admin/components/admin-directory-toggle.js.es6 index f2480802b8..f110293a74 100644 --- a/app/assets/javascripts/admin/components/admin-directory-toggle.js.es6 +++ b/app/assets/javascripts/admin/components/admin-directory-toggle.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "th", classNames: ["sortable"], diff --git a/app/assets/javascripts/admin/components/admin-editable-field.js.es6 b/app/assets/javascripts/admin/components/admin-editable-field.js.es6 index 9d91e2a27f..f2785cffd4 100644 --- a/app/assets/javascripts/admin/components/admin-editable-field.js.es6 +++ b/app/assets/javascripts/admin/components/admin-editable-field.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "", buffer: "", diff --git a/app/assets/javascripts/admin/components/admin-form-row.js.es6 b/app/assets/javascripts/admin/components/admin-form-row.js.es6 index 5159168c30..b5f78c2a21 100644 --- a/app/assets/javascripts/admin/components/admin-form-row.js.es6 +++ b/app/assets/javascripts/admin/components/admin-form-row.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["row"] }); diff --git a/app/assets/javascripts/admin/components/admin-graph.js.es6 b/app/assets/javascripts/admin/components/admin-graph.js.es6 index 5949d51e24..be2e0f4e1a 100644 --- a/app/assets/javascripts/admin/components/admin-graph.js.es6 +++ b/app/assets/javascripts/admin/components/admin-graph.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import loadScript from "discourse/lib/load-script"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "canvas", type: "line", diff --git a/app/assets/javascripts/admin/components/admin-nav.js.es6 b/app/assets/javascripts/admin/components/admin-nav.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/admin/components/admin-nav.js.es6 +++ b/app/assets/javascripts/admin/components/admin-nav.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/admin/components/admin-report-chart.js.es6 b/app/assets/javascripts/admin/components/admin-report-chart.js.es6 index 80d35c4693..f55288d9d2 100644 --- a/app/assets/javascripts/admin/components/admin-report-chart.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-chart.js.es6 @@ -1,7 +1,11 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { debounce } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { number } from "discourse/lib/formatter"; import loadScript from "discourse/lib/load-script"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["admin-report-chart"], limit: 8, total: 0, @@ -10,7 +14,7 @@ export default Ember.Component.extend({ this._super(...arguments); this.resizeHandler = () => - Ember.run.debounce(this, this._scheduleChartRendering, 500); + debounce(this, this._scheduleChartRendering, 500); }, didInsertElement() { @@ -30,11 +34,11 @@ export default Ember.Component.extend({ didReceiveAttrs() { this._super(...arguments); - Ember.run.debounce(this, this._scheduleChartRendering, 100); + debounce(this, this._scheduleChartRendering, 100); }, _scheduleChartRendering() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this._renderChart( this.model, this.element && this.element.querySelector(".chart-canvas") @@ -46,10 +50,8 @@ export default Ember.Component.extend({ if (!chartCanvas) return; const context = chartCanvas.getContext("2d"); - const chartData = Ember.makeArray( - model.get("chartData") || model.get("data") - ); - const prevChartData = Ember.makeArray( + const chartData = makeArray(model.get("chartData") || model.get("data")); + const prevChartData = makeArray( model.get("prevChartData") || model.get("prev_data") ); diff --git a/app/assets/javascripts/admin/components/admin-report-counters.js.es6 b/app/assets/javascripts/admin/components/admin-report-counters.js.es6 index d64bbe20fc..a66a3804c2 100644 --- a/app/assets/javascripts/admin/components/admin-report-counters.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-counters.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["admin-report-counters"], attributeBindings: ["model.description:title"] diff --git a/app/assets/javascripts/admin/components/admin-report-counts.js.es6 b/app/assets/javascripts/admin/components/admin-report-counts.js.es6 index 849d81460a..625dd669ee 100644 --- a/app/assets/javascripts/admin/components/admin-report-counts.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-counts.js.es6 @@ -1,7 +1,9 @@ -export default Ember.Component.extend({ +import { match } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ allTime: true, tagName: "tr", - reverseColors: Ember.computed.match( + reverseColors: match( "report.type", /^(time_to_first_response|topics_with_no_response)$/ ), diff --git a/app/assets/javascripts/admin/components/admin-report-inline-table.js.es6 b/app/assets/javascripts/admin/components/admin-report-inline-table.js.es6 index 7e4933381c..38b3d4595e 100644 --- a/app/assets/javascripts/admin/components/admin-report-inline-table.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-inline-table.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["admin-report-inline-table"] }); diff --git a/app/assets/javascripts/admin/components/admin-report-per-day-counts.js.es6 b/app/assets/javascripts/admin/components/admin-report-per-day-counts.js.es6 index b7620b66cd..b644dbab9f 100644 --- a/app/assets/javascripts/admin/components/admin-report-per-day-counts.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-per-day-counts.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "tr" }); diff --git a/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 b/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 index 852bc92b3d..f28a2b348d 100644 --- a/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-stacked-chart.js.es6 @@ -1,14 +1,18 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { debounce } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { number } from "discourse/lib/formatter"; import loadScript from "discourse/lib/load-script"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["admin-report-chart", "admin-report-stacked-chart"], init() { this._super(...arguments); this.resizeHandler = () => - Ember.run.debounce(this, this._scheduleChartRendering, 500); + debounce(this, this._scheduleChartRendering, 500); }, didInsertElement() { @@ -28,11 +32,11 @@ export default Ember.Component.extend({ didReceiveAttrs() { this._super(...arguments); - Ember.run.debounce(this, this._scheduleChartRendering, 100); + debounce(this, this._scheduleChartRendering, 100); }, _scheduleChartRendering() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { if (!this.element) { return; } @@ -49,9 +53,7 @@ export default Ember.Component.extend({ const context = chartCanvas.getContext("2d"); - const chartData = Ember.makeArray( - model.get("chartData") || model.get("data") - ); + const chartData = makeArray(model.get("chartData") || model.get("data")); const data = { labels: chartData[0].data.map(cd => cd.x), diff --git a/app/assets/javascripts/admin/components/admin-report-storage-stats.js.es6 b/app/assets/javascripts/admin/components/admin-report-storage-stats.js.es6 index c4bf831f56..948ecf1e87 100644 --- a/app/assets/javascripts/admin/components/admin-report-storage-stats.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-storage-stats.js.es6 @@ -1,12 +1,14 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import { setting } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["admin-report-storage-stats"], backupLocation: setting("backup_location"), - backupStats: Ember.computed.alias("model.data.backups"), - uploadStats: Ember.computed.alias("model.data.uploads"), + backupStats: alias("model.data.backups"), + uploadStats: alias("model.data.uploads"), @computed("backupStats") showBackupStats(stats) { diff --git a/app/assets/javascripts/admin/components/admin-report-table-cell.js.es6 b/app/assets/javascripts/admin/components/admin-report-table-cell.js.es6 index 7140b69668..f83a33dbfb 100644 --- a/app/assets/javascripts/admin/components/admin-report-table-cell.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-table-cell.js.es6 @@ -1,6 +1,8 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "td", classNames: ["admin-report-table-cell"], classNameBindings: ["type", "property"], @@ -11,8 +13,8 @@ export default Ember.Component.extend({ return label.compute(data, options || {}); }, - type: Ember.computed.alias("label.type"), - property: Ember.computed.alias("label.mainProperty"), - formatedValue: Ember.computed.alias("computedLabel.formatedValue"), - value: Ember.computed.alias("computedLabel.value") + type: alias("label.type"), + property: alias("label.mainProperty"), + formatedValue: alias("computedLabel.formatedValue"), + value: alias("computedLabel.value") }); diff --git a/app/assets/javascripts/admin/components/admin-report-table-header.js.es6 b/app/assets/javascripts/admin/components/admin-report-table-header.js.es6 index ab986f2946..9317ef1f66 100644 --- a/app/assets/javascripts/admin/components/admin-report-table-header.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-table-header.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "th", classNames: ["admin-report-table-header"], classNameBindings: ["label.mainProperty", "label.type", "isCurrentSort"], diff --git a/app/assets/javascripts/admin/components/admin-report-table-row.js.es6 b/app/assets/javascripts/admin/components/admin-report-table-row.js.es6 index 3be140c308..c86f586a08 100644 --- a/app/assets/javascripts/admin/components/admin-report-table-row.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-table-row.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "tr", classNames: ["admin-report-table-row"], options: null diff --git a/app/assets/javascripts/admin/components/admin-report-table.js.es6 b/app/assets/javascripts/admin/components/admin-report-table.js.es6 index 6e1e22c172..38e00c8ab8 100644 --- a/app/assets/javascripts/admin/components/admin-report-table.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-table.js.es6 @@ -1,13 +1,16 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; const PAGES_LIMIT = 8; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: ["sortable", "twoColumns"], classNames: ["admin-report-table"], sortable: false, sortDirection: 1, - perPage: Ember.computed.alias("options.perPage"), + perPage: alias("options.perPage"), page: 0, @computed("model.computedLabels.length") @@ -89,7 +92,7 @@ export default Ember.Component.extend({ @computed("sortLabel", "sortDirection", "model.data.[]") sortedData(sortLabel, sortDirection, data) { - data = Ember.makeArray(data); + data = makeArray(data); if (sortLabel) { const compare = (label, direction) => { diff --git a/app/assets/javascripts/admin/components/admin-report-trust-level-counts.js.es6 b/app/assets/javascripts/admin/components/admin-report-trust-level-counts.js.es6 index b7620b66cd..b644dbab9f 100644 --- a/app/assets/javascripts/admin/components/admin-report-trust-level-counts.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report-trust-level-counts.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "tr" }); diff --git a/app/assets/javascripts/admin/components/admin-report.js.es6 b/app/assets/javascripts/admin/components/admin-report.js.es6 index 37a8f2acc8..db06feecfc 100644 --- a/app/assets/javascripts/admin/components/admin-report.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report.js.es6 @@ -1,3 +1,8 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { alias, or, and, reads, equal, notEmpty } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import ReportLoader from "discourse/lib/reports-loader"; import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; @@ -34,7 +39,7 @@ function collapseWeekly(data, average) { return aggregate; } -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: ["isEnabled", "isLoading", "dasherizedDataSourceName"], classNames: ["admin-report"], isEnabled: true, @@ -54,12 +59,9 @@ export default Ember.Component.extend({ showHeader: true, showTitle: true, showFilteringUI: false, - showDatesOptions: Ember.computed.alias("model.dates_filtering"), - showRefresh: Ember.computed.or( - "showDatesOptions", - "model.available_filters.length" - ), - shouldDisplayTrend: Ember.computed.and("showTrend", "model.prev_period"), + showDatesOptions: alias("model.dates_filtering"), + showRefresh: or("showDatesOptions", "model.available_filters.length"), + shouldDisplayTrend: and("showTrend", "model.prev_period"), init() { this._super(...arguments); @@ -67,8 +69,8 @@ export default Ember.Component.extend({ this._reports = []; }, - startDate: Ember.computed.reads("filters.startDate"), - endDate: Ember.computed.reads("filters.endDate"), + startDate: reads("filters.startDate"), + endDate: reads("filters.endDate"), didReceiveAttrs() { this._super(...arguments); @@ -80,16 +82,12 @@ export default Ember.Component.extend({ } }, - showError: Ember.computed.or( - "showTimeoutError", - "showExceptionError", - "showNotFoundError" - ), - showNotFoundError: Ember.computed.equal("model.error", "not_found"), - showTimeoutError: Ember.computed.equal("model.error", "timeout"), - showExceptionError: Ember.computed.equal("model.error", "exception"), + showError: or("showTimeoutError", "showExceptionError", "showNotFoundError"), + showNotFoundError: equal("model.error", "not_found"), + showTimeoutError: equal("model.error", "timeout"), + showExceptionError: equal("model.error", "exception"), - hasData: Ember.computed.notEmpty("model.data"), + hasData: notEmpty("model.data"), @computed("dataSourceName", "model.type") dasherizedDataSourceName(dataSourceName, type) { @@ -111,7 +109,7 @@ export default Ember.Component.extend({ displayedModes(currentMode, reportModes, forcedModes) { const modes = forcedModes ? forcedModes.split(",") : reportModes; - return Ember.makeArray(modes).map(mode => { + return makeArray(modes).map(mode => { const base = `btn-default mode-btn ${mode}`; const cssClass = currentMode === mode ? `${base} is-current` : base; @@ -311,7 +309,7 @@ export default Ember.Component.extend({ this.setProperties({ isLoading: true, rateLimitationString: null }); - Ember.run.next(() => { + next(() => { let payload = this._buildPayload(["prev_period"]); const callback = response => { @@ -367,12 +365,12 @@ export default Ember.Component.extend({ _buildOptions(mode) { if (mode === "table") { const tableOptions = JSON.parse(JSON.stringify(TABLE_OPTIONS)); - return Ember.Object.create( + return EmberObject.create( Object.assign(tableOptions, this.get("reportOptions.table") || {}) ); } else { const chartOptions = JSON.parse(JSON.stringify(CHART_OPTIONS)); - return Ember.Object.create( + return EmberObject.create( Object.assign(chartOptions, this.get("reportOptions.chart") || {}) ); } diff --git a/app/assets/javascripts/admin/components/admin-theme-editor.js.es6 b/app/assets/javascripts/admin/components/admin-theme-editor.js.es6 index e54cb32c60..1dec9fce37 100644 --- a/app/assets/javascripts/admin/components/admin-theme-editor.js.es6 +++ b/app/assets/javascripts/admin/components/admin-theme-editor.js.es6 @@ -1,7 +1,9 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("theme.targets", "onlyOverridden", "showAdvanced") visibleTargets(targets, onlyOverridden, showAdvanced) { return targets.filter(target => { @@ -82,7 +84,7 @@ export default Ember.Component.extend({ toggleMaximize: function() { this.toggleProperty("maximized"); - Ember.run.next(() => this.appEvents.trigger("ace:resize")); + next(() => this.appEvents.trigger("ace:resize")); }, onlyOverriddenChanged(value) { diff --git a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 index 1bf6128f1c..23bfac19b4 100644 --- a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 +++ b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { empty } from "@ember/object/computed"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import UserField from "admin/models/user-field"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -9,8 +13,8 @@ import { on } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend(bufferedProperty("userField"), { - editing: Ember.computed.empty("userField.id"), +export default Component.extend(bufferedProperty("userField"), { + editing: empty("userField.id"), classNameBindings: [":user-field"], cantMoveUp: propertyEqual("userField", "firstField"), @@ -27,7 +31,7 @@ export default Ember.Component.extend(bufferedProperty("userField"), { @observes("editing") _focusOnEdit() { if (this.editing) { - Ember.run.scheduleOnce("afterRender", this, "_focusName"); + scheduleOnce("afterRender", this, "_focusName"); } }, @@ -93,7 +97,7 @@ export default Ember.Component.extend(bufferedProperty("userField"), { cancel() { const id = this.get("userField.id"); - if (Ember.isEmpty(id)) { + if (isEmpty(id)) { this.destroyAction(this.userField); } else { this.rollbackBuffer(); diff --git a/app/assets/javascripts/admin/components/admin-watched-word.js.es6 b/app/assets/javascripts/admin/components/admin-watched-word.js.es6 index 4da1828021..8a408cf166 100644 --- a/app/assets/javascripts/admin/components/admin-watched-word.js.es6 +++ b/app/assets/javascripts/admin/components/admin-watched-word.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { escapeExpression } from "discourse/lib/utilities"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNames: ["watched-word"], diff --git a/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 index 7a6b5c13f1..1c7f6f05a0 100644 --- a/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 +++ b/app/assets/javascripts/admin/components/admin-web-hook-event-chooser.js.es6 @@ -1,8 +1,10 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["hook-event"], - typeName: Ember.computed.alias("type.name"), + typeName: alias("type.name"), @computed("typeName") name(typeName) { diff --git a/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 index b558baa0b4..693e6502ff 100644 --- a/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 +++ b/app/assets/javascripts/admin/components/admin-web-hook-event.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { ensureJSON, plainJSON, prettyJSON } from "discourse/lib/formatter"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "li", expandDetails: null, expandDetailsRequestKey: "request", diff --git a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 index 6e325b2fe9..0d8e80cc81 100644 --- a/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 +++ b/app/assets/javascripts/admin/components/admin-web-hook-status.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classes: ["text-muted", "text-danger", "text-successful", "text-muted"], icons: ["far-circle", "times-circle", "circle", "circle"], diff --git a/app/assets/javascripts/admin/components/admin-wrapper.js.es6 b/app/assets/javascripts/admin/components/admin-wrapper.js.es6 index 45daf32977..b60ac12855 100644 --- a/app/assets/javascripts/admin/components/admin-wrapper.js.es6 +++ b/app/assets/javascripts/admin/components/admin-wrapper.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ didInsertElement() { this._super(...arguments); $("body").addClass("admin-interface"); diff --git a/app/assets/javascripts/admin/components/cancel-link.js.es6 b/app/assets/javascripts/admin/components/cancel-link.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/admin/components/cancel-link.js.es6 +++ b/app/assets/javascripts/admin/components/cancel-link.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/admin/components/color-input.js.es6 b/app/assets/javascripts/admin/components/color-input.js.es6 index 17783cd36a..6c02f78dd5 100644 --- a/app/assets/javascripts/admin/components/color-input.js.es6 +++ b/app/assets/javascripts/admin/components/color-input.js.es6 @@ -1,3 +1,5 @@ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as loadScript, loadCSS } from "discourse/lib/load-script"; /** @@ -7,7 +9,7 @@ import { default as loadScript, loadCSS } from "discourse/lib/load-script"; @param brightnessValue is a number from 0 to 255 representing the brightness of the color. See ColorSchemeColor. @params valid is a boolean indicating if the input field is a valid color. **/ -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["color-picker"], hexValueChanged: function() { var hex = this.hexValue; @@ -36,7 +38,7 @@ export default Ember.Component.extend({ didInsertElement() { loadScript("/javascripts/spectrum.js").then(() => { loadCSS("/javascripts/spectrum.css").then(() => { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector(".picker")) .spectrum({ color: "#" + this.hexValue }) .on("change.spectrum", (me, color) => { @@ -46,7 +48,7 @@ export default Ember.Component.extend({ }); }); }); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.hexValueChanged(); }); } diff --git a/app/assets/javascripts/admin/components/email-styles-editor.js.es6 b/app/assets/javascripts/admin/components/email-styles-editor.js.es6 index d0e569421f..e465c04cba 100644 --- a/app/assets/javascripts/admin/components/email-styles-editor.js.es6 +++ b/app/assets/javascripts/admin/components/email-styles-editor.js.es6 @@ -1,7 +1,14 @@ +import { reads } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ - editorId: Ember.computed.reads("fieldName"), +export default Component.extend({ + editorId: reads("fieldName"), + + @computed("fieldName") + currentEditorMode(fieldName) { + return fieldName === "css" ? "scss" : fieldName; + }, @computed("fieldName", "styles.html", "styles.css") resetDisabled(fieldName) { diff --git a/app/assets/javascripts/admin/components/embeddable-host.js.es6 b/app/assets/javascripts/admin/components/embeddable-host.js.es6 index 7639312ceb..57829b45fb 100644 --- a/app/assets/javascripts/admin/components/embeddable-host.js.es6 +++ b/app/assets/javascripts/admin/components/embeddable-host.js.es6 @@ -1,26 +1,30 @@ +import { isEmpty } from "@ember/utils"; +import { or } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import computed from "ember-addons/ember-computed-decorators"; import { on, observes } from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Component.extend(bufferedProperty("host"), { +export default Component.extend(bufferedProperty("host"), { editToggled: false, tagName: "tr", categoryId: null, - editing: Ember.computed.or("host.isNew", "editToggled"), + editing: or("host.isNew", "editToggled"), @on("didInsertElement") @observes("editing") _focusOnInput() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.element.querySelector(".host-name").focus(); }); }, @computed("buffered.host", "host.isSaving") cantSave(host, isSaving) { - return isSaving || Ember.isEmpty(host); + return isSaving || isEmpty(host); }, actions: { diff --git a/app/assets/javascripts/admin/components/embedding-setting.js.es6 b/app/assets/javascripts/admin/components/embedding-setting.js.es6 index 4791e84e35..da7f9abb7f 100644 --- a/app/assets/javascripts/admin/components/embedding-setting.js.es6 +++ b/app/assets/javascripts/admin/components/embedding-setting.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["embed-setting"], @computed("field") diff --git a/app/assets/javascripts/admin/components/flag-user-lists.js.es6 b/app/assets/javascripts/admin/components/flag-user-lists.js.es6 index ae6094c6a7..a6156a93ad 100644 --- a/app/assets/javascripts/admin/components/flag-user-lists.js.es6 +++ b/app/assets/javascripts/admin/components/flag-user-lists.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["flag-user-lists"] }); diff --git a/app/assets/javascripts/admin/components/highlighted-code.js.es6 b/app/assets/javascripts/admin/components/highlighted-code.js.es6 index 9f99c0929b..d182d7e2a1 100644 --- a/app/assets/javascripts/admin/components/highlighted-code.js.es6 +++ b/app/assets/javascripts/admin/components/highlighted-code.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { on, observes } from "ember-addons/ember-computed-decorators"; import highlightSyntax from "discourse/lib/highlight-syntax"; -export default Ember.Component.extend({ +export default Component.extend({ @on("didInsertElement") @observes("code") _refresh: function() { diff --git a/app/assets/javascripts/admin/components/inline-edit-checkbox.js.es6 b/app/assets/javascripts/admin/components/inline-edit-checkbox.js.es6 index a31b436167..e88c2bc3b7 100644 --- a/app/assets/javascripts/admin/components/inline-edit-checkbox.js.es6 +++ b/app/assets/javascripts/admin/components/inline-edit-checkbox.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["inline-edit"], checked: null, diff --git a/app/assets/javascripts/admin/components/install-theme-item.js.es6 b/app/assets/javascripts/admin/components/install-theme-item.js.es6 index c1f3f57a8c..040760db01 100644 --- a/app/assets/javascripts/admin/components/install-theme-item.js.es6 +++ b/app/assets/javascripts/admin/components/install-theme-item.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["install-theme-item"] }); diff --git a/app/assets/javascripts/admin/components/ip-lookup.js.es6 b/app/assets/javascripts/admin/components/ip-lookup.js.es6 index d4bf91ec6a..8438a4ee5c 100644 --- a/app/assets/javascripts/admin/components/ip-lookup.js.es6 +++ b/app/assets/javascripts/admin/components/ip-lookup.js.es6 @@ -1,9 +1,12 @@ +import EmberObject from "@ember/object"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { ajax } from "discourse/lib/ajax"; import AdminUser from "admin/models/admin-user"; import copyText from "discourse/lib/copy-text"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["ip-lookup"], @computed("other_accounts.length", "totalOthersWithSameIP") @@ -20,7 +23,7 @@ export default Ember.Component.extend({ if (!this.location) { ajax("/admin/users/ip-info", { data: { ip: this.ip } }).then(location => - this.set("location", Ember.Object.create(location)) + this.set("location", EmberObject.create(location)) ); } @@ -76,7 +79,7 @@ export default Ember.Component.extend({ $(document.body).append($copyRange); if (copyText(text, $copyRange[0])) { this.set("copied", true); - Ember.run.later(() => this.set("copied", false), 2000); + later(() => this.set("copied", false), 2000); } $copyRange.remove(); }, diff --git a/app/assets/javascripts/admin/components/moderation-history-item.js.es6 b/app/assets/javascripts/admin/components/moderation-history-item.js.es6 index b7620b66cd..b644dbab9f 100644 --- a/app/assets/javascripts/admin/components/moderation-history-item.js.es6 +++ b/app/assets/javascripts/admin/components/moderation-history-item.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "tr" }); diff --git a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 index e60393b3ba..8af1f83b16 100644 --- a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 +++ b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 @@ -1,8 +1,11 @@ +import { equal } from "@ember/object/computed"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; const ACTIONS = ["delete", "delete_replies", "edit", "none"]; -export default Ember.Component.extend({ +export default Component.extend({ postId: null, postAction: null, postEdit: null, @@ -14,7 +17,7 @@ export default Ember.Component.extend({ }); }, - editing: Ember.computed.equal("postAction", "edit"), + editing: equal("postAction", "edit"), actions: { penaltyChanged() { @@ -22,7 +25,7 @@ export default Ember.Component.extend({ // If we switch to edit mode, jump to the edit textarea if (postAction === "edit") { - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { let elem = this.element; let body = elem.closest(".modal-body"); body.scrollTop(body.height()); diff --git a/app/assets/javascripts/admin/components/permalink-form.js.es6 b/app/assets/javascripts/admin/components/permalink-form.js.es6 index 40ae69d090..b1f82ea295 100644 --- a/app/assets/javascripts/admin/components/permalink-form.js.es6 +++ b/app/assets/javascripts/admin/components/permalink-form.js.es6 @@ -1,8 +1,10 @@ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; import Permalink from "admin/models/permalink"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["permalink-form"], formSubmitted: false, permalinkType: "topic_id", @@ -19,7 +21,7 @@ export default Ember.Component.extend({ }, focusPermalink() { - Ember.run.schedule("afterRender", () => + schedule("afterRender", () => this.element.querySelector(".permalink-url").focus() ); }, @@ -68,7 +70,7 @@ export default Ember.Component.extend({ didInsertElement() { this._super(...arguments); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector(".external-url")).keydown(e => { // enter key if (e.keyCode === 13) { diff --git a/app/assets/javascripts/admin/components/report-filters/filter.js.es6 b/app/assets/javascripts/admin/components/report-filters/filter.js.es6 index 25f2464f95..f61b2d496a 100644 --- a/app/assets/javascripts/admin/components/report-filters/filter.js.es6 +++ b/app/assets/javascripts/admin/components/report-filters/filter.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ actions: { onChange(value) { this.applyFilter(this.get("filter.id"), value); diff --git a/app/assets/javascripts/admin/components/resumable-upload.js.es6 b/app/assets/javascripts/admin/components/resumable-upload.js.es6 index b9cab23040..d63a1a651d 100644 --- a/app/assets/javascripts/admin/components/resumable-upload.js.es6 +++ b/app/assets/javascripts/admin/components/resumable-upload.js.es6 @@ -1,3 +1,6 @@ +import { schedule } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { @@ -17,7 +20,7 @@ import { uploadText="UPLOAD" }} **/ -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "button", classNames: ["btn", "ru"], @@ -44,18 +47,16 @@ export default Ember.Component.extend( this.resumable.upload(); // mark as uploading - Ember.run.later(() => this.set("isUploading", true)); + later(() => this.set("isUploading", true)); }); this.resumable.on("fileProgress", file => { // update progress - Ember.run.later(() => - this.set("progress", parseInt(file.progress() * 100, 10)) - ); + later(() => this.set("progress", parseInt(file.progress() * 100, 10))); }); this.resumable.on("fileSuccess", file => { - Ember.run.later(() => { + later(() => { // mark as not uploading anymore this._reset(); @@ -65,7 +66,7 @@ export default Ember.Component.extend( }); this.resumable.on("fileError", (file, message) => { - Ember.run.later(() => { + later(() => { // mark as not uploading anymore this._reset(); @@ -77,7 +78,7 @@ export default Ember.Component.extend( @on("didInsertElement") _assignBrowse() { - Ember.run.schedule("afterRender", () => + schedule("afterRender", () => this.resumable.assignBrowse($(this.element)) ); }, @@ -116,7 +117,7 @@ export default Ember.Component.extend( click() { if (this.isUploading) { this.resumable.cancel(); - Ember.run.later(() => this._reset()); + later(() => this._reset()); return false; } else { return true; diff --git a/app/assets/javascripts/admin/components/save-controls.js.es6 b/app/assets/javascripts/admin/components/save-controls.js.es6 index cade010e5b..b039b0158c 100644 --- a/app/assets/javascripts/admin/components/save-controls.js.es6 +++ b/app/assets/javascripts/admin/components/save-controls.js.es6 @@ -1,9 +1,11 @@ +import { or } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["controls"], - buttonDisabled: Ember.computed.or("model.isSaving", "saveDisabled"), + buttonDisabled: or("model.isSaving", "saveDisabled"), @computed("model.isSaving") savingText(saving) { diff --git a/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 b/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 index 7fb246bf7a..8b6db57764 100644 --- a/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 +++ b/app/assets/javascripts/admin/components/screened-ip-address-form.js.es6 @@ -1,3 +1,5 @@ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; /** A form to create an IP address that will be blocked or whitelisted. Example usage: @@ -13,7 +15,7 @@ import ScreenedIpAddress from "admin/models/screened-ip-address"; import computed from "ember-addons/ember-computed-decorators"; import { on } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["screened-ip-address-form"], formSubmitted: false, actionName: "block", @@ -61,7 +63,7 @@ export default Ember.Component.extend({ .then(result => { this.setProperties({ ip_address: "", formSubmitted: false }); this.action(ScreenedIpAddress.create(result.screened_ip_address)); - Ember.run.schedule("afterRender", () => + schedule("afterRender", () => this.element.querySelector(".ip-address-input").focus() ); }) @@ -83,7 +85,7 @@ export default Ember.Component.extend({ @on("didInsertElement") _init() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector(".ip-address-input")).keydown(e => { if (e.keyCode === 13) { this.send("submit"); diff --git a/app/assets/javascripts/admin/components/secret-value-list.js.es6 b/app/assets/javascripts/admin/components/secret-value-list.js.es6 index 58539cb916..4327f62f80 100644 --- a/app/assets/javascripts/admin/components/secret-value-list.js.es6 +++ b/app/assets/javascripts/admin/components/secret-value-list.js.es6 @@ -1,6 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; import { on } from "ember-addons/ember-computed-decorators"; +import { set } from "@ember/object"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [":value-list", ":secret-value-list"], inputDelimiter: null, collection: null, @@ -42,7 +45,7 @@ export default Ember.Component.extend({ _checkInvalidInput(inputs) { this.set("validationMessage", null); for (let input of inputs) { - if (Ember.isEmpty(input) || input.includes("|")) { + if (isEmpty(input) || input.includes("|")) { this.set( "validationMessage", I18n.t("admin.site_settings.secret_list.invalid_input") @@ -65,7 +68,7 @@ export default Ember.Component.extend({ _replaceValue(index, newValue, keyName) { let item = this.collection[index]; - Ember.set(item, keyName, newValue); + set(item, keyName, newValue); this._saveValues(); }, diff --git a/app/assets/javascripts/admin/components/silence-details.js.es6 b/app/assets/javascripts/admin/components/silence-details.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/admin/components/silence-details.js.es6 +++ b/app/assets/javascripts/admin/components/silence-details.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/admin/components/site-setting.js.es6 b/app/assets/javascripts/admin/components/site-setting.js.es6 index 78696c6e06..cd768407ff 100644 --- a/app/assets/javascripts/admin/components/site-setting.js.es6 +++ b/app/assets/javascripts/admin/components/site-setting.js.es6 @@ -1,10 +1,15 @@ +import Component from "@ember/component"; import BufferedContent from "discourse/mixins/buffered-content"; import SiteSetting from "admin/models/site-setting"; import SettingComponent from "admin/mixins/setting-component"; -export default Ember.Component.extend(BufferedContent, SettingComponent, { +export default Component.extend(BufferedContent, SettingComponent, { + updateExistingUsers: null, + _save() { const setting = this.buffered; - return SiteSetting.update(setting.get("setting"), setting.get("value")); + return SiteSetting.update(setting.get("setting"), setting.get("value"), { + updateExistingUsers: this.updateExistingUsers + }); } }); diff --git a/app/assets/javascripts/admin/components/site-settings/bool.js.es6 b/app/assets/javascripts/admin/components/site-settings/bool.js.es6 index f46e965832..2b2fdaca8e 100644 --- a/app/assets/javascripts/admin/components/site-settings/bool.js.es6 +++ b/app/assets/javascripts/admin/components/site-settings/bool.js.es6 @@ -1,10 +1,12 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("value") enabled: { get(value) { - if (Ember.isEmpty(value)) { + if (isEmpty(value)) { return false; } return value.toString() === "true"; diff --git a/app/assets/javascripts/admin/components/site-settings/category-list.js.es6 b/app/assets/javascripts/admin/components/site-settings/category-list.js.es6 index 36c712fa8d..d4476ddf13 100644 --- a/app/assets/javascripts/admin/components/site-settings/category-list.js.es6 +++ b/app/assets/javascripts/admin/components/site-settings/category-list.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("value") selectedCategories: { get(value) { diff --git a/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 b/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 index 0ab60a3436..21af030269 100644 --- a/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 +++ b/app/assets/javascripts/admin/components/site-settings/group-list.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed() groupChoices() { return this.site.get("groups").map(g => { diff --git a/app/assets/javascripts/admin/components/site-settings/tag-list.js.es6 b/app/assets/javascripts/admin/components/site-settings/tag-list.js.es6 new file mode 100644 index 0000000000..417ad622cb --- /dev/null +++ b/app/assets/javascripts/admin/components/site-settings/tag-list.js.es6 @@ -0,0 +1,15 @@ +import Component from "@ember/component"; +import computed from "ember-addons/ember-computed-decorators"; + +export default Component.extend({ + @computed("value") + selectedTags: { + get(value) { + return value.split("|"); + }, + set(value) { + this.set("value", value.join("|")); + return value; + } + } +}); diff --git a/app/assets/javascripts/admin/components/site-settings/uploaded-image-list.js.es6 b/app/assets/javascripts/admin/components/site-settings/uploaded-image-list.js.es6 index 57bd7fa49b..7e705321d0 100644 --- a/app/assets/javascripts/admin/components/site-settings/uploaded-image-list.js.es6 +++ b/app/assets/javascripts/admin/components/site-settings/uploaded-image-list.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import showModal from "discourse/lib/show-modal"; -export default Ember.Component.extend({ +export default Component.extend({ actions: { showUploadModal({ value, setting }) { showModal("admin-uploaded-image-list", { diff --git a/app/assets/javascripts/admin/components/site-text-summary.js.es6 b/app/assets/javascripts/admin/components/site-text-summary.js.es6 index da6dda43f8..4467a092d1 100644 --- a/app/assets/javascripts/admin/components/site-text-summary.js.es6 +++ b/app/assets/javascripts/admin/components/site-text-summary.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { on } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["site-text"], classNameBindings: ["siteText.overridden"], diff --git a/app/assets/javascripts/admin/components/staff-actions.js.es6 b/app/assets/javascripts/admin/components/staff-actions.js.es6 index 5c7da1dc9d..1c295799dd 100644 --- a/app/assets/javascripts/admin/components/staff-actions.js.es6 +++ b/app/assets/javascripts/admin/components/staff-actions.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import DiscourseURL from "discourse/lib/url"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["table", "staff-actions"], willDestroyElement() { diff --git a/app/assets/javascripts/admin/components/suspension-details.js.es6 b/app/assets/javascripts/admin/components/suspension-details.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/admin/components/suspension-details.js.es6 +++ b/app/assets/javascripts/admin/components/suspension-details.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/admin/components/tags-uploader.js.es6 b/app/assets/javascripts/admin/components/tags-uploader.js.es6 index 1373792f24..88f4afc8d9 100644 --- a/app/assets/javascripts/admin/components/tags-uploader.js.es6 +++ b/app/assets/javascripts/admin/components/tags-uploader.js.es6 @@ -1,9 +1,11 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import UploadMixin from "discourse/mixins/upload"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "csv", uploadUrl: "/tags/upload", - addDisabled: Ember.computed.alias("uploading"), + addDisabled: alias("uploading"), elementId: "tag-uploader", validateUploadedFilesOptions() { diff --git a/app/assets/javascripts/admin/components/theme-setting-editor.js.es6 b/app/assets/javascripts/admin/components/theme-setting-editor.js.es6 index 5a764e55eb..e0ebe6ccdd 100644 --- a/app/assets/javascripts/admin/components/theme-setting-editor.js.es6 +++ b/app/assets/javascripts/admin/components/theme-setting-editor.js.es6 @@ -1,10 +1,11 @@ +import Component from "@ember/component"; import BufferedContent from "discourse/mixins/buffered-content"; import SettingComponent from "admin/mixins/setting-component"; import { ajax } from "discourse/lib/ajax"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Component.extend(BufferedContent, SettingComponent, { +export default Component.extend(BufferedContent, SettingComponent, { layoutName: "admin/templates/components/site-setting", + _save() { return ajax(`/admin/themes/${this.model.id}/setting`, { type: "PUT", @@ -12,6 +13,6 @@ export default Ember.Component.extend(BufferedContent, SettingComponent, { name: this.setting.setting, value: this.get("buffered.value") } - }).catch(popupAjaxError); + }); } }); diff --git a/app/assets/javascripts/admin/components/theme-translation.js.es6 b/app/assets/javascripts/admin/components/theme-translation.js.es6 index ab29ac2312..361df489af 100644 --- a/app/assets/javascripts/admin/components/theme-translation.js.es6 +++ b/app/assets/javascripts/admin/components/theme-translation.js.es6 @@ -1,11 +1,13 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import BufferedContent from "discourse/mixins/buffered-content"; import SettingComponent from "admin/mixins/setting-component"; -export default Ember.Component.extend(BufferedContent, SettingComponent, { +export default Component.extend(BufferedContent, SettingComponent, { layoutName: "admin/templates/components/site-setting", - setting: Ember.computed.alias("translation"), + setting: alias("translation"), type: "string", - settingName: Ember.computed.alias("translation.key"), + settingName: alias("translation.key"), _save() { return this.model.saveTranslation( diff --git a/app/assets/javascripts/admin/components/themes-list-item.js.es6 b/app/assets/javascripts/admin/components/themes-list-item.js.es6 index 7bafa95c21..af30e5a398 100644 --- a/app/assets/javascripts/admin/components/themes-list-item.js.es6 +++ b/app/assets/javascripts/admin/components/themes-list-item.js.es6 @@ -1,3 +1,6 @@ +import { gt, and } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes @@ -7,13 +10,13 @@ import { escape } from "pretty-text/sanitizer"; const MAX_COMPONENTS = 4; -export default Ember.Component.extend({ +export default Component.extend({ childrenExpanded: false, classNames: ["themes-list-item"], classNameBindings: ["theme.selected:selected"], - hasComponents: Ember.computed.gt("children.length", 0), - displayComponents: Ember.computed.and("hasComponents", "theme.isActive"), - displayHasMore: Ember.computed.gt("theme.childThemes.length", MAX_COMPONENTS), + hasComponents: gt("children.length", 0), + displayComponents: and("hasComponents", "theme.isActive"), + displayHasMore: gt("theme.childThemes.length", MAX_COMPONENTS), click(e) { if (!$(e.target).hasClass("others-count")) { @@ -32,7 +35,7 @@ export default Ember.Component.extend({ }, scheduleAnimation() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.animate(true); }); }, diff --git a/app/assets/javascripts/admin/components/themes-list.js.es6 b/app/assets/javascripts/admin/components/themes-list.js.es6 index d306bab11c..357e4f756c 100644 --- a/app/assets/javascripts/admin/components/themes-list.js.es6 +++ b/app/assets/javascripts/admin/components/themes-list.js.es6 @@ -1,18 +1,20 @@ +import { gt, equal } from "@ember/object/computed"; +import Component from "@ember/component"; import { THEMES, COMPONENTS } from "admin/models/theme"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ THEMES: THEMES, COMPONENTS: COMPONENTS, classNames: ["themes-list"], - hasThemes: Ember.computed.gt("themesList.length", 0), - hasActiveThemes: Ember.computed.gt("activeThemes.length", 0), - hasInactiveThemes: Ember.computed.gt("inactiveThemes.length", 0), + hasThemes: gt("themesList.length", 0), + hasActiveThemes: gt("activeThemes.length", 0), + hasInactiveThemes: gt("inactiveThemes.length", 0), - themesTabActive: Ember.computed.equal("currentTab", THEMES), - componentsTabActive: Ember.computed.equal("currentTab", COMPONENTS), + themesTabActive: equal("currentTab", THEMES), + componentsTabActive: equal("currentTab", COMPONENTS), @computed("themes", "components", "currentTab") themesList(themes, components) { diff --git a/app/assets/javascripts/admin/components/value-list.js.es6 b/app/assets/javascripts/admin/components/value-list.js.es6 index ff93375260..31ef93932e 100644 --- a/app/assets/javascripts/admin/components/value-list.js.es6 +++ b/app/assets/javascripts/admin/components/value-list.js.es6 @@ -1,17 +1,20 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { empty, alias } from "@ember/object/computed"; +import Component from "@ember/component"; import { on } from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [":value-list"], - inputInvalid: Ember.computed.empty("newValue"), + inputInvalid: empty("newValue"), inputDelimiter: null, inputType: null, newValue: "", collection: null, values: null, - noneKey: Ember.computed.alias("addKey"), + noneKey: alias("addKey"), @on("didReceiveAttrs") _setupCollection() { @@ -29,7 +32,7 @@ export default Ember.Component.extend({ @computed("choices.[]", "collection.[]") filteredChoices(choices, collection) { - return Ember.makeArray(choices).filter(i => collection.indexOf(i) < 0); + return makeArray(choices).filter(i => collection.indexOf(i) < 0); }, keyDown(event) { diff --git a/app/assets/javascripts/admin/components/watched-word-form.js.es6 b/app/assets/javascripts/admin/components/watched-word-form.js.es6 index b56f2c423c..629c5a2b6a 100644 --- a/app/assets/javascripts/admin/components/watched-word-form.js.es6 +++ b/app/assets/javascripts/admin/components/watched-word-form.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import WatchedWord from "admin/models/watched-word"; import { default as computed, @@ -5,7 +8,7 @@ import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["watched-word-form"], formSubmitted: false, actionKey: null, @@ -21,7 +24,7 @@ export default Ember.Component.extend({ @observes("word") removeMessage() { - if (this.showMessage && !Ember.isEmpty(this.word)) { + if (this.showMessage && !isEmpty(this.word)) { this.set("showMessage", false); } }, @@ -63,7 +66,7 @@ export default Ember.Component.extend({ message: I18n.t("admin.watched_words.form.success") }); this.action(WatchedWord.create(result)); - Ember.run.schedule("afterRender", () => + schedule("afterRender", () => this.element.querySelector(".watched-word-input").focus() ); }) @@ -85,7 +88,7 @@ export default Ember.Component.extend({ @on("didInsertElement") _init() { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector(".watched-word-input")).keydown(e => { if (e.keyCode === 13) { this.send("submit"); diff --git a/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 b/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 index b1706337f2..417f3d5bbf 100644 --- a/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 +++ b/app/assets/javascripts/admin/components/watched-word-uploader.js.es6 @@ -1,11 +1,13 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "txt", classNames: "watched-words-uploader", uploadUrl: "/admin/logs/watched_words/upload", - addDisabled: Ember.computed.alias("uploading"), + addDisabled: alias("uploading"), validateUploadedFilesOptions() { return { skipValidation: true }; diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys-index.js.es6 new file mode 100644 index 0000000000..b087269626 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-api-keys-index.js.es6 @@ -0,0 +1,13 @@ +import { popupAjaxError } from "discourse/lib/ajax-error"; + +export default Ember.Controller.extend({ + actions: { + revokeKey(key) { + key.revoke().catch(popupAjaxError); + }, + + undoRevokeKey(key) { + key.undoRevoke().catch(popupAjaxError); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys-new.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys-new.js.es6 new file mode 100644 index 0000000000..f4d56c0a05 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-api-keys-new.js.es6 @@ -0,0 +1,39 @@ +import { default as computed } from "ember-addons/ember-computed-decorators"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +export default Ember.Controller.extend({ + userModes: [ + { id: "all", name: I18n.t("admin.api.all_users") }, + { id: "single", name: I18n.t("admin.api.single_user") } + ], + + @computed("userMode") + showUserSelector(mode) { + return mode === "single"; + }, + + @computed("model.description", "model.username", "userMode") + saveDisabled(description, username, userMode) { + if (Ember.isBlank(description)) return true; + if (userMode === "single" && Ember.isBlank(username)) return true; + return false; + }, + + actions: { + changeUserMode(value) { + if (value === "all") { + this.model.set("username", null); + } + this.set("userMode", value); + }, + + save() { + this.model + .save() + .then(() => { + this.transitionToRoute("adminApiKeys.show", this.model.id); + }) + .catch(popupAjaxError); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys-show.js.es6 new file mode 100644 index 0000000000..2e19ea5779 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin-api-keys-show.js.es6 @@ -0,0 +1,54 @@ +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { empty } from "@ember/object/computed"; + +export default Ember.Controller.extend(bufferedProperty("model"), { + isNew: empty("model.id"), + + actions: { + saveDescription() { + const buffered = this.buffered; + const attrs = buffered.getProperties("description"); + + this.model + .save(attrs) + .then(() => { + this.set("editingDescription", false); + this.rollbackBuffer(); + }) + .catch(popupAjaxError); + }, + + cancel() { + const id = this.get("userField.id"); + if (Ember.isEmpty(id)) { + this.destroyAction(this.userField); + } else { + this.rollbackBuffer(); + this.set("editing", false); + } + }, + + editDescription() { + this.toggleProperty("editingDescription"); + if (!this.editingDescription) { + this.rollbackBuffer(); + } + }, + + revokeKey(key) { + key.revoke().catch(popupAjaxError); + }, + + deleteKey(key) { + key + .destroyRecord() + .then(() => this.transitionToRoute("adminApiKeys.index")) + .catch(popupAjaxError); + }, + + undoRevokeKey(key) { + key.undoRevoke().catch(popupAjaxError); + } + } +}); diff --git a/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 index 87b26f5ef1..e69de29bb2 100644 --- a/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-api-keys.js.es6 @@ -1,41 +0,0 @@ -import ApiKey from "admin/models/api-key"; -import { default as computed } from "ember-addons/ember-computed-decorators"; - -export default Ember.Controller.extend({ - @computed("model.[]") - hasMasterKey(model) { - return !!model.findBy("user", null); - }, - - actions: { - generateMasterKey() { - ApiKey.generateMasterKey().then(key => this.model.pushObject(key)); - }, - - regenerateKey(key) { - bootbox.confirm( - I18n.t("admin.api.confirm_regen"), - I18n.t("no_value"), - I18n.t("yes_value"), - result => { - if (result) { - key.regenerate(); - } - } - ); - }, - - revokeKey(key) { - bootbox.confirm( - I18n.t("admin.api.confirm_revoke"), - I18n.t("no_value"), - I18n.t("yes_value"), - result => { - if (result) { - key.revoke().then(() => this.model.removeObject(key)); - } - } - ); - } - } -}); diff --git a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 index 684f844bc5..6b69eaea72 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 @@ -1,13 +1,16 @@ +import { alias, equal } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { setting, i18n } from "discourse/lib/computed"; -export default Ember.Controller.extend({ - adminBackups: Ember.inject.controller(), - status: Ember.computed.alias("adminBackups.model"), +export default Controller.extend({ + adminBackups: inject(), + status: alias("adminBackups.model"), uploadLabel: i18n("admin.backups.upload.label"), backupLocation: setting("backup_location"), - localBackupStorage: Ember.computed.equal("backupLocation", "local"), + localBackupStorage: equal("backupLocation", "local"), @computed("status.allowRestore", "status.isOperationRunning") restoreTitle(allowRestore, isOperationRunning) { diff --git a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 index 40bad8ae00..a32e216255 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 @@ -1,6 +1,9 @@ -export default Ember.Controller.extend({ - adminBackups: Ember.inject.controller(), - status: Ember.computed.alias("adminBackups.model"), +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; +export default Controller.extend({ + adminBackups: inject(), + status: alias("adminBackups.model"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/admin/controllers/admin-backups.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups.js.es6 index 5cfa57271e..7e942d9e9c 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups.js.es6 @@ -1,9 +1,11 @@ -export default Ember.Controller.extend({ - noOperationIsRunning: Ember.computed.not("model.isOperationRunning"), - rollbackEnabled: Ember.computed.and( +import { not, and } from "@ember/object/computed"; +import Controller from "@ember/controller"; +export default Controller.extend({ + noOperationIsRunning: not("model.isOperationRunning"), + rollbackEnabled: and( "model.canRollback", "model.restoreEnabled", "noOperationIsRunning" ), - rollbackDisabled: Ember.computed.not("rollbackEnabled") + rollbackDisabled: not("rollbackEnabled") }); diff --git a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 index 1f7382f54b..733f4589fe 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 @@ -1,21 +1,22 @@ +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import { propertyNotEqual } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(bufferedProperty("model"), { - adminBadges: Ember.inject.controller(), +export default Controller.extend(bufferedProperty("model"), { + adminBadges: inject(), saving: false, savingStatus: "", - badgeTypes: Ember.computed.alias("adminBadges.badgeTypes"), - badgeGroupings: Ember.computed.alias("adminBadges.badgeGroupings"), - badgeTriggers: Ember.computed.alias("adminBadges.badgeTriggers"), - protectedSystemFields: Ember.computed.alias( - "adminBadges.protectedSystemFields" - ), + badgeTypes: alias("adminBadges.badgeTypes"), + badgeGroupings: alias("adminBadges.badgeGroupings"), + badgeTriggers: alias("adminBadges.badgeTriggers"), + protectedSystemFields: alias("adminBadges.protectedSystemFields"), - readOnly: Ember.computed.alias("buffered.system"), + readOnly: alias("buffered.system"), showDisplayName: propertyNotEqual("name", "displayName"), @computed("model.query", "buffered.query") diff --git a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges.js.es6 index 77c79b724a..cf6c4e3aa2 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges.js.es6 @@ -1 +1,2 @@ -export default Ember.Controller.extend(); +import Controller from "@ember/controller"; +export default Controller.extend(); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 index 3fbdb989cf..ce99c2cfea 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 @@ -1,6 +1,8 @@ +import { later } from "@ember/runloop"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ @computed("model.colors", "onlyOverridden") colors(allColors, onlyOverridden) { if (onlyOverridden) { @@ -40,7 +42,7 @@ export default Ember.Controller.extend({ ); } - Ember.run.later(() => { + later(() => { this.set("model.savingStatus", null); }, 2000); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 index 7a9be8cc5d..21c628be24 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 @@ -1,7 +1,9 @@ +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import showModal from "discourse/lib/show-modal"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ @computed("model.@each.id") baseColorScheme() { return this.model.findBy("is_base", true); @@ -14,7 +16,7 @@ export default Ember.Controller.extend({ @computed("baseColorScheme") baseColors(baseColorScheme) { - const baseColorsHash = Ember.Object.create({}); + const baseColorsHash = EmberObject.create({}); baseColorScheme.get("colors").forEach(color => { baseColorsHash.set(color.get("name"), color); }); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 index b8054c8bc3..f48f46eff0 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-style-edit.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ @computed("model.isSaving") saveButtonText(isSaving) { return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save"); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-templates-edit.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-templates-edit.js.es6 index 68a78a7d7f..5ec405594a 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-email-templates-edit.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-templates-edit.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(bufferedProperty("emailTemplate"), { +export default Controller.extend(bufferedProperty("emailTemplate"), { saved: false, @computed("buffered.body", "buffered.subject") diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 index 8631babc67..2f85e8418d 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 @@ -1,6 +1,8 @@ -export default Ember.Controller.extend({ +import { sort } from "@ember/object/computed"; +import Controller from "@ember/controller"; +export default Controller.extend({ emailTemplates: null, - sortedTemplates: Ember.computed.sort("emailTemplates", "titleSorting"), + sortedTemplates: sort("emailTemplates", "titleSorting"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 index 9cb38c75ea..5c6d2499f4 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-robots-txt.js.es6 @@ -1,12 +1,14 @@ +import { not } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import { propertyEqual } from "discourse/lib/computed"; -export default Ember.Controller.extend(bufferedProperty("model"), { +export default Controller.extend(bufferedProperty("model"), { saved: false, isSaving: false, saveDisabled: propertyEqual("model.robots_txt", "buffered.robots_txt"), - resetDisbaled: Ember.computed.not("model.overridden"), + resetDisbaled: not("model.overridden"), actions: { save() { diff --git a/app/assets/javascripts/admin/controllers/admin-customize-themes-edit.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-themes-edit.js.es6 index ba54e3c91f..a5a286bf80 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-themes-edit.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-themes-edit.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { url } from "discourse/lib/computed"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ section: null, currentTarget: 0, maximized: false, diff --git a/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 index fc211ce628..d4622e21d8 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-themes-show.js.es6 @@ -1,3 +1,6 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { empty, notEmpty, match } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { url } from "discourse/lib/computed"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -7,10 +10,10 @@ import { THEMES, COMPONENTS } from "admin/models/theme"; const THEME_UPLOAD_VAR = 2; -export default Ember.Controller.extend({ +export default Controller.extend({ downloadUrl: url("model.id", "/admin/customize/themes/%@/export"), previewUrl: url("model.id", "/admin/themes/%@/preview"), - addButtonDisabled: Ember.computed.empty("selectedChildThemeId"), + addButtonDisabled: empty("selectedChildThemeId"), editRouteName: "adminCustomizeThemes.edit", @computed("model.editedFields") @@ -79,14 +82,14 @@ export default Ember.Controller.extend({ return settings.map(setting => ThemeSettings.create(setting)); }, - hasSettings: Ember.computed.notEmpty("settings"), + hasSettings: notEmpty("settings"), @computed("model.translations") translations(translations) { return translations.map(setting => ThemeSettings.create(setting)); }, - hasTranslations: Ember.computed.notEmpty("translations"), + hasTranslations: notEmpty("translations"), @computed("model.remoteError", "updatingRemote") showRemoteError(errorMessage, updating) { @@ -124,8 +127,8 @@ export default Ember.Controller.extend({ }); this.get("parentController.model.content").forEach(theme => { - const children = Ember.makeArray(theme.get("childThemes")); - const rawChildren = Ember.makeArray(theme.get("child_themes")); + const children = makeArray(theme.get("childThemes")); + const rawChildren = makeArray(theme.get("child_themes")); const index = children ? children.indexOf(model) : -1; if (index > -1) { children.splice(index, 1); @@ -147,10 +150,7 @@ export default Ember.Controller.extend({ "scss" ); }, - sourceIsHttp: Ember.computed.match( - "model.remote_theme.remote_url", - /^http(s)?:\/\// - ), + sourceIsHttp: match("model.remote_theme.remote_url", /^http(s)?:\/\//), actions: { updateToLatest() { this.set("updatingRemote", true); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-themes.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-themes.js.es6 index f38ae3ab74..6727df97f3 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-themes.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-themes.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { THEMES } from "admin/models/theme"; -export default Ember.Controller.extend({ +export default Controller.extend({ currentTab: THEMES, @computed("model", "model.@each.component") diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 index eb85ef4a41..24884b0ba6 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-general.js.es6 @@ -1,3 +1,6 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { setting } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; import AdminDashboard from "admin/models/admin-dashboard"; @@ -6,16 +9,14 @@ import PeriodComputationMixin from "admin/mixins/period-computation"; function staticReport(reportType) { return Ember.computed("reports.[]", function() { - return Ember.makeArray(this.reports).find( - report => report.type === reportType - ); + return makeArray(this.reports).find(report => report.type === reportType); }); } -export default Ember.Controller.extend(PeriodComputationMixin, { +export default Controller.extend(PeriodComputationMixin, { isLoading: false, dashboardFetchedAt: null, - exceptionController: Ember.inject.controller("exception"), + exceptionController: inject("exception"), logSearchQueriesEnabled: setting("log_search_queries"), basePath: Discourse.BaseUri, @@ -93,7 +94,7 @@ export default Ember.Controller.extend(PeriodComputationMixin, { this.setProperties({ dashboardFetchedAt: new Date(), model: adminDashboardModel, - reports: Ember.makeArray(adminDashboardModel.reports).map(x => + reports: makeArray(adminDashboardModel.reports).map(x => Report.create(x) ) }); diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js.es6 index df06e682f4..e5d8dae25a 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-moderation.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import PeriodComputationMixin from "admin/mixins/period-computation"; -export default Ember.Controller.extend(PeriodComputationMixin, { +export default Controller.extend(PeriodComputationMixin, { @computed flagsStatusOptions() { return { diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js.es6 index 9c2eccdab1..b582f733aa 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-reports.js.es6 @@ -1,7 +1,9 @@ +import { debounce } from "@ember/runloop"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; const { get } = Ember; -export default Ember.Controller.extend({ +export default Controller.extend({ filter: null, @computed("model.[]", "filter") @@ -20,7 +22,7 @@ export default Ember.Controller.extend({ actions: { filterReports(filter) { - Ember.run.debounce(this, this._performFiltering, filter, 250); + debounce(this, this._performFiltering, filter, 250); } }, diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 index 0ff4b540d1..0f214d6f2d 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 @@ -1,3 +1,5 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { setting } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; import AdminDashboard from "admin/models/admin-dashboard"; @@ -5,10 +7,10 @@ import VersionCheck from "admin/models/version-check"; const PROBLEMS_CHECK_MINUTES = 1; -export default Ember.Controller.extend({ +export default Controller.extend({ isLoading: false, dashboardFetchedAt: null, - exceptionController: Ember.inject.controller("exception"), + exceptionController: inject("exception"), showVersionChecks: setting("version_checks"), @computed("problems.length") diff --git a/app/assets/javascripts/admin/controllers/admin-email-advanced-test.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-advanced-test.js.es6 index c98fb7cfb9..8443344349 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-advanced-test.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-advanced-test.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ email: null, text: null, elided: null, diff --git a/app/assets/javascripts/admin/controllers/admin-email-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-index.js.es6 index 02860948c0..124c364af3 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-index.js.es6 @@ -1,11 +1,13 @@ +import { empty } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Controller.extend({ +export default Controller.extend({ /** Is the "send test email" button disabled? @property sendTestEmailDisabled **/ - sendTestEmailDisabled: Ember.computed.empty("testEmailAddress"), + sendTestEmailDisabled: empty("testEmailAddress"), /** Clears the 'sentTestEmail' property on successful send. diff --git a/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 index c7c2df8c95..49a84ea6d1 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-logs.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import EmailLog from "admin/models/email-log"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, loadLogs(sourceModel, loadMore) { diff --git a/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 b/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 index 407478d681..66b393196a 100644 --- a/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-email-preview-digest.js.es6 @@ -1,14 +1,16 @@ +import { empty, or, notEmpty } from "@ember/object/computed"; +import Controller from "@ember/controller"; import EmailPreview from "admin/models/email-preview"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ username: null, lastSeen: null, - emailEmpty: Ember.computed.empty("email"), - sendEmailDisabled: Ember.computed.or("emailEmpty", "sendingEmail"), - showSendEmailForm: Ember.computed.notEmpty("model.html_content"), - htmlEmpty: Ember.computed.empty("model.html_content"), + emailEmpty: empty("email"), + sendEmailDisabled: or("emailEmpty", "sendingEmail"), + showSendEmailForm: notEmpty("model.html_content"), + htmlEmpty: empty("model.html_content"), actions: { refresh() { diff --git a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 index a8b522130c..7e185e9d12 100644 --- a/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-embedding.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ saved: false, embedding: null, diff --git a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 index d110904338..6a1d295759 100644 --- a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 @@ -1,6 +1,9 @@ +import { sort } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Controller.extend({ - sortedEmojis: Ember.computed.sort("model", "emojiSorting"), +export default Controller.extend({ + sortedEmojis: sort("model", "emojiSorting"), init() { this._super(...arguments); @@ -11,7 +14,7 @@ export default Ember.Controller.extend({ actions: { emojiUploaded(emoji) { emoji.url += "?t=" + new Date().getTime(); - this.model.pushObject(Ember.Object.create(emoji)); + this.model.pushObject(EmberObject.create(emoji)); }, destroy(emoji) { diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 index 2a410f7705..5b0908c363 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-emails.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; import ScreenedEmail from "admin/models/screened-email"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, actions: { diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 index 66ffe3c08c..2e404eb29d 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-ip-addresses.js.es6 @@ -1,9 +1,10 @@ +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; import { outputExportResult } from "discourse/lib/export-result"; import { exportEntity } from "discourse/lib/export-csv"; import ScreenedIpAddress from "admin/models/screened-ip-address"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, filter: null, savedIpAddress: null, diff --git a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 index ef01562302..3f33783184 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-screened-urls.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; import ScreenedUrl from "admin/models/screened-url"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, show() { diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 index a3d332c1f5..a375379fc0 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 @@ -1,3 +1,7 @@ +import { gt } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { scheduleOnce } from "@ember/runloop"; +import Controller from "@ember/controller"; import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; import { @@ -5,10 +9,10 @@ import { on } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ model: null, filters: null, - filtersExists: Ember.computed.gt("filterCount", 0), + filtersExists: gt("filterCount", 0), userHistoryActions: null, @computed("filters.action_name") @@ -19,14 +23,14 @@ export default Ember.Controller.extend({ @on("init") resetFilters() { this.setProperties({ - model: Ember.Object.create({ loadingMore: true }), - filters: Ember.Object.create() + model: EmberObject.create({ loadingMore: true }), + filters: EmberObject.create() }); this.scheduleRefresh(); }, _changeFilters(props) { - this.set("model", Ember.Object.create({ loadingMore: true })); + this.set("model", EmberObject.create({ loadingMore: true })); this.filters.setProperties(props); this.scheduleRefresh(); }, @@ -66,7 +70,7 @@ export default Ember.Controller.extend({ }, scheduleRefresh() { - Ember.run.scheduleOnce("afterRender", this, this._refresh); + scheduleOnce("afterRender", this, this._refresh); }, actions: { diff --git a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 index 45e88514a0..d024c83051 100644 --- a/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-permalinks.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; import Permalink from "admin/models/permalink"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, filter: null, diff --git a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 index 36b1f7ca11..c0322317e5 100644 --- a/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-plugins.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ @computed adminRoutes: function() { return this.model diff --git a/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6 index 2a78ece7f4..359be15f1d 100644 --- a/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-reports-show.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ queryParams: ["start_date", "end_date", "filters"], start_date: null, end_date: null, diff --git a/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 index 5c26cb0e9f..397b4c9b9e 100644 --- a/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; export const DEFAULT_PERIOD = "yearly"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, period: DEFAULT_PERIOD, searchType: "all", diff --git a/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 b/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 index 229aa67db8..66def62c97 100644 --- a/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import { DEFAULT_PERIOD } from "admin/controllers/admin-search-logs-index"; -export default Ember.Controller.extend({ +export default Controller.extend({ loading: false, term: null, period: DEFAULT_PERIOD, diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 index a5831299ec..3fd10f15d1 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-settings-category.js.es6 @@ -1,8 +1,10 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ categoryNameKey: null, - adminSiteSettings: Ember.inject.controller(), + adminSiteSettings: inject(), @computed("adminSiteSettings.visibleSiteSettings", "categoryNameKey") category(categories, nameKey) { diff --git a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 index 09a335946d..fe35885617 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-settings.js.es6 @@ -1,14 +1,17 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; -export default Ember.Controller.extend({ +export default Controller.extend({ filter: null, - allSiteSettings: Ember.computed.alias("model"), + allSiteSettings: alias("model"), visibleSiteSettings: null, onlyOverridden: false, filterContentNow(category) { // If we have no content, don't bother filtering anything - if (!!Ember.isEmpty(this.allSiteSettings)) return; + if (!!isEmpty(this.allSiteSettings)) return; let filter; if (this.filter) { diff --git a/app/assets/javascripts/admin/controllers/admin-site-text-edit.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-text-edit.js.es6 index 4aa1c3d428..cd815b9ae8 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-text-edit.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-text-edit.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(bufferedProperty("siteText"), { +export default Controller.extend(bufferedProperty("siteText"), { saved: false, @computed("buffered.value") diff --git a/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 index 1c484e4287..1a1b266ae1 100644 --- a/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-site-text-index.js.es6 @@ -1,6 +1,8 @@ +import { debounce } from "@ember/runloop"; +import Controller from "@ember/controller"; let lastSearch; -export default Ember.Controller.extend({ +export default Controller.extend({ searching: false, siteTexts: null, preferred: false, @@ -26,14 +28,14 @@ export default Ember.Controller.extend({ toggleOverridden() { this.toggleProperty("overridden"); this.set("searching", true); - Ember.run.debounce(this, this._performSearch, 400); + debounce(this, this._performSearch, 400); }, search() { const q = this.q; if (q !== lastSearch) { this.set("searching", true); - Ember.run.debounce(this, this._performSearch, 400); + debounce(this, this._performSearch, 400); lastSearch = q; } } diff --git a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 index d419cf9e34..fac3436c6e 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 @@ -1,13 +1,17 @@ +import { alias, sort } from "@ember/object/computed"; +import { next } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import GrantBadgeController from "discourse/mixins/grant-badge-controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(GrantBadgeController, { - adminUser: Ember.inject.controller(), - user: Ember.computed.alias("adminUser.model"), - userBadges: Ember.computed.alias("model"), - allBadges: Ember.computed.alias("badges"), - sortedBadges: Ember.computed.sort("model", "badgeSortOrder"), +export default Controller.extend(GrantBadgeController, { + adminUser: inject(), + user: alias("adminUser.model"), + userBadges: alias("model"), + allBadges: alias("badges"), + sortedBadges: sort("model", "badgeSortOrder"), init() { this._super(...arguments); @@ -69,7 +73,7 @@ export default Ember.Controller.extend(GrantBadgeController, { ).then( () => { this.set("badgeReason", ""); - Ember.run.next(() => { + next(() => { // Update the selected badge ID after the combobox has re-rendered. const newSelectedBadge = this.grantableBadges[0]; if (newSelectedBadge) { diff --git a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 index 7d2a6b3d56..b81b08f559 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 @@ -1,11 +1,13 @@ +import { gte, sort } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; const MAX_FIELDS = 20; -export default Ember.Controller.extend({ +export default Controller.extend({ fieldTypes: null, - createDisabled: Ember.computed.gte("model.length", MAX_FIELDS), - sortedFields: Ember.computed.sort("model", "fieldSortOrder"), + createDisabled: gte("model.length", MAX_FIELDS), + sortedFields: sort("model", "fieldSortOrder"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index 4a24bbd4b5..de2e37668f 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -1,3 +1,6 @@ +import { notEmpty, and } from "@ember/object/computed"; +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import { propertyNotEqual, setting } from "discourse/lib/computed"; @@ -5,25 +8,24 @@ import { userPath } from "discourse/lib/url"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; +import { htmlSafe } from "@ember/template"; -export default Ember.Controller.extend(CanCheckEmails, { - adminTools: Ember.inject.service(), +export default Controller.extend(CanCheckEmails, { + adminTools: service(), originalPrimaryGroupId: null, customGroupIdsBuffer: null, availableGroups: null, userTitleValue: null, showBadges: setting("enable_badges"), - hasLockedTrustLevel: Ember.computed.notEmpty( - "model.manual_locked_trust_level" - ), + hasLockedTrustLevel: notEmpty("model.manual_locked_trust_level"), primaryGroupDirty: propertyNotEqual( "originalPrimaryGroupId", "model.primary_group_id" ), - canDisableSecondFactor: Ember.computed.and( + canDisableSecondFactor: and( "model.second_factor_enabled", "model.can_disable_second_factor" ), @@ -46,7 +48,7 @@ export default Ember.Controller.extend(CanCheckEmails, { automaticGroups(automaticGroups) { return automaticGroups .map(group => { - const name = Ember.String.htmlSafe(group.name); + const name = htmlSafe(group.name); return `${name}`; }) .join(", "); @@ -257,10 +259,6 @@ export default Ember.Controller.extend(CanCheckEmails, { .finally(() => this.toggleProperty("editingTitle")); }, - generateApiKey() { - this.model.generateApiKey(); - }, - saveCustomGroups() { const currentIds = this.customGroupIds; const bufferedIds = this.customGroupIdsBuffer; @@ -293,32 +291,6 @@ export default Ember.Controller.extend(CanCheckEmails, { resetPrimaryGroup() { this.set("model.primary_group_id", this.originalPrimaryGroupId); - }, - - regenerateApiKey() { - bootbox.confirm( - I18n.t("admin.api.confirm_regen"), - I18n.t("no_value"), - I18n.t("yes_value"), - result => { - if (result) { - this.model.generateApiKey(); - } - } - ); - }, - - revokeApiKey() { - bootbox.confirm( - I18n.t("admin.api.confirm_revoke"), - I18n.t("no_value"), - I18n.t("yes_value"), - result => { - if (result) { - this.model.revokeApiKey(); - } - } - ); } } }); diff --git a/app/assets/javascripts/admin/controllers/admin-user.js.es6 b/app/assets/javascripts/admin/controllers/admin-user.js.es6 index 77c79b724a..cf6c4e3aa2 100644 --- a/app/assets/javascripts/admin/controllers/admin-user.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user.js.es6 @@ -1 +1,2 @@ -export default Ember.Controller.extend(); +import Controller from "@ember/controller"; +export default Controller.extend(); diff --git a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 index 743e68d24b..944b0d9485 100644 --- a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 @@ -1,10 +1,11 @@ +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; import { i18n } from "discourse/lib/computed"; import AdminUser from "admin/models/admin-user"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(CanCheckEmails, { +export default Controller.extend(CanCheckEmails, { model: null, query: null, order: null, diff --git a/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 b/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 index cf4a28e2d3..1726446d8c 100644 --- a/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-watched-words-action.js.es6 @@ -1,13 +1,17 @@ +import { or } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import WatchedWord from "admin/models/watched-word"; import { ajax } from "discourse/lib/ajax"; import { fmt } from "discourse/lib/computed"; import showModal from "discourse/lib/show-modal"; -export default Ember.Controller.extend({ +export default Controller.extend({ actionNameKey: null, - adminWatchedWords: Ember.inject.controller(), - showWordsList: Ember.computed.or( + adminWatchedWords: inject(), + showWordsList: or( "adminWatchedWords.filtered", "adminWatchedWords.showWords" ), @@ -49,7 +53,7 @@ export default Ember.Controller.extend({ if (a) { a.words.unshiftObject(arg); a.incrementProperty("count"); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { // remove from other actions lists let match = null; this.get("adminWatchedWords.model").forEach(action => { diff --git a/app/assets/javascripts/admin/controllers/admin-watched-words.js.es6 b/app/assets/javascripts/admin/controllers/admin-watched-words.js.es6 index 20ed611781..397c5b030e 100644 --- a/app/assets/javascripts/admin/controllers/admin-watched-words.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-watched-words.js.es6 @@ -1,14 +1,18 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; -export default Ember.Controller.extend({ +export default Controller.extend({ filter: null, filtered: false, showWords: false, - disableShowWords: Ember.computed.alias("filtered"), + disableShowWords: alias("filtered"), regularExpressions: null, filterContentNow() { - if (!!Ember.isEmpty(this.allWatchedWords)) return; + if (!!isEmpty(this.allWatchedWords)) return; let filter; if (this.filter) { @@ -27,7 +31,7 @@ export default Ember.Controller.extend({ return wordRecord.word.indexOf(filter) > -1; }); matchesByAction.pushObject( - Ember.Object.create({ + EmberObject.create({ nameKey: wordsForAction.nameKey, name: wordsForAction.name, words: wordRecords, @@ -41,7 +45,7 @@ export default Ember.Controller.extend({ filterContent: debounce(function() { this.filterContentNow(); - this.set("filtered", !Ember.isEmpty(this.filter)); + this.set("filtered", !isEmpty(this.filter)); }, 250).observes("filter"), actions: { diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 index 388fab304f..e550a79069 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 @@ -1,10 +1,12 @@ +import { alias } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ pingDisabled: false, - incomingCount: Ember.computed.alias("incomingEventIds.length"), + incomingCount: alias("incomingEventIds.length"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 index 2a637d7278..83de79e1f0 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show.js.es6 @@ -1,13 +1,17 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { extractDomainFromUrl } from "discourse/lib/utilities"; import computed from "ember-addons/ember-computed-decorators"; import InputValidation from "discourse/models/input-validation"; -export default Ember.Controller.extend({ - adminWebHooks: Ember.inject.controller(), - eventTypes: Ember.computed.alias("adminWebHooks.eventTypes"), - defaultEventTypes: Ember.computed.alias("adminWebHooks.defaultEventTypes"), - contentTypes: Ember.computed.alias("adminWebHooks.contentTypes"), +export default Controller.extend({ + adminWebHooks: inject(), + eventTypes: alias("adminWebHooks.eventTypes"), + defaultEventTypes: alias("adminWebHooks.defaultEventTypes"), + contentTypes: alias("adminWebHooks.contentTypes"), @computed showTagsFilter() { @@ -35,7 +39,7 @@ export default Ember.Controller.extend({ @computed("model.secret") secretValidation(secret) { - if (!Ember.isEmpty(secret)) { + if (!isEmpty(secret)) { if (secret.indexOf(" ") !== -1) { return InputValidation.create({ failed: true, @@ -54,7 +58,7 @@ export default Ember.Controller.extend({ @computed("model.wildcard_web_hook", "model.web_hook_event_types.[]") eventTypeValidation(isWildcard, eventTypes) { - if (!isWildcard && Ember.isEmpty(eventTypes)) { + if (!isWildcard && isEmpty(eventTypes)) { return InputValidation.create({ failed: true, reason: I18n.t("admin.web_hooks.event_type_missing") @@ -76,7 +80,7 @@ export default Ember.Controller.extend({ ) { return isSaving ? false - : secretValidation || eventTypeValidation || Ember.isEmpty(payloadUrl); + : secretValidation || eventTypeValidation || isEmpty(payloadUrl); }, actions: { diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 index 696541c1cf..f9f401e330 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ actions: { destroy(webhook) { return bootbox.confirm( diff --git a/app/assets/javascripts/admin/controllers/admin.js.es6 b/app/assets/javascripts/admin/controllers/admin.js.es6 index a79cf81944..f01a898b0c 100644 --- a/app/assets/javascripts/admin/controllers/admin.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin.js.es6 @@ -1,7 +1,10 @@ +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; +import { dasherize } from "@ember/string"; -export default Ember.Controller.extend({ - router: Ember.inject.service(), +export default Controller.extend({ + router: service(), @computed("siteSettings.enable_group_directory") showGroups(enableGroupDirectory) { @@ -25,7 +28,7 @@ export default Ember.Controller.extend({ segment !== "admin" ); }) - .map(Ember.String.dasherize) + .map(dasherize) .join(" "); // this is done to avoid breaking css customizations diff --git a/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 index 73f1f1e11f..d53278c856 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-add-upload.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { and, not } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; import { @@ -52,8 +56,8 @@ const SCSS_VARIABLE_NAMES = [ "love-low" ]; -export default Ember.Controller.extend(ModalFunctionality, { - adminCustomizeThemesShow: Ember.inject.controller(), +export default Controller.extend(ModalFunctionality, { + adminCustomizeThemesShow: inject(), uploadUrl: "/admin/themes/upload_asset", @@ -62,8 +66,8 @@ export default Ember.Controller.extend(ModalFunctionality, { this.set("fileSelected", false); }, - enabled: Ember.computed.and("nameValid", "fileSelected"), - disabled: Ember.computed.not("enabled"), + enabled: and("nameValid", "fileSelected"), + disabled: not("enabled"), @computed("name", "adminCustomizeThemesShow.model.theme_fields") errorMessage(name, themeFields) { @@ -104,7 +108,7 @@ export default Ember.Controller.extend(ModalFunctionality, { actions: { updateName() { let name = this.name; - if (Ember.isEmpty(name)) { + if (isEmpty(name)) { name = $("#file-input")[0].files[0].name; this.set("name", name.split(".")[0]); } diff --git a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 index 045a96c2aa..b6419c8e04 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 @@ -1,10 +1,12 @@ +import { alias, map } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { escapeExpression } from "discourse/lib/utilities"; -export default Ember.Controller.extend({ - sample: Ember.computed.alias("model.sample"), - errors: Ember.computed.alias("model.errors"), - count: Ember.computed.alias("model.grant_count"), +export default Controller.extend({ + sample: alias("model.sample"), + errors: alias("model.errors"), + count: alias("model.grant_count"), @computed("count", "sample.length") countWarning(count, sampleLength) { @@ -33,7 +35,7 @@ export default Ember.Controller.extend({ return output; }, - processedSample: Ember.computed.map("model.sample", grant => { + processedSample: map("model.sample", grant => { let i18nKey = "admin.badges.preview.grant.with"; const i18nParams = { username: escapeExpression(grant.username) }; diff --git a/app/assets/javascripts/admin/controllers/modals/admin-color-scheme-select-base.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-color-scheme-select-base.js.es6 index 374b6392f4..ea64338a83 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-color-scheme-select-base.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-color-scheme-select-base.js.es6 @@ -1,7 +1,9 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { - adminCustomizeColors: Ember.inject.controller(), +export default Controller.extend(ModalFunctionality, { + adminCustomizeColors: inject(), actions: { selectBase() { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 index 76dc4c07d7..4d0c66143c 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @observes("model") modelChanged() { const model = this.model; diff --git a/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6 index e19afcd359..210d664cda 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6 @@ -1,10 +1,11 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import IncomingEmail from "admin/models/incoming-email"; import computed from "ember-addons/ember-computed-decorators"; import { longDate } from "discourse/lib/formatter"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @computed("model.date") date(d) { return longDate(d); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 index a81e8caef7..81055d733d 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 @@ -1,3 +1,6 @@ +import { equal, match, alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -7,28 +10,29 @@ import { } from "ember-addons/ember-computed-decorators"; import { THEMES, COMPONENTS } from "admin/models/theme"; import { POPULAR_THEMES } from "discourse-common/helpers/popular-themes"; +import { set } from "@ember/object"; const MIN_NAME_LENGTH = 4; -export default Ember.Controller.extend(ModalFunctionality, { - popular: Ember.computed.equal("selection", "popular"), - local: Ember.computed.equal("selection", "local"), - remote: Ember.computed.equal("selection", "remote"), - create: Ember.computed.equal("selection", "create"), +export default Controller.extend(ModalFunctionality, { + popular: equal("selection", "popular"), + local: equal("selection", "local"), + remote: equal("selection", "remote"), + create: equal("selection", "create"), selection: "popular", - adminCustomizeThemes: Ember.inject.controller(), + adminCustomizeThemes: inject(), loading: false, keyGenUrl: "/admin/themes/generate_key_pair", importUrl: "/admin/themes/import", recordType: "theme", - checkPrivate: Ember.computed.match("uploadUrl", /^git/), + checkPrivate: match("uploadUrl", /^git/), localFile: null, uploadUrl: null, urlPlaceholder: "https://github.com/discourse/sample_theme", advancedVisible: false, - themesController: Ember.inject.controller("adminCustomizeThemes"), - selectedType: Ember.computed.alias("themesController.currentTab"), - component: Ember.computed.equal("selectedType", COMPONENTS), + themesController: inject("adminCustomizeThemes"), + selectedType: alias("themesController.currentTab"), + component: equal("selectedType", COMPONENTS), init() { this._super(...arguments); @@ -43,7 +47,7 @@ export default Ember.Controller.extend(ModalFunctionality, { themes(installedThemes) { return POPULAR_THEMES.map(t => { if (installedThemes.includes(t.name)) { - Ember.set(t, "installed", true); + set(t, "installed", true); } return t; }); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-reseed.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-reseed.js.es6 index f71c7eaf2e..176c46be36 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-reseed.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-reseed.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: true, reseeding: false, categories: null, diff --git a/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6 index 79ec3e6945..5c04066941 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-silence-user.js.es6 @@ -1,7 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import PenaltyController from "admin/mixins/penalty-controller"; -export default Ember.Controller.extend(PenaltyController, { +export default Controller.extend(PenaltyController, { silenceUntil: null, silencing: false, @@ -12,9 +14,7 @@ export default Ember.Controller.extend(PenaltyController, { @computed("silenceUntil", "reason", "silencing") submitDisabled(silenceUntil, reason, silencing) { - return ( - silencing || Ember.isEmpty(silenceUntil) || !reason || reason.length < 1 - ); + return silencing || isEmpty(silenceUntil) || !reason || reason.length < 1; }, actions: { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 index 23420631f0..06110e0113 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 @@ -1,3 +1,4 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality); +export default Controller.extend(ModalFunctionality); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 index 7bd96b326a..b4cc2f188d 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 @@ -1,7 +1,9 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { - adminBackupsLogs: Ember.inject.controller(), +export default Controller.extend(ModalFunctionality, { + adminBackupsLogs: inject(), actions: { startBackupWithUploads() { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 index c5911322c5..c5afea9d88 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 @@ -1,7 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import PenaltyController from "admin/mixins/penalty-controller"; -export default Ember.Controller.extend(PenaltyController, { +export default Controller.extend(PenaltyController, { suspendUntil: null, suspending: false, @@ -12,9 +14,7 @@ export default Ember.Controller.extend(PenaltyController, { @computed("suspendUntil", "reason", "suspending") submitDisabled(suspendUntil, reason, suspending) { - return ( - suspending || Ember.isEmpty(suspendUntil) || !reason || reason.length < 1 - ); + return suspending || isEmpty(suspendUntil) || !reason || reason.length < 1; }, actions: { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-theme-change.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-theme-change.js.es6 index 834376a2d6..e33284d233 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-theme-change.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-theme-change.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loadDiff() { this.set("loading", true); ajax( diff --git a/app/assets/javascripts/admin/controllers/modals/admin-uploaded-image-list.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-uploaded-image-list.js.es6 index 22aa327651..a5ac891c21 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-uploaded-image-list.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-uploaded-image-list.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { on, observes } from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @on("init") @observes("model.value") _setup() { diff --git a/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 index 7af6650ca6..10f90ee615 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-watched-word-test.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @computed("value", "model.compiledRegularExpression") matches(value, regexpString) { if (!value || !regexpString) return; diff --git a/app/assets/javascripts/admin/controllers/modals/site-setting-default-categories.js.es6 b/app/assets/javascripts/admin/controllers/modals/site-setting-default-categories.js.es6 new file mode 100644 index 0000000000..62e77ed8e6 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/modals/site-setting-default-categories.js.es6 @@ -0,0 +1,20 @@ +import Controller from "@ember/controller"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; + +export default Controller.extend(ModalFunctionality, { + onShow() { + this.set("updateExistingUsers", null); + }, + + actions: { + updateExistingUsers() { + this.set("updateExistingUsers", true); + this.send("closeModal"); + }, + + cancel() { + this.set("updateExistingUsers", false); + this.send("closeModal"); + } + } +}); diff --git a/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 b/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 index 2a2440a294..0e1ea29a27 100644 --- a/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 +++ b/app/assets/javascripts/admin/helpers/disposition-icon.js.es6 @@ -1,6 +1,7 @@ import { iconHTML } from "discourse-common/lib/icon-library"; +import Helper from "@ember/component/helper"; -export default Ember.Helper.extend({ +export default Helper.extend({ compute([disposition]) { if (!disposition) { return null; diff --git a/app/assets/javascripts/admin/helpers/post-action-title.js.es6 b/app/assets/javascripts/admin/helpers/post-action-title.js.es6 index 5ce437bf4a..657aee2e9b 100644 --- a/app/assets/javascripts/admin/helpers/post-action-title.js.es6 +++ b/app/assets/javascripts/admin/helpers/post-action-title.js.es6 @@ -1,3 +1,5 @@ +import Helper from "@ember/component/helper"; + function postActionTitle([id, nameKey]) { let title = I18n.t(`admin.flags.short_names.${nameKey}`, { defaultValue: null @@ -11,4 +13,4 @@ function postActionTitle([id, nameKey]) { return title; } -export default Ember.Helper.helper(postActionTitle); +export default Helper.helper(postActionTitle); diff --git a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 index b38e249da3..cb07e9d2ca 100644 --- a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 +++ b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 @@ -1,7 +1,9 @@ import ModalFunctionality from "discourse/mixins/modal-functionality"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import Mixin from "@ember/object/mixin"; +import { Promise } from "rsvp"; -export default Ember.Mixin.create(ModalFunctionality, { +export default Mixin.create(ModalFunctionality, { reason: null, message: null, postEdit: null, @@ -25,7 +27,7 @@ export default Ember.Mixin.create(ModalFunctionality, { penalize(cb) { let before = this.before; - let promise = before ? before() : Ember.RSVP.resolve(); + let promise = before ? before() : Promise.resolve(); return promise .then(() => cb()) diff --git a/app/assets/javascripts/admin/mixins/period-computation.js.es6 b/app/assets/javascripts/admin/mixins/period-computation.js.es6 index 4323532e84..354fd0ad85 100644 --- a/app/assets/javascripts/admin/mixins/period-computation.js.es6 +++ b/app/assets/javascripts/admin/mixins/period-computation.js.es6 @@ -1,7 +1,8 @@ import DiscourseURL from "discourse/lib/url"; import computed from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ queryParams: ["period"], period: "monthly", diff --git a/app/assets/javascripts/admin/mixins/setting-component.js.es6 b/app/assets/javascripts/admin/mixins/setting-component.js.es6 index 18be48a2d1..762d5cfa2b 100644 --- a/app/assets/javascripts/admin/mixins/setting-component.js.es6 +++ b/app/assets/javascripts/admin/mixins/setting-component.js.es6 @@ -1,5 +1,11 @@ +import { alias, oneWay } from "@ember/object/computed"; import computed from "ember-addons/ember-computed-decorators"; import { categoryLinkHTML } from "discourse/helpers/category-link"; +import { on } from "@ember/object/evented"; +import Mixin from "@ember/object/mixin"; +import showModal from "discourse/lib/show-modal"; +import AboutRoute from "discourse/routes/about"; +import { Promise } from "rsvp"; const CUSTOM_TYPES = [ "bool", @@ -14,16 +20,17 @@ const CUSTOM_TYPES = [ "compact_list", "secret_list", "upload", - "group_list" + "group_list", + "tag_list" ]; const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"]; -export default Ember.Mixin.create({ +export default Mixin.create({ classNameBindings: [":row", ":setting", "overridden", "typeClass"], - content: Ember.computed.alias("setting"), + content: alias("setting"), validationMessage: null, - isSecret: Ember.computed.oneWay("setting.secret"), + isSecret: oneWay("setting.secret"), @computed("buffered.value", "setting.value") dirty(bufferVal, settingVal) { @@ -89,33 +96,88 @@ export default Ember.Mixin.create({ return settingDefault !== bufferedValue; }, - _watchEnterKey: function() { + _watchEnterKey: on("didInsertElement", function() { $(this.element).on("keydown.setting-enter", ".input-setting-string", e => { if (e.keyCode === 13) { // enter key this.send("save"); } }); - }.on("didInsertElement"), + }), - _removeBindings: function() { + _removeBindings: on("willDestroyElement", function() { $(this.element).off("keydown.setting-enter"); - }.on("willDestroyElement"), + }), _save() { Ember.warn("You should define a `_save` method", { id: "discourse.setting-component.missing-save" }); - return Ember.RSVP.resolve(); + return Promise.resolve(); }, actions: { + update() { + const defaultUserPreferences = [ + "default_email_digest_frequency", + "default_include_tl0_in_digests", + "default_email_level", + "default_email_messages_level", + "default_email_mailing_list_mode", + "default_email_mailing_list_mode_frequency", + "disable_mailing_list_mode", + "default_email_previous_replies", + "default_email_in_reply_to", + "default_other_new_topic_duration_minutes", + "default_other_auto_track_topics_after_msecs", + "default_other_notification_level_when_replying", + "default_other_external_links_in_new_tab", + "default_other_enable_quoting", + "default_other_enable_defer", + "default_other_dynamic_favicon", + "default_other_like_notification_frequency", + "default_topics_automatic_unpin", + "default_categories_watching", + "default_categories_tracking", + "default_categories_muted", + "default_categories_watching_first_post", + "default_tags_watching", + "default_tags_tracking", + "default_tags_muted", + "default_tags_watching_first_post", + "default_text_size", + "default_title_count_mode" + ]; + const key = this.buffered.get("setting"); + + if (defaultUserPreferences.includes(key)) { + AboutRoute.create() + .model() + .then(result => { + const controller = showModal("site-setting-default-categories", { + model: { + count: result.stats.user_count, + key: key.replace(/_/g, " ") + }, + admin: true + }); + + controller.set("onClose", () => { + this.updateExistingUsers = controller.updateExistingUsers; + this.send("save"); + }); + }); + } else { + this.send("save"); + } + }, + save() { this._save() .then(() => { this.set("validationMessage", null); this.commitBuffer(); - if (AUTO_REFRESH_ON_SAVE.includes(this.get("setting.setting"))) { + if (AUTO_REFRESH_ON_SAVE.includes(this.setting.setting)) { this.afterSave(); } }) diff --git a/app/assets/javascripts/admin/mixins/setting-object.js.es6 b/app/assets/javascripts/admin/mixins/setting-object.js.es6 index ef047af732..c02004cea8 100644 --- a/app/assets/javascripts/admin/mixins/setting-object.js.es6 +++ b/app/assets/javascripts/admin/mixins/setting-object.js.es6 @@ -1,6 +1,7 @@ import computed from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ @computed("value", "default") overridden(val, defaultVal) { if (val === null) val = ""; diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6 index 8a8ba62481..880cb44c39 100644 --- a/app/assets/javascripts/admin/models/admin-user.js.es6 +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -1,26 +1,21 @@ +import { filter, or, gt, lt, not } from "@ember/object/computed"; import { iconHTML } from "discourse-common/lib/icon-library"; import { ajax } from "discourse/lib/ajax"; import computed from "ember-addons/ember-computed-decorators"; import { propertyNotEqual } from "discourse/lib/computed"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import ApiKey from "admin/models/api-key"; import Group from "discourse/models/group"; import { userPath } from "discourse/lib/url"; +import { Promise } from "rsvp"; const wrapAdmin = user => (user ? AdminUser.create(user) : null); const AdminUser = Discourse.User.extend({ adminUserView: true, - customGroups: Ember.computed.filter( - "groups", - g => !g.automatic && Group.create(g) - ), - automaticGroups: Ember.computed.filter( - "groups", - g => g.automatic && Group.create(g) - ), + customGroups: filter("groups", g => !g.automatic && Group.create(g)), + automaticGroups: filter("groups", g => g.automatic && Group.create(g)), - canViewProfile: Ember.computed.or("active", "staged"), + canViewProfile: or("active", "staged"), @computed("bounce_score", "reset_bounce_score_after") bounceScore(bounce_score, reset_bounce_score_after) { @@ -49,7 +44,7 @@ const AdminUser = Discourse.User.extend({ return Discourse.getURL("/admin/email/bounced"); }, - canResetBounceScore: Ember.computed.gt("bounce_score", 0), + canResetBounceScore: gt("bounce_score", 0), resetBounceScore() { return ajax(`/admin/users/${this.id}/reset_bounce_score`, { @@ -62,16 +57,6 @@ const AdminUser = Discourse.User.extend({ ); }, - generateApiKey() { - return ajax(`/admin/users/${this.id}/generate_api_key`, { - type: "POST" - }).then(result => { - const apiKey = ApiKey.create(result.api_key); - this.set("api_key", apiKey); - return apiKey; - }); - }, - groupAdded(added) { return ajax(`/admin/users/${this.id}/groups`, { type: "POST", @@ -289,9 +274,9 @@ const AdminUser = Discourse.User.extend({ }); }, - canLockTrustLevel: Ember.computed.lt("trust_level", 4), + canLockTrustLevel: lt("trust_level", 4), - canSuspend: Ember.computed.not("staff"), + canSuspend: not("staff"), @computed("suspended_till", "suspended_at") suspendDuration(suspendedTill, suspendedAt) { @@ -519,7 +504,7 @@ const AdminUser = Discourse.User.extend({ loadDetails() { if (this.loadedDetails) { - return Ember.RSVP.resolve(this); + return Promise.resolve(this); } return AdminUser.find(this.id).then(result => { @@ -557,9 +542,9 @@ AdminUser.reopenClass({ }); }, - findAll(query, filter) { + findAll(query, userFilter) { return ajax(`/admin/users/list/${query}.json`, { - data: filter + data: userFilter }).then(users => users.map(u => AdminUser.create(u))); } }); diff --git a/app/assets/javascripts/admin/models/api-key.js.es6 b/app/assets/javascripts/admin/models/api-key.js.es6 index 62a4e003bf..95d8e1914c 100644 --- a/app/assets/javascripts/admin/models/api-key.js.es6 +++ b/app/assets/javascripts/admin/models/api-key.js.es6 @@ -1,47 +1,55 @@ import AdminUser from "admin/models/admin-user"; +import RestModel from "discourse/models/rest"; import { ajax } from "discourse/lib/ajax"; +import computed from "ember-addons/ember-computed-decorators"; -const KEY_ENDPOINT = "/admin/api/key"; -const KEYS_ENDPOINT = "/admin/api/keys"; +const ApiKey = RestModel.extend({ + user: Ember.computed("_user", { + get() { + return this._user; + }, + set(key, value) { + if (value && !(value instanceof AdminUser)) { + this.set("_user", AdminUser.create(value)); + } else { + this.set("_user", value); + } + return this._user; + } + }), -const ApiKey = Discourse.Model.extend({ - regenerate() { - return ajax(KEY_ENDPOINT, { - type: "PUT", - data: { id: this.id } - }).then(result => { - this.set("key", result.api_key.key); - return this; - }); + @computed("key") + shortKey(key) { + return `${key.substring(0, 4)}...`; + }, + + @computed("description") + shortDescription(description) { + if (!description || description.length < 40) return description; + return `${description.substring(0, 40)}...`; }, revoke() { - return ajax(KEY_ENDPOINT, { - type: "DELETE", - data: { id: this.id } - }); - } -}); - -ApiKey.reopenClass({ - create() { - const result = this._super.apply(this, arguments); - if (result.user) { - result.user = AdminUser.create(result.user); - } - return result; + return ajax(`${this.basePath}/revoke`, { + type: "POST" + }).then(result => this.setProperties(result.api_key)); }, - find() { - return ajax(KEYS_ENDPOINT).then(keys => - keys.map(key => ApiKey.create(key)) - ); + undoRevoke() { + return ajax(`${this.basePath}/undo-revoke`, { + type: "POST" + }).then(result => this.setProperties(result.api_key)); }, - generateMasterKey() { - return ajax(KEY_ENDPOINT, { type: "POST" }).then(result => - ApiKey.create(result.api_key) - ); + createProperties() { + return this.getProperties("description", "username"); + }, + + @computed() + basePath() { + return this.store + .adapterFor("api-key") + .pathFor(this.store, "api-key", this.id); } }); diff --git a/app/assets/javascripts/admin/models/backup-status.js.es6 b/app/assets/javascripts/admin/models/backup-status.js.es6 index 2eb856c3be..b7deec1c10 100644 --- a/app/assets/javascripts/admin/models/backup-status.js.es6 +++ b/app/assets/javascripts/admin/models/backup-status.js.es6 @@ -1,7 +1,8 @@ +import { not } from "@ember/object/computed"; import computed from "ember-addons/ember-computed-decorators"; export default Discourse.Model.extend({ - restoreDisabled: Ember.computed.not("restoreEnabled"), + restoreDisabled: not("restoreEnabled"), @computed("allowRestore", "isOperationRunning") restoreEnabled(allowRestore, isOperationRunning) { diff --git a/app/assets/javascripts/admin/models/color-scheme.js.es6 b/app/assets/javascripts/admin/models/color-scheme.js.es6 index 26c8ccdc0e..8875bf2e5e 100644 --- a/app/assets/javascripts/admin/models/color-scheme.js.es6 +++ b/app/assets/javascripts/admin/models/color-scheme.js.es6 @@ -1,3 +1,4 @@ +import { not } from "@ember/object/computed"; import { ajax } from "discourse/lib/ajax"; import ColorSchemeColor from "admin/models/color-scheme-color"; import computed from "ember-addons/ember-computed-decorators"; @@ -59,7 +60,7 @@ const ColorScheme = Discourse.Model.extend(Ember.Copyable, { return !changed || this.saving || this.colors.any(c => !c.get("valid")); }, - newRecord: Ember.computed.not("id"), + newRecord: not("id"), save(opts) { if (this.is_base || this.disableSave) return; diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index c7967cc6d5..37c495e06f 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -1,3 +1,6 @@ +import { makeArray } from "discourse-common/lib/helpers"; +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; import { escapeExpression } from "discourse/lib/utilities"; import { ajax } from "discourse/lib/ajax"; import round from "discourse/lib/round"; @@ -135,7 +138,7 @@ const Report = Discourse.Model.extend({ @computed("data", "currentTotal") currentAverage(data, total) { - return Ember.makeArray(data).length === 0 + return makeArray(data).length === 0 ? 0 : parseFloat((total / parseFloat(data.length)).toFixed(1)); }, @@ -323,7 +326,7 @@ const Report = Discourse.Model.extend({ const formatedValue = () => { const userId = row[properties.id]; - const user = Ember.Object.create({ + const user = EmberObject.create({ username, name: formatUsername(username), avatar_template: row[properties.avatar] @@ -391,7 +394,7 @@ const Report = Discourse.Model.extend({ }, _numberLabel(value, options = {}) { - const formatNumbers = Ember.isEmpty(options.formatNumbers) + const formatNumbers = isEmpty(options.formatNumbers) ? true : options.formatNumbers; diff --git a/app/assets/javascripts/admin/models/screened-ip-address.js.es6 b/app/assets/javascripts/admin/models/screened-ip-address.js.es6 index c7f3863738..0449a666f3 100644 --- a/app/assets/javascripts/admin/models/screened-ip-address.js.es6 +++ b/app/assets/javascripts/admin/models/screened-ip-address.js.es6 @@ -1,3 +1,4 @@ +import { equal } from "@ember/object/computed"; import { ajax } from "discourse/lib/ajax"; import computed from "ember-addons/ember-computed-decorators"; @@ -7,7 +8,7 @@ const ScreenedIpAddress = Discourse.Model.extend({ return I18n.t(`admin.logs.screened_ips.actions.${actionName}`); }, - isBlocked: Ember.computed.equal("action_name", "block"), + isBlocked: equal("action_name", "block"), @computed("ip_address") isRange(ipAddress) { diff --git a/app/assets/javascripts/admin/models/site-setting.js.es6 b/app/assets/javascripts/admin/models/site-setting.js.es6 index ca1c175864..7760a61114 100644 --- a/app/assets/javascripts/admin/models/site-setting.js.es6 +++ b/app/assets/javascripts/admin/models/site-setting.js.es6 @@ -25,9 +25,14 @@ SiteSetting.reopenClass({ }); }, - update(key, value) { + update(key, value, opts = {}) { const data = {}; data[key] = value; + + if (opts["updateExistingUsers"] === true) { + data["updateExistingUsers"] = true; + } + return ajax(`/admin/site_settings/${key}`, { type: "PUT", data }); } }); diff --git a/app/assets/javascripts/admin/models/theme.js.es6 b/app/assets/javascripts/admin/models/theme.js.es6 index 7e49ff9b9e..4ea3d3e216 100644 --- a/app/assets/javascripts/admin/models/theme.js.es6 +++ b/app/assets/javascripts/admin/models/theme.js.es6 @@ -1,3 +1,6 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { or, gt } from "@ember/object/computed"; import RestModel from "discourse/models/rest"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -13,9 +16,9 @@ export const COMPONENTS = "components"; const SETTINGS_TYPE_ID = 5; const Theme = RestModel.extend({ - isActive: Ember.computed.or("default", "user_selectable"), - isPendingUpdates: Ember.computed.gt("remote_theme.commits_behind", 0), - hasEditedFields: Ember.computed.gt("editedFields.length", 0), + isActive: or("default", "user_selectable"), + isPendingUpdates: gt("remote_theme.commits_behind", 0), + hasEditedFields: gt("editedFields.length", 0), @computed("theme_fields.[]") targets() { @@ -160,11 +163,11 @@ const Theme = RestModel.extend({ hasEdited(target, name) { if (name) { - return !Ember.isEmpty(this.getField(target, name)); + return !isEmpty(this.getField(target, name)); } else { let fields = this.theme_fields || []; return fields.any( - field => field.target === target && !Ember.isEmpty(field.value) + field => field.target === target && !isEmpty(field.value) ); } }, @@ -226,8 +229,8 @@ const Theme = RestModel.extend({ themeFields[key] = field; } else { const changed = - (Ember.isEmpty(existingField.value) && !Ember.isEmpty(value)) || - (Ember.isEmpty(value) && !Ember.isEmpty(existingField.value)); + (isEmpty(existingField.value) && !isEmpty(value)) || + (isEmpty(value) && !isEmpty(existingField.value)); existingField.value = value; if (changed) { @@ -241,7 +244,7 @@ const Theme = RestModel.extend({ @computed("childThemes.[]") child_theme_ids(childThemes) { if (childThemes) { - return childThemes.map(theme => Ember.get(theme, "id")); + return childThemes.map(theme => get(theme, "id")); } }, diff --git a/app/assets/javascripts/admin/models/user-field.js.es6 b/app/assets/javascripts/admin/models/user-field.js.es6 index a57e452d86..78c004d418 100644 --- a/app/assets/javascripts/admin/models/user-field.js.es6 +++ b/app/assets/javascripts/admin/models/user-field.js.es6 @@ -1,9 +1,10 @@ +import EmberObject from "@ember/object"; import RestModel from "discourse/models/rest"; import { i18n } from "discourse/lib/computed"; const UserField = RestModel.extend(); -const UserFieldType = Ember.Object.extend({ +const UserFieldType = EmberObject.extend({ name: i18n("id", "admin.user_fields.field_types.%@") }); diff --git a/app/assets/javascripts/admin/models/version-check.js.es6 b/app/assets/javascripts/admin/models/version-check.js.es6 index ce41d66713..2012d0ff08 100644 --- a/app/assets/javascripts/admin/models/version-check.js.es6 +++ b/app/assets/javascripts/admin/models/version-check.js.es6 @@ -17,12 +17,10 @@ const VersionCheck = Discourse.Model.extend({ return missingVersionsCount === 1; }, - @computed("git_branch", "installed_sha") - gitLink(gitBranch, installedSHA) { - if (gitBranch && installedSHA) { - return `https://github.com/discourse/discourse/compare/${installedSHA}...${gitBranch}`; - } else if (installedSHA) { - return `https://github.com/discourse/discourse/tree/${installedSHA}`; + @computed("installed_sha") + gitLink(installedSHA) { + if (installedSHA) { + return `https://github.com/discourse/discourse/commits/${installedSHA}`; } }, diff --git a/app/assets/javascripts/admin/models/watched-word.js.es6 b/app/assets/javascripts/admin/models/watched-word.js.es6 index 9f335032e3..b9ef7380b6 100644 --- a/app/assets/javascripts/admin/models/watched-word.js.es6 +++ b/app/assets/javascripts/admin/models/watched-word.js.es6 @@ -1,4 +1,5 @@ import { ajax } from "discourse/lib/ajax"; +import EmberObject from "@ember/object"; const WatchedWord = Discourse.Model.extend({ save() { @@ -37,7 +38,7 @@ WatchedWord.reopenClass({ }); return Object.keys(actions).map(n => { - return Ember.Object.create({ + return EmberObject.create({ nameKey: n, name: I18n.t("admin.watched_words.actions." + n), words: actions[n], diff --git a/app/assets/javascripts/admin/models/web-hook.js.es6 b/app/assets/javascripts/admin/models/web-hook.js.es6 index cc35f47437..84111591fa 100644 --- a/app/assets/javascripts/admin/models/web-hook.js.es6 +++ b/app/assets/javascripts/admin/models/web-hook.js.es6 @@ -1,3 +1,4 @@ +import { isEmpty } from "@ember/utils"; import RestModel from "discourse/models/rest"; import Category from "discourse/models/category"; import Group from "discourse/models/group"; @@ -78,13 +79,13 @@ export default RestModel.extend({ wildcard_web_hook: this.wildcard_web_hook, verify_certificate: this.verify_certificate, active: this.active, - web_hook_event_type_ids: Ember.isEmpty(types) + web_hook_event_type_ids: isEmpty(types) ? [null] : types.map(type => type.id), - category_ids: Ember.isEmpty(categoryIds) ? [null] : categoryIds, - tag_names: Ember.isEmpty(tagNames) ? [null] : tagNames, + category_ids: isEmpty(categoryIds) ? [null] : categoryIds, + tag_names: isEmpty(tagNames) ? [null] : tagNames, group_ids: - Ember.isEmpty(groupNames) || Ember.isEmpty(groupNames[0]) + isEmpty(groupNames) || isEmpty(groupNames[0]) ? [null] : Discourse.Site.currentProp("groups").reduce((groupIds, g) => { if (groupNames.includes(g.name)) { diff --git a/app/assets/javascripts/admin/routes/admin-api-index.js.es6 b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 index c66efab129..f770f90c91 100644 --- a/app/assets/javascripts/admin/routes/admin-api-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-api-index.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; + +export default Route.extend({ beforeModel() { this.transitionTo("adminApiKeys"); } diff --git a/app/assets/javascripts/admin/routes/admin-api-keys-index.js.es6 b/app/assets/javascripts/admin/routes/admin-api-keys-index.js.es6 new file mode 100644 index 0000000000..25f6df3e4a --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-api-keys-index.js.es6 @@ -0,0 +1,7 @@ +import Route from "@ember/routing/route"; + +export default Route.extend({ + model() { + return this.store.findAll("api-key"); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-api-keys-new.es6 b/app/assets/javascripts/admin/routes/admin-api-keys-new.es6 new file mode 100644 index 0000000000..3969615c9f --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-api-keys-new.es6 @@ -0,0 +1,7 @@ +import Route from "@ember/routing/route"; + +export default Route.extend({ + model() { + return this.store.createRecord("api-key"); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-api-keys-show.js.es6 b/app/assets/javascripts/admin/routes/admin-api-keys-show.js.es6 new file mode 100644 index 0000000000..b21f2cd021 --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin-api-keys-show.js.es6 @@ -0,0 +1,5 @@ +export default Ember.Route.extend({ + model(params) { + return this.store.find("api-key", params.api_key_id); + } +}); diff --git a/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 b/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 index 4332cb0adc..1b3f3067fc 100644 --- a/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-api-keys.js.es6 @@ -1,7 +1,13 @@ -import ApiKey from "admin/models/api-key"; +import Route from "@ember/routing/route"; -export default Ember.Route.extend({ - model() { - return ApiKey.find(); +export default Route.extend({ + actions: { + show(apiKey) { + this.transitionTo("adminApiKeys.show", apiKey.id); + }, + + new() { + this.transitionTo("adminApiKeys.new"); + } } }); diff --git a/app/assets/javascripts/admin/routes/admin-backups-index.js.es6 b/app/assets/javascripts/admin/routes/admin-backups-index.js.es6 index 39ed982a78..d20da4ac50 100644 --- a/app/assets/javascripts/admin/routes/admin-backups-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups-index.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import Backup from "admin/models/backup"; -export default Ember.Route.extend({ +export default Route.extend({ activate() { this.messageBus.subscribe("/admin/backups", backups => this.controller.set("model", backups.map(backup => Backup.create(backup))) diff --git a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 index a0febc3d1d..3d24756a4a 100644 --- a/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups-logs.js.es6 @@ -1,6 +1,8 @@ +import EmberObject from "@ember/object"; +import Route from "@ember/routing/route"; import PreloadStore from "preload-store"; -export default Ember.Route.extend({ +export default Route.extend({ // since the logs are pushed via the message bus // we only want to preload them (hence the beforeModel hook) beforeModel() { @@ -15,7 +17,7 @@ export default Ember.Route.extend({ return log.message.length === 0 || log.message[0] === "["; }) .map(function(log) { - return Ember.Object.create(log); + return EmberObject.create(log); }) .value(); logs.pushObjects(newLogs); diff --git a/app/assets/javascripts/admin/routes/admin-backups.js.es6 b/app/assets/javascripts/admin/routes/admin-backups.js.es6 index b70c978286..5025f41536 100644 --- a/app/assets/javascripts/admin/routes/admin-backups.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups.js.es6 @@ -1,3 +1,5 @@ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import showModal from "discourse/lib/show-modal"; import BackupStatus from "admin/models/backup-status"; @@ -6,7 +8,7 @@ import PreloadStore from "preload-store"; const LOG_CHANNEL = "/admin/backups/logs"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ activate() { this.messageBus.subscribe(LOG_CHANNEL, log => { if (log.message === "[STARTED]") { @@ -41,7 +43,7 @@ export default Discourse.Route.extend({ } else { this.controllerFor("adminBackupsLogs") .get("logs") - .pushObject(Ember.Object.create(log)); + .pushObject(EmberObject.create(log)); } }); }, diff --git a/app/assets/javascripts/admin/routes/admin-badges-index.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-index.js.es6 index 84a5bee571..36a4414877 100644 --- a/app/assets/javascripts/admin/routes/admin-badges-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges-index.js.es6 @@ -1,3 +1,4 @@ +import Route from "@ember/routing/route"; import { emojiUrlFor } from "discourse/lib/text"; const badgeIntroLinks = [ @@ -13,7 +14,7 @@ const badgeIntroLinks = [ } ]; -export default Ember.Route.extend({ +export default Route.extend({ setupController(controller) { controller.setProperties({ badgeIntroLinks, 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 7837d1b30d..36043f6096 100644 --- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 @@ -1,10 +1,12 @@ +import { get } from "@ember/object"; +import Route from "@ember/routing/route"; import { ajax } from "discourse/lib/ajax"; import Badge from "discourse/models/badge"; import showModal from "discourse/lib/show-modal"; -export default Ember.Route.extend({ +export default Route.extend({ serialize(m) { - return { badge_id: Ember.get(m, "id") || "new" }; + return { badge_id: get(m, "id") || "new" }; }, model(params) { diff --git a/app/assets/javascripts/admin/routes/admin-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-badges.js.es6 index 9fee47fb4e..0dac4bbaa2 100644 --- a/app/assets/javascripts/admin/routes/admin-badges.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges.js.es6 @@ -1,8 +1,9 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import Badge from "discourse/models/badge"; import BadgeGrouping from "discourse/models/badge-grouping"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ _json: null, model() { diff --git a/app/assets/javascripts/admin/routes/admin-customize-colors-show.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-colors-show.js.es6 index 545a09ad9b..146a3a61a9 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-colors-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-colors-show.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model(params) { const all = this.modelFor("adminCustomize.colors"); const model = all.findBy("id", parseInt(params.scheme_id)); diff --git a/app/assets/javascripts/admin/routes/admin-customize-colors.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-colors.js.es6 index f4853fda28..835814df07 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-colors.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-colors.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import ColorScheme from "admin/models/color-scheme"; -export default Ember.Route.extend({ +export default Route.extend({ model() { return ColorScheme.findAll(); }, diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 index 74649c1a00..8dcc18f0d9 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-email-style-edit.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model(params) { return { model: this.modelFor("adminCustomizeEmailStyle"), diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 index 8e202e62bd..d63186e0eb 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-email-style.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model() { return this.store.find("email-style"); }, diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 index a6f170b09e..0bf85baf4a 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-email-templates-edit.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import { scrollTop } from "discourse/mixins/scroll-top"; -export default Ember.Route.extend({ +export default Route.extend({ model(params) { const all = this.modelFor("adminCustomizeEmailTemplates"); return all.findBy("id", params.id); diff --git a/app/assets/javascripts/admin/routes/admin-customize-email-templates.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-email-templates.js.es6 index fa6d3041a6..39b04b835f 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-email-templates.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-email-templates.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model() { return this.store.findAll("email-template"); }, diff --git a/app/assets/javascripts/admin/routes/admin-customize-index.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-index.js.es6 index 10d55df015..9c593b7e25 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-index.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ beforeModel() { this.transitionTo("adminCustomizeThemes"); } diff --git a/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 index 50acd6cac1..866d7cf8ec 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-robots-txt.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Route.extend({ +export default Route.extend({ model() { return ajax("/admin/customize/robots"); } diff --git a/app/assets/javascripts/admin/routes/admin-customize-themes-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-themes-edit.js.es6 index 2e37bdc1ce..335e9fd578 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-themes-edit.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-themes-edit.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model(params) { const all = this.modelFor("adminCustomizeThemes"); const model = all.findBy("id", parseInt(params.theme_id)); diff --git a/app/assets/javascripts/admin/routes/admin-customize-themes-index.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-themes-index.js.es6 index ea09122d62..425a04617a 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-themes-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-themes-index.js.es6 @@ -1,3 +1,4 @@ +import Route from "@ember/routing/route"; import { emojiUrlFor } from "discourse/lib/text"; const externalResources = [ @@ -18,7 +19,7 @@ const externalResources = [ } ]; -export default Ember.Route.extend({ +export default Route.extend({ setupController(controller) { this._super(...arguments); this.controllerFor("adminCustomizeThemes").set("editingTheme", false); diff --git a/app/assets/javascripts/admin/routes/admin-customize-themes-show.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-themes-show.js.es6 index a0ca4feef8..c9573fd8ac 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-themes-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-themes-show.js.es6 @@ -1,7 +1,8 @@ +import Route from "@ember/routing/route"; import { scrollTop } from "discourse/mixins/scroll-top"; import { THEMES, COMPONENTS } from "admin/models/theme"; -export default Ember.Route.extend({ +export default Route.extend({ serialize(model) { return { theme_id: model.get("id") }; }, diff --git a/app/assets/javascripts/admin/routes/admin-customize-themes.js.es6 b/app/assets/javascripts/admin/routes/admin-customize-themes.js.es6 index 91c7ec5b76..7f7274ee0e 100644 --- a/app/assets/javascripts/admin/routes/admin-customize-themes.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-customize-themes.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import showModal from "discourse/lib/show-modal"; -export default Ember.Route.extend({ +export default Route.extend({ model() { return this.store.findAll("theme"); }, diff --git a/app/assets/javascripts/admin/routes/admin-dashboard-general.js.es6 b/app/assets/javascripts/admin/routes/admin-dashboard-general.js.es6 index ffd544b3db..1ee1b22121 100644 --- a/app/assets/javascripts/admin/routes/admin-dashboard-general.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-dashboard-general.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ activate() { this.controllerFor("admin-dashboard-general").fetchDashboard(); } diff --git a/app/assets/javascripts/admin/routes/admin-dashboard-reports.js.es6 b/app/assets/javascripts/admin/routes/admin-dashboard-reports.js.es6 index 7aea901096..0de5bfe505 100644 --- a/app/assets/javascripts/admin/routes/admin-dashboard-reports.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-dashboard-reports.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return ajax("/admin/reports").then(json => json); }, diff --git a/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 b/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 index a6ff3c215e..905a148bc7 100644 --- a/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-dashboard.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { scrollTop } from "discourse/mixins/scroll-top"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ activate() { this.controllerFor("admin-dashboard").fetchProblems(); this.controllerFor("admin-dashboard").fetchDashboard(); diff --git a/app/assets/javascripts/admin/routes/admin-email-incomings.js.es6 b/app/assets/javascripts/admin/routes/admin-email-incomings.js.es6 index 79331282bb..aa86f7f31d 100644 --- a/app/assets/javascripts/admin/routes/admin-email-incomings.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-incomings.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import IncomingEmail from "admin/models/incoming-email"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return IncomingEmail.findAll({ status: this.status }); }, diff --git a/app/assets/javascripts/admin/routes/admin-email-index.js.es6 b/app/assets/javascripts/admin/routes/admin-email-index.js.es6 index ca912cc009..878885f983 100644 --- a/app/assets/javascripts/admin/routes/admin-email-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-index.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import EmailSettings from "admin/models/email-settings"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return EmailSettings.find(); } diff --git a/app/assets/javascripts/admin/routes/admin-email-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-email-logs.js.es6 index 7813fb93fd..8ebfebd199 100644 --- a/app/assets/javascripts/admin/routes/admin-email-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-logs.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ setupController(controller) { controller.setProperties({ loading: true, diff --git a/app/assets/javascripts/admin/routes/admin-email-preview-digest.js.es6 b/app/assets/javascripts/admin/routes/admin-email-preview-digest.js.es6 index 972f3c9b6d..391ec6c75b 100644 --- a/app/assets/javascripts/admin/routes/admin-email-preview-digest.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-email-preview-digest.js.es6 @@ -1,9 +1,10 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { default as EmailPreview, oneWeekAgo } from "admin/models/email-preview"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return EmailPreview.findDigest(this.currentUser.get("username")); }, diff --git a/app/assets/javascripts/admin/routes/admin-embedding.js.es6 b/app/assets/javascripts/admin/routes/admin-embedding.js.es6 index d698c52450..080dce2083 100644 --- a/app/assets/javascripts/admin/routes/admin-embedding.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-embedding.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model() { return this.store.find("embedding"); }, diff --git a/app/assets/javascripts/admin/routes/admin-emojis.js.es6 b/app/assets/javascripts/admin/routes/admin-emojis.js.es6 index f412a90898..dd7e94d40a 100644 --- a/app/assets/javascripts/admin/routes/admin-emojis.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-emojis.js.es6 @@ -1,9 +1,12 @@ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ + +export default DiscourseRoute.extend({ model: function() { return ajax("/admin/customize/emojis.json").then(function(emojis) { return emojis.map(function(emoji) { - return Ember.Object.create(emoji); + return EmberObject.create(emoji); }); }); } diff --git a/app/assets/javascripts/admin/routes/admin-flags-posts-active.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-posts-active.js.es6 index d971939503..1a1d01a091 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-posts-active.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-posts-active.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.store.findAll("flagged-post", { filter: "active" }); } diff --git a/app/assets/javascripts/admin/routes/admin-flags-posts-old.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-posts-old.js.es6 index c7d22ccdad..a4157d5714 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-posts-old.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-posts-old.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.store.findAll("flagged-post", { filter: "old" }); } diff --git a/app/assets/javascripts/admin/routes/admin-flags-topics-index.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-topics-index.js.es6 index d635328c05..5fb295d648 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-topics-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-topics-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.store.findAll("flagged-topic"); }, diff --git a/app/assets/javascripts/admin/routes/admin-logs-index.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-index.js.es6 index ff4c94aada..d003b429b6 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ redirect: function() { this.transitionTo("adminLogs.staffActionLogs"); } diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 index f4f3a4f673..2016a96188 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-emails.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ renderTemplate: function() { this.render("admin/templates/logs/screened-emails", { into: "adminLogs" }); }, diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 index 24000436b7..4343785594 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-ip-addresses.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ renderTemplate() { this.render("admin/templates/logs/screened-ip-addresses", { into: "adminLogs" diff --git a/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 index 2369a886cd..ba0b76c9c5 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-screened-urls.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ renderTemplate: function() { this.render("admin/templates/logs/screened-urls", { into: "adminLogs" }); }, 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 fd1fea9615..0ef8e6e232 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 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import showModal from "discourse/lib/show-modal"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ // TODO: make this automatic using an `{{outlet}}` renderTemplate: function() { this.render("admin/templates/logs/staff-action-logs", { diff --git a/app/assets/javascripts/admin/routes/admin-permalinks.js.es6 b/app/assets/javascripts/admin/routes/admin-permalinks.js.es6 index d8c3c43865..996b90aaa8 100644 --- a/app/assets/javascripts/admin/routes/admin-permalinks.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-permalinks.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Permalink from "admin/models/permalink"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return Permalink.findAll(); }, diff --git a/app/assets/javascripts/admin/routes/admin-plugins.js.es6 b/app/assets/javascripts/admin/routes/admin-plugins.js.es6 index 06ea7eb259..c4af286faf 100644 --- a/app/assets/javascripts/admin/routes/admin-plugins.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-plugins.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model() { return this.store.findAll("plugin"); }, diff --git a/app/assets/javascripts/admin/routes/admin-reports-index.js.es6 b/app/assets/javascripts/admin/routes/admin-reports-index.js.es6 index 2d21467ae6..864f1a3fb2 100644 --- a/app/assets/javascripts/admin/routes/admin-reports-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-reports-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel() { this.transitionTo("admin.dashboardReports"); } diff --git a/app/assets/javascripts/admin/routes/admin-reports-show.js.es6 b/app/assets/javascripts/admin/routes/admin-reports-show.js.es6 index 9bf9ff8eba..1fa8bc739d 100644 --- a/app/assets/javascripts/admin/routes/admin-reports-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-reports-show.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ queryParams: { start_date: { refreshModel: true }, end_date: { refreshModel: true }, diff --git a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 index 478a851d86..f90b66f97a 100644 --- a/app/assets/javascripts/admin/routes/admin-route-map.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-route-map.js.es6 @@ -101,7 +101,14 @@ export default function() { ); this.route("adminApi", { path: "/api", resetNamespace: true }, function() { - this.route("adminApiKeys", { path: "/keys", resetNamespace: true }); + this.route( + "adminApiKeys", + { path: "/keys", resetNamespace: true }, + function() { + this.route("show", { path: "/:api_key_id" }); + this.route("new", { path: "/new" }); + } + ); this.route( "adminWebHooks", diff --git a/app/assets/javascripts/admin/routes/admin-search-logs-index.js.es6 b/app/assets/javascripts/admin/routes/admin-search-logs-index.js.es6 index 966032045e..8244c0f2af 100644 --- a/app/assets/javascripts/admin/routes/admin-search-logs-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-search-logs-index.js.es6 @@ -1,6 +1,8 @@ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { period: { refreshModel: true }, searchType: { refreshModel: true } @@ -11,7 +13,7 @@ export default Discourse.Route.extend({ return ajax("/admin/logs/search_logs.json", { data: { period: params.period, search_type: params.searchType } }).then(search_logs => { - return search_logs.map(sl => Ember.Object.create(sl)); + return search_logs.map(sl => EmberObject.create(sl)); }); }, diff --git a/app/assets/javascripts/admin/routes/admin-search-logs-term.js.es6 b/app/assets/javascripts/admin/routes/admin-search-logs-term.js.es6 index 40d3e25be6..7c9c8f274c 100644 --- a/app/assets/javascripts/admin/routes/admin-search-logs-term.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-search-logs-term.js.es6 @@ -1,8 +1,10 @@ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import { fillMissingDates } from "discourse/lib/utilities"; import { translateResults } from "discourse/lib/search"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { term: { refreshModel: true }, period: { refreshModel: true }, @@ -32,7 +34,7 @@ export default Discourse.Route.extend({ json.term.search_result = translateResults(json.term.search_result); } - const model = Ember.Object.create({ type: "search_log_term" }); + const model = EmberObject.create({ type: "search_log_term" }); model.setProperties(json.term); return model; }); diff --git a/app/assets/javascripts/admin/routes/admin-site-settings-category.js.es6 b/app/assets/javascripts/admin/routes/admin-site-settings-category.js.es6 index a774415083..b5a2f810b2 100644 --- a/app/assets/javascripts/admin/routes/admin-site-settings-category.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-site-settings-category.js.es6 @@ -1,4 +1,7 @@ -export default Discourse.Route.extend({ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model(params) { // The model depends on user input, so let the controller do the work: this.controllerFor("adminSiteSettingsCategory").set( @@ -9,7 +12,7 @@ export default Discourse.Route.extend({ "categoryNameKey", params.category_id ); - return Ember.Object.create({ + return EmberObject.create({ nameKey: params.category_id, name: I18n.t("admin.site_settings.categories." + params.category_id), siteSettings: this.controllerFor("adminSiteSettingsCategory").get( diff --git a/app/assets/javascripts/admin/routes/admin-site-settings-index.js.es6 b/app/assets/javascripts/admin/routes/admin-site-settings-index.js.es6 index 59e851e509..88a091c4b9 100644 --- a/app/assets/javascripts/admin/routes/admin-site-settings-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-site-settings-index.js.es6 @@ -2,7 +2,9 @@ Handles when you click the Site Settings tab in admin, but haven't chosen a category. It will redirect to the first category. **/ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel() { this.replaceWith( "adminSiteSettingsCategory", diff --git a/app/assets/javascripts/admin/routes/admin-site-settings.js.es6 b/app/assets/javascripts/admin/routes/admin-site-settings.js.es6 index b6c3e857ea..ab687a4585 100644 --- a/app/assets/javascripts/admin/routes/admin-site-settings.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-site-settings.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import SiteSetting from "admin/models/site-setting"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { filter: { replace: true } }, diff --git a/app/assets/javascripts/admin/routes/admin-site-text-edit.js.es6 b/app/assets/javascripts/admin/routes/admin-site-text-edit.js.es6 index 00ccca0256..c423eae45a 100644 --- a/app/assets/javascripts/admin/routes/admin-site-text-edit.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-site-text-edit.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model(params) { return this.store.find("site-text", params.id); }, diff --git a/app/assets/javascripts/admin/routes/admin-site-text-index.js.es6 b/app/assets/javascripts/admin/routes/admin-site-text-index.js.es6 index dfec2f64d3..815dd1c084 100644 --- a/app/assets/javascripts/admin/routes/admin-site-text-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-site-text-index.js.es6 @@ -1,6 +1,8 @@ +import Route from "@ember/routing/route"; import showModal from "discourse/lib/show-modal"; +import { getProperties } from "@ember/object"; -export default Ember.Route.extend({ +export default Route.extend({ queryParams: { q: { replace: true }, overridden: { replace: true } @@ -9,7 +11,7 @@ export default Ember.Route.extend({ model(params) { return this.store.find( "site-text", - Ember.getProperties(params, "q", "overridden") + getProperties(params, "q", "overridden") ); }, diff --git a/app/assets/javascripts/admin/routes/admin-user-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-user-badges.js.es6 index b585117f19..cce32753d1 100644 --- a/app/assets/javascripts/admin/routes/admin-user-badges.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-badges.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import UserBadge from "discourse/models/user-badge"; import Badge from "discourse/models/badge"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { const username = this.modelFor("adminUser").get("username"); return UserBadge.findByUsername(username); diff --git a/app/assets/javascripts/admin/routes/admin-user-fields.js.es6 b/app/assets/javascripts/admin/routes/admin-user-fields.js.es6 index c4278dc627..ea4e0adef0 100644 --- a/app/assets/javascripts/admin/routes/admin-user-fields.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-fields.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import UserField from "admin/models/user-field"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model: function() { return this.store.findAll("user-field"); }, 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 2b623dbcf8..51af9f2d2e 100644 --- a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Group from "discourse/models/group"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return this.modelFor("adminUser"); }, diff --git a/app/assets/javascripts/admin/routes/admin-user-tl3-requirements.js.es6 b/app/assets/javascripts/admin/routes/admin-user-tl3-requirements.js.es6 index 6364e89f7c..17cd54dc8a 100644 --- a/app/assets/javascripts/admin/routes/admin-user-tl3-requirements.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-tl3-requirements.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.modelFor("adminUser"); } diff --git a/app/assets/javascripts/admin/routes/admin-user.js.es6 b/app/assets/javascripts/admin/routes/admin-user.js.es6 index c25f750c25..563c63d0a5 100644 --- a/app/assets/javascripts/admin/routes/admin-user.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user.js.es6 @@ -1,6 +1,8 @@ +import { get } from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import AdminUser from "admin/models/admin-user"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ serialize(model) { return { user_id: model.get("id"), @@ -9,7 +11,7 @@ export default Discourse.Route.extend({ }, model(params) { - return AdminUser.find(Ember.get(params, "user_id")); + return AdminUser.find(get(params, "user_id")); }, renderTemplate() { diff --git a/app/assets/javascripts/admin/routes/admin-users-index.js.es6 b/app/assets/javascripts/admin/routes/admin-users-index.js.es6 index 8b28ea79fc..7549cb230c 100644 --- a/app/assets/javascripts/admin/routes/admin-users-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-users-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ redirect: function() { this.transitionTo("adminUsersList"); } diff --git a/app/assets/javascripts/admin/routes/admin-users-list-index.js.es6 b/app/assets/javascripts/admin/routes/admin-users-list-index.js.es6 index 696345ad42..9f15d72cff 100644 --- a/app/assets/javascripts/admin/routes/admin-users-list-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-users-list-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel: function() { this.transitionTo("adminUsersList.show", "active"); } diff --git a/app/assets/javascripts/admin/routes/admin-users-list-show.js.es6 b/app/assets/javascripts/admin/routes/admin-users-list-show.js.es6 index e0c1105566..764fe4ad34 100644 --- a/app/assets/javascripts/admin/routes/admin-users-list-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-users-list-show.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ queryParams: { order: { refreshModel: true }, ascending: { refreshModel: true } diff --git a/app/assets/javascripts/admin/routes/admin-users-list.js.es6 b/app/assets/javascripts/admin/routes/admin-users-list.js.es6 index d6b76356f1..9e520d1735 100644 --- a/app/assets/javascripts/admin/routes/admin-users-list.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-users-list.js.es6 @@ -1,8 +1,9 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { exportEntity } from "discourse/lib/export-csv"; import { outputExportResult } from "discourse/lib/export-result"; import AdminUser from "admin/models/admin-user"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ actions: { exportUsers() { exportEntity("user_list", { diff --git a/app/assets/javascripts/admin/routes/admin-watched-words-action.js.es6 b/app/assets/javascripts/admin/routes/admin-watched-words-action.js.es6 index 99450e09ce..358cfebe67 100644 --- a/app/assets/javascripts/admin/routes/admin-watched-words-action.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-watched-words-action.js.es6 @@ -1,4 +1,7 @@ -export default Discourse.Route.extend({ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model(params) { this.controllerFor("adminWatchedWordsAction").set( "actionNameKey", @@ -7,7 +10,7 @@ export default Discourse.Route.extend({ let filteredContent = this.controllerFor("adminWatchedWordsAction").get( "filteredContent" ); - return Ember.Object.create({ + return EmberObject.create({ nameKey: params.action_id, name: I18n.t("admin.watched_words.actions." + params.action_id), words: filteredContent diff --git a/app/assets/javascripts/admin/routes/admin-watched-words-index.js.es6 b/app/assets/javascripts/admin/routes/admin-watched-words-index.js.es6 index 4ff2351e1b..a957c11478 100644 --- a/app/assets/javascripts/admin/routes/admin-watched-words-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-watched-words-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel() { this.replaceWith( "adminWatchedWords.action", diff --git a/app/assets/javascripts/admin/routes/admin-watched-words.js.es6 b/app/assets/javascripts/admin/routes/admin-watched-words.js.es6 index 8970e6a614..924ab49779 100644 --- a/app/assets/javascripts/admin/routes/admin-watched-words.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-watched-words.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import WatchedWord from "admin/models/watched-word"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { filter: { replace: true } }, diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 index 1e0d3220cf..64f28d3652 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show-events.js.es6 @@ -1,9 +1,9 @@ -export default Discourse.Route.extend({ +import { get } from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model(params) { - return this.store.findAll( - "web-hook-event", - Ember.get(params, "web_hook_id") - ); + return this.store.findAll("web-hook-event", get(params, "web_hook_id")); }, setupController(controller, model) { diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 index 611b015dcb..34aed775cc 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js.es6 @@ -1,4 +1,8 @@ -export default Discourse.Route.extend({ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ serialize(model) { return { web_hook_id: model.get("id") || "new" }; }, @@ -7,14 +11,11 @@ export default Discourse.Route.extend({ if (params.web_hook_id === "new") { return this.store.createRecord("web-hook"); } - return this.store.find("web-hook", Ember.get(params, "web_hook_id")); + return this.store.find("web-hook", get(params, "web_hook_id")); }, setupController(controller, model) { - if ( - model.get("isNew") || - Ember.isEmpty(model.get("web_hook_event_types")) - ) { + if (model.get("isNew") || isEmpty(model.get("web_hook_event_types"))) { model.set("web_hook_event_types", controller.get("defaultEventTypes")); } diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 b/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 index eed884a8ab..30daf6b6cb 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-web-hooks.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ model() { return this.store.findAll("web-hook"); }, diff --git a/app/assets/javascripts/admin/routes/admin.js.es6 b/app/assets/javascripts/admin/routes/admin.js.es6 index fa373dd937..bc4e8173ef 100644 --- a/app/assets/javascripts/admin/routes/admin.js.es6 +++ b/app/assets/javascripts/admin/routes/admin.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("admin_title"); }, diff --git a/app/assets/javascripts/admin/services/admin-tools.js.es6 b/app/assets/javascripts/admin/services/admin-tools.js.es6 index 7f3b4d88a8..bb5e1ac06a 100644 --- a/app/assets/javascripts/admin/services/admin-tools.js.es6 +++ b/app/assets/javascripts/admin/services/admin-tools.js.es6 @@ -2,13 +2,16 @@ // and the admin application. Use this if you need front end code to access admin // modules. Inject it optionally, and if it exists go to town! +import EmberObject from "@ember/object"; import AdminUser from "admin/models/admin-user"; import { iconHTML } from "discourse-common/lib/icon-library"; import { ajax } from "discourse/lib/ajax"; import showModal from "discourse/lib/show-modal"; import { getOwner } from "discourse-common/lib/get-owner"; +import Service from "@ember/service"; +import { Promise } from "rsvp"; -export default Ember.Service.extend({ +export default Service.extend({ init() { this._super(...arguments); @@ -21,7 +24,7 @@ export default Ember.Service.extend({ "controller:adminLogs.staffActionLogs" ); target.transitionToRoute("adminLogs.staffActionLogs").then(() => { - controller.set("filters", Ember.Object.create()); + controller.set("filters", EmberObject.create()); controller._changeFilters(filters); }); }, @@ -52,7 +55,7 @@ export default Ember.Service.extend({ controller.setProperties({ postId: opts.postId, postEdit: opts.postEdit }); return (user.adminUserView - ? Ember.RSVP.resolve(user) + ? Promise.resolve(user) : AdminUser.find(user.get("id")) ).then(loadedUser => { controller.setProperties({ @@ -76,7 +79,7 @@ export default Ember.Service.extend({ // Try loading the email if the site supports it let tryEmail = this.siteSettings.moderators_view_emails ? adminUser.checkEmail() - : Ember.RSVP.resolve(); + : Promise.resolve(); return tryEmail.then(() => { let message = I18n.messageFormat("flagging.delete_confirm_MF", { @@ -90,7 +93,7 @@ export default Ember.Service.extend({ let userId = adminUser.get("id"); - return new Ember.RSVP.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const buttons = [ { label: I18n.t("composer.cancel"), diff --git a/app/assets/javascripts/admin/templates/api-keys.hbs b/app/assets/javascripts/admin/templates/api-keys-index.hbs similarity index 55% rename from app/assets/javascripts/admin/templates/api-keys.hbs rename to app/assets/javascripts/admin/templates/api-keys-index.hbs index a1254f3042..a0d5bf9f77 100644 --- a/app/assets/javascripts/admin/templates/api-keys.hbs +++ b/app/assets/javascripts/admin/templates/api-keys-index.hbs @@ -1,7 +1,14 @@ +{{d-button + class="btn-primary" + action=(route-action "new") + icon="plus" + label="admin.api.new_key"}} + {{#if model}} + @@ -9,8 +16,14 @@ {{#each model as |k|}} - - + + + {{/each}} @@ -52,11 +69,4 @@
{{i18n "admin.api.key"}}{{i18n "admin.api.description"}} {{i18n "admin.api.user"}} {{i18n "admin.api.created"}} {{i18n "admin.api.last_used"}}
{{k.key}}
+ {{#if k.revoked_at}}{{d-icon 'times-circle'}}{{/if}} + {{k.shortKey}} + + {{k.shortDescription}} +
{{i18n 'admin.api.user'}}
{{#if k.user}} @@ -34,17 +47,21 @@ {{/if}}
- {{d-button - class="btn-default" - action=(action "regenerateKey") - actionParam=k icon="undo" - label="admin.api.regenerate"}} - {{d-button - class="btn-default" - action=(action "revokeKey") - actionParam=k - icon="times" - label="admin.api.revoke"}} + {{d-button action=(route-action "show" k) icon="far-eye" title="admin.api.show_details"}} + {{#if k.revoked_at}} + {{d-button + action=(action "undoRevokeKey") + actionParam=k icon="undo" + title="admin.api.undo_revoke"}} + {{else}} + {{d-button + class="btn-danger" + action=(action "revokeKey") + actionParam=k + icon="times" + title="admin.api.revoke"}} + {{/if}} +
{{else}}

{{i18n "admin.api.none"}}

-{{/if}} - -{{#unless hasMasterKey}} - {{d-button - class="btn-primary" - action=(action "generateMasterKey") - icon="key"}} -{{/unless}} +{{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/admin/templates/api-keys-new.hbs b/app/assets/javascripts/admin/templates/api-keys-new.hbs new file mode 100644 index 0000000000..15f25b1ce1 --- /dev/null +++ b/app/assets/javascripts/admin/templates/api-keys-new.hbs @@ -0,0 +1,27 @@ +{{#link-to 'adminApiKeys.index' class="go-back"}} + {{d-icon 'arrow-left'}} + {{i18n 'admin.api.all_api_keys'}} +{{/link-to}} + +
+ {{#admin-form-row label="admin.api.description"}} + {{input value=model.description maxlength="255" placeholder=(i18n "admin.api.description_placeholder")}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.user_mode"}} + {{combo-box content=userModes value=userMode onSelect=(action "changeUserMode")}} + {{/admin-form-row}} + + {{#if showUserSelector}} + {{#admin-form-row label="admin.api.user"}} + {{user-selector single="true" + usernames=model.username + placeholderKey="admin.api.user_placeholder" + }} + {{/admin-form-row}} + {{/if}} + + {{#admin-form-row}} + {{d-button icon="check" label="admin.api.save" action=(action "save") class="btn-primary" disabled=saveDisabled}} + {{/admin-form-row}} +
\ No newline at end of file diff --git a/app/assets/javascripts/admin/templates/api-keys-show.hbs b/app/assets/javascripts/admin/templates/api-keys-show.hbs new file mode 100644 index 0000000000..a742cf994a --- /dev/null +++ b/app/assets/javascripts/admin/templates/api-keys-show.hbs @@ -0,0 +1,80 @@ +{{#link-to 'adminApiKeys.index' class="go-back"}} + {{d-icon 'arrow-left'}} + {{i18n 'admin.api.all_api_keys'}} +{{/link-to}} + +
+ {{#admin-form-row label="admin.api.key"}} + {{#if model.revoked_at}}{{d-icon 'times-circle'}}{{/if}} + {{model.key}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.description"}} + {{#if editingDescription}} + {{input value=buffered.description maxlength="255" placeholder=(i18n "admin.api.description_placeholder")}} + {{else}} + {{if model.description model.description (i18n "admin.api.no_description")}} + {{/if}} + +
+ {{#if editingDescription}} + {{d-button class="ok" action=(action "saveDescription") icon="check"}} + {{d-button class="cancel" action=(action "editDescription") icon="times"}} + {{else}} + {{d-button class="btn-default" action=(action "editDescription") icon="pencil-alt"}} + {{/if}} +
+ {{/admin-form-row}} + + {{#admin-form-row label="admin.api.user"}} + {{#if model.user}} + {{#link-to "adminUser" model.user}} + {{avatar model.user imageSize="small"}} {{model.user.username}} + {{/link-to}} + {{else}} + {{i18n "admin.api.all_users"}} + {{/if}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.created"}} + {{format-date model.created_at leaveAgo="true"}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.updated"}} + {{format-date model.updated_at leaveAgo="true"}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.last_used"}} + {{#if k.last_used_at}} + {{format-date k.last_used_at leaveAgo="true"}} + {{else}} + {{i18n "admin.api.never_used"}} + {{/if}} + {{/admin-form-row}} + + {{#admin-form-row label="admin.api.revoked"}} + {{#if model.revoked_at}} + {{format-date model.revoked_at leaveAgo="true"}} + {{/if}} +
+ {{#if model.revoked_at}} + {{d-button + action=(action "undoRevokeKey") + actionParam=model icon="undo" + label="admin.api.undo_revoke"}} + {{d-button + action=(action "deleteKey") + actionParam=model icon="trash" + label="admin.api.delete" + class="btn-danger"}} + {{else}} + {{d-button + class="btn-danger" + action=(action "revokeKey") + actionParam=model + icon="times" + label="admin.api.revoke"}} + {{/if}} +
+ {{/admin-form-row}} +
\ No newline at end of file diff --git a/app/assets/javascripts/admin/templates/badges-show.hbs b/app/assets/javascripts/admin/templates/badges-show.hbs index eaaa9fcde1..7a50b1084b 100644 --- a/app/assets/javascripts/admin/templates/badges-show.hbs +++ b/app/assets/javascripts/admin/templates/badges-show.hbs @@ -39,7 +39,10 @@ content=badgeGroupings class="badge-selector" nameProperty="name"}} - + {{d-button + class="btn-default" + action=(route-action "editGroupings") + icon="pencil-alt"}} @@ -138,7 +141,11 @@
- + {{d-button + class="btn-primary" + action=(action "save") + disabled=saving + label="admin.badges.save"}} {{savingStatus}} {{#unless readOnly}} {{i18n 'admin.badges.delete'}} diff --git a/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs b/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs index 883149644d..e03feb7cb7 100644 --- a/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs +++ b/app/assets/javascripts/admin/templates/components/email-styles-editor.hbs @@ -9,7 +9,7 @@
-{{ace-editor content=editorContents mode=fieldName editorId=editorId}} +{{ace-editor content=editorContents mode=currentEditorMode editorId=editorId}} {{/if}} - {{#d-button action=(action "editTheme") class="btn btn-default edit"}}{{i18n 'admin.customize.theme.edit_css_html'}}{{/d-button}} + {{d-button + class="btn-default edit" + action=(action "editTheme") + label="admin.customize.theme.edit_css_html"}}
diff --git a/app/assets/javascripts/admin/templates/email-advanced-test.hbs b/app/assets/javascripts/admin/templates/email-advanced-test.hbs index c0b8ee7a27..34853b20e8 100644 --- a/app/assets/javascripts/admin/templates/email-advanced-test.hbs +++ b/app/assets/javascripts/admin/templates/email-advanced-test.hbs @@ -3,7 +3,9 @@
{{textarea name="email" value=email class="email-body"}} - + {{d-button + action=(action "run") + label="admin.email.advanced_test.run"}}
{{#conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/templates/email-index.hbs b/app/assets/javascripts/admin/templates/email-index.hbs index c21e3a5ca6..42109ddaa9 100644 --- a/app/assets/javascripts/admin/templates/email-index.hbs +++ b/app/assets/javascripts/admin/templates/email-index.hbs @@ -20,7 +20,11 @@ {{text-field value=testEmailAddress placeholderKey="admin.email.test_email_address"}}
- + {{d-button + class="btn-primary" + action=(action "sendTestEmail") + disabled=sendTestEmailDisabled + label="admin.email.send_test"}} {{#if sentTestEmailMessage}}{{sentTestEmailMessage}}{{/if}}
{{/if}} diff --git a/app/assets/javascripts/admin/templates/email-preview-digest.hbs b/app/assets/javascripts/admin/templates/email-preview-digest.hbs index 32df5b0d97..932aa9ffc2 100644 --- a/app/assets/javascripts/admin/templates/email-preview-digest.hbs +++ b/app/assets/javascripts/admin/templates/email-preview-digest.hbs @@ -6,7 +6,10 @@ {{date-picker-past value=lastSeen id="last-seen"}} {{user-selector single="true" usernames=username canReceiveUpdates="true"}} - + {{d-button + class="btn-primary digest-refresh-button" + action=(action "refresh") + label="admin.email.refresh"}}
{{#if showHtml}} @@ -30,7 +33,11 @@ {{else}} {{text-field value=email placeholderKey="admin.email.test_email_address"}} - + {{d-button + class="btn-default" + action=(action "sendEmail") + disabled=sendEmailDisabled + label="admin.email.send_digest"}} {{#if sentEmail}} {{i18n 'admin.email.sent_test'}} {{/if}} @@ -51,4 +58,4 @@
-{{/conditional-loading-spinner}} \ No newline at end of file +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/emojis.hbs b/app/assets/javascripts/admin/templates/emojis.hbs index f677287654..6281b15c05 100644 --- a/app/assets/javascripts/admin/templates/emojis.hbs +++ b/app/assets/javascripts/admin/templates/emojis.hbs @@ -20,7 +20,12 @@ :{{e.name}}: - + + {{d-button + action=(action "destroy" e) + class="btn-danger pull-right" + icon="far-trash-alt"}} + {{/each}} diff --git a/app/assets/javascripts/admin/templates/logs/screened-emails.hbs b/app/assets/javascripts/admin/templates/logs/screened-emails.hbs index 532e68c29c..e8cb30140c 100644 --- a/app/assets/javascripts/admin/templates/logs/screened-emails.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened-emails.hbs @@ -1,7 +1,13 @@

{{i18n 'admin.logs.screened_emails.description'}}

- + +{{d-button + class="btn-default screened-email-export" + action=(action "exportScreenedEmailList") + title="admin.export_csv.button_title.screened_email" + icon="download" + label="admin.export_csv.button_text"}}
diff --git a/app/assets/javascripts/admin/templates/logs/screened-urls.hbs b/app/assets/javascripts/admin/templates/logs/screened-urls.hbs index c2a526e5f7..1ee4274368 100644 --- a/app/assets/javascripts/admin/templates/logs/screened-urls.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened-urls.hbs @@ -1,7 +1,12 @@

{{i18n 'admin.logs.screened_urls.description'}}

- + {{d-button + class="btn-default" + action=(action "exportScreenedUrlList") + title="admin.export_csv.button_title.screened_url" + icon="download" + label="admin.export_csv.button_text"}}
{{#conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/admin/templates/modal/admin-color-scheme-select-base.hbs b/app/assets/javascripts/admin/templates/modal/admin-color-scheme-select-base.hbs index 371c06df49..e1978b918a 100644 --- a/app/assets/javascripts/admin/templates/modal/admin-color-scheme-select-base.hbs +++ b/app/assets/javascripts/admin/templates/modal/admin-color-scheme-select-base.hbs @@ -7,6 +7,10 @@ valueAttribute="base_scheme_id"}} {{/d-modal-body}} diff --git a/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs b/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs index 0990760888..dd201e2aed 100644 --- a/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs +++ b/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs @@ -1,5 +1,12 @@ {{#d-modal-body title="admin.backups.operations.backup.confirm"}} - - - + {{d-button + class="btn-primary" + action=(action "startBackupWithUploads") + label="yes_value"}} + {{d-button + action=(action "startBackupWithoutUploads") + label="admin.backups.operations.backup.without_uploads"}} + {{d-button + action=(action "cancel") + label="no_value"}} {{/d-modal-body}} diff --git a/app/assets/javascripts/admin/templates/modal/admin-theme-change.hbs b/app/assets/javascripts/admin/templates/modal/admin-theme-change.hbs index 1b6b06870a..ec26f608d8 100644 --- a/app/assets/javascripts/admin/templates/modal/admin-theme-change.hbs +++ b/app/assets/javascripts/admin/templates/modal/admin-theme-change.hbs @@ -3,6 +3,9 @@ {{{diff}}} {{/d-modal-body}} diff --git a/app/assets/javascripts/admin/templates/modal/site-setting-default-categories.hbs b/app/assets/javascripts/admin/templates/modal/site-setting-default-categories.hbs new file mode 100644 index 0000000000..0bd05c2ba8 --- /dev/null +++ b/app/assets/javascripts/admin/templates/modal/site-setting-default-categories.hbs @@ -0,0 +1,8 @@ +{{#d-modal-body class="incoming-emails" rawTitle=model.key}} +{{i18n "admin.site_settings.default_categories.modal_description" count=model.count}} +{{/d-modal-body}} + + diff --git a/app/assets/javascripts/admin/templates/user-badges.hbs b/app/assets/javascripts/admin/templates/user-badges.hbs index 92e4403fe1..9f81cd2f74 100644 --- a/app/assets/javascripts/admin/templates/user-badges.hbs +++ b/app/assets/javascripts/admin/templates/user-badges.hbs @@ -22,7 +22,10 @@ {{input type="text" value=badgeReason}}
{{i18n 'admin.badges.reason_help'}} - + {{d-button + class="btn-primary" + action=(action "grantBadge") + label="admin.badges.grant"}} {{/if}} @@ -52,9 +55,14 @@ {{age-with-tooltip userBadge.granted_at}} {{#if userBadge.grouped}} - + {{d-button + action=(action "expandGroup" userBadge) + label="admin.badges.expand"}} {{else}} - + {{d-button + class="btn-danger" + action=(action "revokeBadge" userBadge) + label="admin.badges.revoke"}} {{/if}} diff --git a/app/assets/javascripts/admin/templates/user-index.hbs b/app/assets/javascripts/admin/templates/user-index.hbs index 6166eb1b9a..7eb9504fb5 100644 --- a/app/assets/javascripts/admin/templates/user-index.hbs +++ b/app/assets/javascripts/admin/templates/user-index.hbs @@ -292,33 +292,14 @@ {{#if currentUser.admin}}
-
{{i18n "admin.api.key"}}
- {{#if model.api_key}} -
- {{model.api_key.key}} - {{d-button - class="btn-default" - action=(action "regenerateApiKey") - icon="undo" - label="admin.api.regenerate"}} - {{d-button - class="btn-default" - action=(action "revokeApiKey") - icon="times" - label="admin.api.revoke"}} -
- {{else}} -
- — -
-
- {{d-button - class="btn-default" - action=(action "generateApiKey") - icon="key" - label="admin.api.generate"}} -
- {{/if}} +
{{i18n "admin.api.active_keys"}}
+
+ {{model.api_key_count}} +
+
+ {{d-button href="/admin/api/keys" label="admin.api.manage_keys"}} + +
{{/if}} diff --git a/app/assets/javascripts/admin/templates/users-list-show.hbs b/app/assets/javascripts/admin/templates/users-list-show.hbs index 36cc552089..065d2ed93d 100644 --- a/app/assets/javascripts/admin/templates/users-list-show.hbs +++ b/app/assets/javascripts/admin/templates/users-list-show.hbs @@ -1,16 +1,22 @@

{{title}}

{{#if canCheckEmails}} - {{#if showEmails}} - - {{else}} - - {{/if}} + {{#if showEmails}} + {{d-button + action=(action "toggleEmailVisibility") + class="hide-emails btn-default" + label="admin.users.hide_emails"}} + {{else}} + {{d-button + action=(action "toggleEmailVisibility") + class="show-emails btn-default" + label="admin.users.show_emails"}} + {{/if}} {{/if}}
+
{{text-field value=listFilter placeholder=searchHint}} -
{{#load-more selector=".users-list tr" action=(action "loadMore")}} diff --git a/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6 b/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6 index 8e23ba55ee..d3d301212a 100644 --- a/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/buffered-render.js.es6 @@ -1,3 +1,4 @@ +import { scheduleOnce } from "@ember/runloop"; // Ember 2.0 removes buffered rendering, but we can still implement it ourselves. // In the long term we'll want to remove this. @@ -13,7 +14,7 @@ const Mixin = { }, rerenderBuffer() { - Ember.run.scheduleOnce("render", this, this._customRender); + scheduleOnce("render", this, this._customRender); } }; diff --git a/app/assets/javascripts/discourse-common/lib/helpers.js.es6 b/app/assets/javascripts/discourse-common/lib/helpers.js.es6 index 907ae24d8c..5b7d4fdc81 100644 --- a/app/assets/javascripts/discourse-common/lib/helpers.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/helpers.js.es6 @@ -1,7 +1,15 @@ -import { get } from "discourse-common/lib/raw-handlebars"; +import { get } from "@ember/object"; +import Helper from "@ember/component/helper"; + +export function makeArray(obj) { + if (obj === null || obj === undefined) { + return []; + } + return Array.isArray(obj) ? obj : [obj]; +} export function htmlHelper(fn) { - return Ember.Helper.helper(function(...args) { + return Helper.helper(function(...args) { args = args.length > 1 ? args[0].concat({ hash: args[args.length - 1] }) : args; return new Handlebars.SafeString(fn.apply(this, args) || ""); @@ -10,8 +18,19 @@ export function htmlHelper(fn) { const _helpers = {}; +function rawGet(ctx, property, options) { + if (options.types && options.data.view) { + var view = options.data.view; + return view.getStream + ? view.getStream(property).value() + : view.getAttr(property); + } else { + return get(ctx, property); + } +} + export function registerHelper(name, fn) { - _helpers[name] = Ember.Helper.helper(fn); + _helpers[name] = Helper.helper(fn); } export function findHelper(name) { @@ -39,7 +58,7 @@ function resolveParams(ctx, options) { ) { params[k] = hash[k]; } else if (type === "ID" || type === "PathExpression") { - params[k] = get(ctx, hash[k], options); + params[k] = rawGet(ctx, hash[k], options); } }); } else { @@ -59,14 +78,14 @@ export function registerUnbound(name, fn) { options.types && (options.types[i] === "ID" || options.types[i] === "PathExpression") ) { - properties[i] = get(this, properties[i], options); + properties[i] = rawGet(this, properties[i], options); } } return fn.call(this, ...properties, resolveParams(this, options)); }; - _helpers[name] = Ember.Helper.extend({ + _helpers[name] = Helper.extend({ compute: (params, args) => fn(...params, args) }); Handlebars.registerHelper(name, func); diff --git a/app/assets/javascripts/discourse-common/lib/raw-handlebars-helpers.js.es6 b/app/assets/javascripts/discourse-common/lib/raw-handlebars-helpers.js.es6 new file mode 100644 index 0000000000..432ce98853 --- /dev/null +++ b/app/assets/javascripts/discourse-common/lib/raw-handlebars-helpers.js.es6 @@ -0,0 +1,44 @@ +import { get } from "@ember/object"; + +export function registerRawHelpers(hbs, handlebarsClass) { + hbs.helper = function() {}; + hbs.helpers = Object.create(handlebarsClass.helpers); + + hbs.helpers["get"] = function(context, options) { + var firstContext = options.contexts[0]; + var val = firstContext[context]; + + if (context.indexOf("controller.") === 0) { + context = context.slice(context.indexOf(".") + 1); + } + + return val === undefined ? get(firstContext, context) : val; + }; + + // #each .. in support (as format is transformed to this) + hbs.registerHelper("each", function( + localName, + inKeyword, + contextName, + options + ) { + var list = get(this, contextName); + var output = []; + var innerContext = Object.create(this); + for (var i = 0; i < list.length; i++) { + innerContext[localName] = list[i]; + output.push(options.fn(innerContext)); + } + return output.join(""); + }); + + function stringCompatHelper(fn) { + const old = hbs.helpers[fn]; + hbs.helpers[fn] = function(context, options) { + return old.apply(this, [hbs.helpers.get(context, options), options]); + }; + } + stringCompatHelper("if"); + stringCompatHelper("unless"); + stringCompatHelper("with"); +} diff --git a/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 b/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 index 5922fc55c8..eed8ec09a0 100644 --- a/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 +++ b/app/assets/javascripts/discourse-common/lib/raw-handlebars.js.es6 @@ -2,63 +2,8 @@ // templates are highly compatible with Ember so you don't need to worry about calling "get" // and computed properties function, additionally it uses stringParams like Ember does -// compat with ie8 in case this gets picked up elsewhere -const objectCreate = - Object.create || - function(parent) { - function F() {} - F.prototype = parent; - return new F(); - }; - const RawHandlebars = Handlebars.create(); -RawHandlebars.helper = function() {}; -RawHandlebars.helpers = objectCreate(Handlebars.helpers); - -RawHandlebars.helpers["get"] = function(context, options) { - var firstContext = options.contexts[0]; - var val = firstContext[context]; - - if (context.indexOf("controller.") === 0) { - context = context.slice(context.indexOf(".") + 1); - } - - return val === undefined ? Ember.get(firstContext, context) : val; -}; - -// adds compatability so this works with stringParams -function stringCompatHelper(fn) { - const old = RawHandlebars.helpers[fn]; - RawHandlebars.helpers[fn] = function(context, options) { - return old.apply(this, [ - RawHandlebars.helpers.get(context, options), - options - ]); - }; -} - -// #each .. in support (as format is transformed to this) -RawHandlebars.registerHelper("each", function( - localName, - inKeyword, - contextName, - options -) { - var list = Ember.get(this, contextName); - var output = []; - var innerContext = objectCreate(this); - for (var i = 0; i < list.length; i++) { - innerContext[localName] = list[i]; - output.push(options.fn(innerContext)); - } - return output.join(""); -}); - -stringCompatHelper("if"); -stringCompatHelper("unless"); -stringCompatHelper("with"); - function buildPath(blk, args) { var result = { type: "PathExpression", @@ -113,14 +58,14 @@ function replaceGet(ast) { if (Handlebars.Compiler) { RawHandlebars.Compiler = function() {}; - RawHandlebars.Compiler.prototype = objectCreate( + RawHandlebars.Compiler.prototype = Object.create( Handlebars.Compiler.prototype ); RawHandlebars.Compiler.prototype.compiler = RawHandlebars.Compiler; RawHandlebars.JavaScriptCompiler = function() {}; - RawHandlebars.JavaScriptCompiler.prototype = objectCreate( + RawHandlebars.JavaScriptCompiler.prototype = Object.create( Handlebars.JavaScriptCompiler.prototype ); RawHandlebars.JavaScriptCompiler.prototype.compiler = @@ -171,17 +116,6 @@ if (Handlebars.Compiler) { }; } -RawHandlebars.get = function(ctx, property, options) { - if (options.types && options.data.view) { - var view = options.data.view; - return view.getStream - ? view.getStream(property).value() - : view.getAttr(property); - } else { - return Ember.get(ctx, property); - } -}; - export function template() { return RawHandlebars.template.apply(this, arguments); } @@ -194,8 +128,4 @@ export function compile() { return RawHandlebars.compile.apply(this, arguments); } -export function get() { - return RawHandlebars.get.apply(this, arguments); -} - export default RawHandlebars; diff --git a/app/assets/javascripts/discourse-common/mixins/focus-event.js.es6 b/app/assets/javascripts/discourse-common/mixins/focus-event.js.es6 index c0395b53ac..974d73c958 100644 --- a/app/assets/javascripts/discourse-common/mixins/focus-event.js.es6 +++ b/app/assets/javascripts/discourse-common/mixins/focus-event.js.es6 @@ -1,10 +1,11 @@ +import { bind } from "@ember/runloop"; import { getOwner } from "discourse-common/lib/get-owner"; export default Ember.Mixin.create({ ready() { this._super(...arguments); - this._onChangeHandler = Ember.run.bind(this, this._onChange); + this._onChangeHandler = bind(this, this._onChange); // Default to true Discourse.set("hasFocus", true); @@ -26,7 +27,7 @@ export default Ember.Mixin.create({ _onChange() { const container = getOwner(this); - const appEvents = container.lookup("app-events:main"); + const appEvents = container.lookup("service:app-events"); if (document.visibilityState === "hidden") { if (Discourse.hasFocus) { diff --git a/app/assets/javascripts/discourse-common/resolver.js.es6 b/app/assets/javascripts/discourse-common/resolver.js.es6 index aeab2d45fa..e1507406bb 100644 --- a/app/assets/javascripts/discourse-common/resolver.js.es6 +++ b/app/assets/javascripts/discourse-common/resolver.js.es6 @@ -1,9 +1,7 @@ import { findHelper } from "discourse-common/lib/helpers"; +import { get } from "@ember/object"; import deprecated from "discourse-common/lib/deprecated"; - -/* global requirejs, require */ -var classify = Ember.String.classify; -var get = Ember.get; +import { classify, dasherize } from "@ember/string"; const _options = {}; @@ -63,7 +61,7 @@ export function buildResolver(baseName) { split[1] = split[1].replace(".templates", "").replace("/templates", ""); // Try slashes - let dashed = Ember.String.dasherize(split[1].replace(/\./g, "/")); + let dashed = dasherize(split[1].replace(/\./g, "/")); if ( requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed] @@ -72,7 +70,7 @@ export function buildResolver(baseName) { } // Try with dashes instead of slashes - dashed = Ember.String.dasherize(split[1].replace(/\./g, "-")); + dashed = dasherize(split[1].replace(/\./g, "-")); if ( requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed] @@ -86,7 +84,7 @@ export function buildResolver(baseName) { customResolve(parsedName) { // If we end with the name we want, use it. This allows us to define components within plugins. const suffix = parsedName.type + "s/" + parsedName.fullNameWithoutType, - dashed = Ember.String.dasherize(suffix), + dashed = dasherize(suffix), moduleName = Object.keys(requirejs.entries).find(function(e) { return ( e.indexOf(suffix, e.length - suffix.length) !== -1 || diff --git a/app/assets/javascripts/discourse-loader.js b/app/assets/javascripts/discourse-loader.js index 3a86a00da1..5052771e91 100644 --- a/app/assets/javascripts/discourse-loader.js +++ b/app/assets/javascripts/discourse-loader.js @@ -1,18 +1,108 @@ var define, requirejs; (function() { - - var MOVED_MODULES = { - "discourse/views/list/post-count-or-badges": "discourse/raw-views/list/post-count-or-badges", - "discourse/views/list/posts-count-column" : "discourse/raw-views/list/posts-count-column", - "discourse/views/list/visited-line" : "discourse/raw-views/list/visited-line", - "discourse/views/topic-list-header-column" : "discourse/raw-views/topic-list-header-column", - "discourse/views/topic-status" : "discourse/raw-views/topic-status" - }; + // In future versions of ember we don't need this + var EMBER_MODULES = {}; + if (typeof Ember !== "undefined") { + EMBER_MODULES = { + jquery: { default: $ }, + "@ember/component": { default: Ember.Component }, + "@ember/controller": { + default: Ember.Controller, + inject: Ember.inject.controller + }, + "@ember/object": { + default: Ember.Object, + get: Ember.get, + getProperties: Ember.getProperties, + set: Ember.set, + setProperties: Ember.setProperties + }, + "@ember/object/computed": { + default: Ember.computed, + alias: Ember.computed.alias, + and: Ember.computed.and, + bool: Ember.computed.bool, + collect: Ember.computed.collect, + deprecatingAlias: Ember.computed.deprecatingAlias, + empty: Ember.computed.empty, + equal: Ember.computed.equal, + filter: Ember.computed.filter, + filterBy: Ember.computed.filterBy, + gt: Ember.computed.gt, + gte: Ember.computed.gte, + intersect: Ember.computed.intersect, + lt: Ember.computed.lt, + lte: Ember.computed.lte, + map: Ember.computed.map, + mapBy: Ember.computed.mapBy, + match: Ember.computed.match, + max: Ember.computed.max, + min: Ember.computed.min, + none: Ember.computed.none, + not: Ember.computed.not, + notEmpty: Ember.computed.notEmpty, + oneWay: Ember.computed.oneWay, + or: Ember.computed.or, + readOnly: Ember.computed.readOnly, + reads: Ember.computed.reads, + setDiff: Ember.computed.setDiff, + sort: Ember.computed.sort, + sum: Ember.computed.sum, + union: Ember.computed.union, + uniq: Ember.computed.uniq, + uniqBy: Ember.computed.uniqBy + }, + "@ember/object/mixin": { default: Ember.Mixin }, + "@ember/object/proxy": { default: Ember.ObjectProxy }, + "@ember/object/evented": { on: Ember.on }, + "@ember/routing/route": { default: Ember.Route }, + "@ember/runloop": { + bind: Ember.run.bind, + cancel: Ember.run.cancel, + debounce: Ember.testing ? Ember.run : Ember.run.debounce, + later: Ember.run.later, + next: Ember.run.next, + once: Ember.run.once, + run: Ember.run, + schedule: Ember.run.schedule, + scheduleOnce: Ember.run.scheduleOnce, + throttle: Ember.run.throttle + }, + "@ember/service": { + default: Ember.Service, + inject: Ember.inject.service + }, + "@ember/utils": { + isEmpty: Ember.isEmpty + }, + "rsvp": { + Promise: Ember.RSVP.Promise, + hash: Ember.RSVP.hash, + all: Ember.RSVP.all + }, + "@ember/string": { + dasherize: Ember.String.dasherize, + classify: Ember.String.classify, + underscore: Ember.String.underscore, + camelize: Ember.String.camelize + }, + "@ember/template": { + htmlSafe: Ember.String.htmlSafe + }, + "@ember/application": { + setOwner: Ember.setOwner, + getOwner: Ember.getOwner + }, + "@ember/component/helper": { + default: Ember.Helper + } + }; + } var _isArray; if (!Array.isArray) { - _isArray = function (x) { + _isArray = function(x) { return Object.prototype.toString.call(x) === "[object Array]"; }; } else { @@ -34,28 +124,34 @@ var define, requirejs; } function unsupportedModule(length) { - throw new Error("an unsupported module was defined, expected `define(name, deps, module)` instead got: `" + length + "` arguments to define`"); + throw new Error( + "an unsupported module was defined, expected `define(name, deps, module)` instead got: `" + + length + + "` arguments to define`" + ); } - var defaultDeps = ['require', 'exports', 'module']; + var defaultDeps = ["require", "exports", "module"]; function Module(name, deps, callback, exports) { - this.id = uuid++; - this.name = name; - this.deps = !deps.length && callback.length ? defaultDeps : deps; - this.exports = exports || { }; + this.id = uuid++; + this.name = name; + this.deps = !deps.length && callback.length ? defaultDeps : deps; + this.exports = exports || {}; this.callback = callback; - this.state = undefined; - this._require = undefined; + this.state = undefined; + this._require = undefined; } - Module.prototype.makeRequire = function() { var name = this.name; - return this._require || (this._require = function(dep) { - return requirejs(resolve(dep, name)); - }); + return ( + this._require || + (this._require = function(dep) { + return requirejs(resolve(dep, name)); + }) + ); }; define = function(name, deps, callback) { @@ -65,7 +161,7 @@ var define, requirejs; if (!_isArray(deps)) { callback = deps; - deps = []; + deps = []; } registry[name] = new Module(name, deps, callback); @@ -74,7 +170,7 @@ var define, requirejs; // we don't support all of AMD // define.amd = {}; // we will support petals... - define.petal = { }; + define.petal = {}; function Alias(path) { this.name = path; @@ -91,15 +187,15 @@ var define, requirejs; var dep; // TODO: new Module // TODO: seen refactor - var module = { }; + var module = {}; for (var i = 0, l = length; i < l; i++) { dep = deps[i]; - if (dep === 'exports') { + if (dep === "exports") { module.exports = reified[i] = rseen; - } else if (dep === 'require') { + } else if (dep === "require") { reified[i] = mod.makeRequire(); - } else if (dep === 'module') { + } else if (dep === "module") { mod.exports = rseen; module = reified[i] = mod; } else { @@ -114,30 +210,22 @@ var define, requirejs; } function requireFrom(name, origin) { - - var mod = registry[name]; + var mod = EMBER_MODULES[name] || registry[name]; if (!mod) { - var moved = MOVED_MODULES[name]; - if (moved) { - console.warn("DEPRECATION: `" + name + "` was moved to `" + moved + "`"); // eslint-disable-line no-console - } - mod = registry[moved]; - } - - if (!mod) { - throw new Error('Could not find module `' + name + '` imported from `' + origin + '`'); + throw new Error( + "Could not find module `" + name + "` imported from `" + origin + "`" + ); } return requirejs(name); } function missingModule(name) { - throw new Error('Could not find module ' + name); + throw new Error("Could not find module " + name); } requirejs = require = function(name) { - - if (MOVED_MODULES[name]) { - name = MOVED_MODULES[name]; + if (EMBER_MODULES[name]) { + return EMBER_MODULES[name]; } var mod = registry[name]; @@ -146,10 +234,11 @@ var define, requirejs; mod = registry[mod.callback.name]; } - if (!mod) { missingModule(name); } + if (!mod) { + missingModule(name); + } - if (mod.state !== FAILED && - seen.hasOwnProperty(name)) { + if (mod.state !== FAILED && seen.hasOwnProperty(name)) { return seen[name]; } @@ -157,17 +246,20 @@ var define, requirejs; var module; var loaded = false; - seen[name] = { }; // placeholder for run-time cycles + seen[name] = {}; // placeholder for run-time cycles - tryFinally(function() { - reified = reify(mod, name, seen[name]); - module = mod.callback.apply(this, reified.deps); - loaded = true; - }, function() { - if (!loaded) { - mod.state = FAILED; + tryFinally( + function() { + reified = reify(mod, name, seen[name]); + module = mod.callback.apply(this, reified.deps); + loaded = true; + }, + function() { + if (!loaded) { + mod.state = FAILED; + } } - }); + ); var obj; if (module === undefined && reified.module.exports) { @@ -176,10 +268,12 @@ var define, requirejs; obj = seen[name] = module; } - if (obj !== null && - (typeof obj === 'object' || typeof obj === 'function') && - obj['default'] === undefined) { - obj['default'] = obj; + if ( + obj !== null && + (typeof obj === "object" || typeof obj === "function") && + obj["default"] === undefined + ) { + obj["default"] = obj; } return (seen[name] = obj); @@ -187,26 +281,30 @@ var define, requirejs; window.requireModule = requirejs; function resolve(child, name) { - if (child.charAt(0) !== '.') { return child; } + if (child.charAt(0) !== ".") { + return child; + } - var parts = child.split('/'); - var nameParts = name.split('/'); + var parts = child.split("/"); + var nameParts = name.split("/"); var parentBase = nameParts.slice(0, -1); for (var i = 0, l = parts.length; i < l; i++) { var part = parts[i]; - if (part === '..') { + if (part === "..") { if (parentBase.length === 0) { - throw new Error('Cannot access parent module of root'); + throw new Error("Cannot access parent module of root"); } parentBase.pop(); - } else if (part === '.') { + } else if (part === ".") { continue; - } else { parentBase.push(part); } + } else { + parentBase.push(part); + } } - return parentBase.join('/'); + return parentBase.join("/"); } requirejs.entries = requirejs._eak_seen = registry; diff --git a/app/assets/javascripts/discourse/adapters/post.js.es6 b/app/assets/javascripts/discourse/adapters/post.js.es6 index 5c3268daaa..950198067e 100644 --- a/app/assets/javascripts/discourse/adapters/post.js.es6 +++ b/app/assets/javascripts/discourse/adapters/post.js.es6 @@ -1,6 +1,7 @@ import { ajax } from "discourse/lib/ajax"; import RestAdapter from "discourse/adapters/rest"; import { Result } from "discourse/adapters/rest"; +import { underscore } from "@ember/string"; export default RestAdapter.extend({ find(store, type, findArgs) { @@ -10,7 +11,7 @@ export default RestAdapter.extend({ }, createRecord(store, type, args) { - const typeField = Ember.String.underscore(type); + const typeField = underscore(type); args.nested_post = true; return ajax(this.pathFor(store, type), { method: "POST", data: args }).then( function(json) { diff --git a/app/assets/javascripts/discourse/adapters/rest.js.es6 b/app/assets/javascripts/discourse/adapters/rest.js.es6 index b5ffc0f626..bc2839985f 100644 --- a/app/assets/javascripts/discourse/adapters/rest.js.es6 +++ b/app/assets/javascripts/discourse/adapters/rest.js.es6 @@ -1,5 +1,7 @@ +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { hashString } from "discourse/lib/hash"; +import { underscore } from "@ember/string"; const ADMIN_MODELS = [ "plugin", @@ -24,7 +26,7 @@ function rethrow(error) { throw error; } -export default Ember.Object.extend({ +export default EmberObject.extend({ storageKey(type, findArgs, options) { if (options && options.cacheKey) { return options.cacheKey; @@ -65,10 +67,14 @@ export default Ember.Object.extend({ pathFor(store, type, findArgs) { let path = this.basePath(store, type, findArgs) + - Ember.String.underscore(store.pluralize(type)); + underscore(store.pluralize(this.apiNameFor(type))); return this.appendQueryParams(path, findArgs); }, + apiNameFor(type) { + return type; + }, + findAll(store, type, findArgs) { return ajax(this.pathFor(store, type, findArgs)).catch(rethrow); }, @@ -103,7 +109,7 @@ export default Ember.Object.extend({ update(store, type, id, attrs) { const data = {}; - const typeField = Ember.String.underscore(type); + const typeField = underscore(this.apiNameFor(type)); data[typeField] = attrs; return ajax( @@ -116,7 +122,7 @@ export default Ember.Object.extend({ createRecord(store, type, attrs) { const data = {}; - const typeField = Ember.String.underscore(type); + const typeField = underscore(this.apiNameFor(type)); data[typeField] = attrs; return ajax(this.pathFor(store, type), this.getPayload("POST", data)).then( function(json) { diff --git a/app/assets/javascripts/discourse/components/about-page-users.js.es6 b/app/assets/javascripts/discourse/components/about-page-users.js.es6 index e2d65135db..7d4ff773ba 100644 --- a/app/assets/javascripts/discourse/components/about-page-users.js.es6 +++ b/app/assets/javascripts/discourse/components/about-page-users.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import { userPath } from "discourse/lib/url"; import { formatUsername, escapeExpression } from "discourse/lib/utilities"; import { normalize } from "discourse/components/user-info"; import { renderAvatar } from "discourse/helpers/user-avatar"; -export default Ember.Component.extend({ +export default Component.extend({ usersTemplates: Ember.computed("users.[]", function() { return (this.users || []).map(user => { let name = ""; diff --git a/app/assets/javascripts/discourse/components/activation-controls.js.es6 b/app/assets/javascripts/discourse/components/activation-controls.js.es6 index d7d7fe800f..9b49ce7211 100644 --- a/app/assets/javascripts/discourse/components/activation-controls.js.es6 +++ b/app/assets/javascripts/discourse/components/activation-controls.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: "activation-controls" }); diff --git a/app/assets/javascripts/discourse/components/add-category-tag-classes.js.es6 b/app/assets/javascripts/discourse/components/add-category-tag-classes.js.es6 index d5399dcfe7..d4a75e6ebe 100644 --- a/app/assets/javascripts/discourse/components/add-category-tag-classes.js.es6 +++ b/app/assets/javascripts/discourse/components/add-category-tag-classes.js.es6 @@ -1,6 +1,8 @@ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ _slug: null, didInsertElement() { @@ -25,7 +27,7 @@ export default Ember.Component.extend({ @observes("category.fullSlug", "tags") refreshClass() { - Ember.run.scheduleOnce("afterRender", this, this._updateClass); + scheduleOnce("afterRender", this, this._updateClass); }, _removeClass() { diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index 7349ce5a6b..3350ddff31 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "avatar", tagName: "span", imageIsNotASquare: false, diff --git a/app/assets/javascripts/discourse/components/backup-codes.js.es6 b/app/assets/javascripts/discourse/components/backup-codes.js.es6 index 51be5edccd..5e80cc3e3b 100644 --- a/app/assets/javascripts/discourse/components/backup-codes.js.es6 +++ b/app/assets/javascripts/discourse/components/backup-codes.js.es6 @@ -1,3 +1,4 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding @@ -12,7 +13,7 @@ function b64EncodeUnicode(str) { ); } -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["backup-codes"], backupCodes: null, diff --git a/app/assets/javascripts/discourse/components/backup-uploader.js.es6 b/app/assets/javascripts/discourse/components/backup-uploader.js.es6 index 66b2665095..e75470439d 100644 --- a/app/assets/javascripts/discourse/components/backup-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/backup-uploader.js.es6 @@ -1,9 +1,11 @@ +import Component from "@ember/component"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; +import { on } from "@ember/object/evented"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { tagName: "span", @computed("uploading", "uploadProgress") @@ -34,7 +36,7 @@ export default Ember.Component.extend(UploadMixin, { }; }, - _init: function() { + _init: on("didInsertElement", function() { const $upload = $(this.element); $upload.on("fileuploadadd", (e, data) => { @@ -47,5 +49,5 @@ export default Ember.Component.extend(UploadMixin, { }) .catch(popupAjaxError); }); - }.on("didInsertElement") + }) }); diff --git a/app/assets/javascripts/discourse/components/badge-button.js.es6 b/app/assets/javascripts/discourse/components/badge-button.js.es6 index d0c2708b66..dde5bfb804 100644 --- a/app/assets/javascripts/discourse/components/badge-button.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-button.js.es6 @@ -1,6 +1,8 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", classNameBindings: [ ":user-badge", @@ -14,5 +16,5 @@ export default Ember.Component.extend({ }, attributeBindings: ["data-badge-name", "title"], - "data-badge-name": Ember.computed.alias("badge.name") + "data-badge-name": alias("badge.name") }); diff --git a/app/assets/javascripts/discourse/components/badge-card.js.es6 b/app/assets/javascripts/discourse/components/badge-card.js.es6 index c4312447e9..f9380b11eb 100644 --- a/app/assets/javascripts/discourse/components/badge-card.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-card.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { sanitize, emojiUnescape } from "discourse/lib/text"; -export default Ember.Component.extend({ +export default Component.extend({ size: "medium", classNameBindings: [":badge-card", "size", "badge.slug"], diff --git a/app/assets/javascripts/discourse/components/badge-selector.js.es6 b/app/assets/javascripts/discourse/components/badge-selector.js.es6 index 53ed8e385a..94c08c95ca 100644 --- a/app/assets/javascripts/discourse/components/badge-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-selector.js.es6 @@ -1,3 +1,4 @@ +import Component from "@ember/component"; import { on, observes, @@ -6,7 +7,7 @@ import { import { findRawTemplate } from "discourse/lib/raw-templates"; const { makeArray } = Ember; -export default Ember.Component.extend({ +export default Component.extend({ @computed("placeholderKey") placeholder(placeholderKey) { return placeholderKey ? I18n.t(placeholderKey) : ""; diff --git a/app/assets/javascripts/discourse/components/badge-title.js.es6 b/app/assets/javascripts/discourse/components/badge-title.js.es6 index 117b1cc490..d7fd08c318 100644 --- a/app/assets/javascripts/discourse/components/badge-title.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-title.js.es6 @@ -1,12 +1,18 @@ +import Component from "@ember/component"; import { ajax } from "discourse/lib/ajax"; -import BadgeSelectController from "discourse/mixins/badge-select-controller"; +import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend(BadgeSelectController, { +export default Component.extend({ classNames: ["badge-title"], saved: false, saving: false, + @computed("selectableUserBadges", "selectedUserBadgeId") + selectedUserBadge(selectableUserBadges, selectedUserBadgeId) { + return selectableUserBadges.findBy("id", parseInt(selectedUserBadgeId)); + }, + actions: { save() { this.setProperties({ saved: false, saving: true }); diff --git a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 index e8af6acc94..64942198ed 100644 --- a/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 +++ b/app/assets/javascripts/discourse/components/basic-topic-list.js.es6 @@ -1,8 +1,10 @@ +import { alias, not } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ - loadingMore: Ember.computed.alias("topicList.loadingMore"), - loading: Ember.computed.not("loaded"), +export default Component.extend({ + loadingMore: alias("topicList.loadingMore"), + loading: not("loaded"), @computed("topicList.loaded") loaded() { diff --git a/app/assets/javascripts/discourse/components/bread-crumbs.js.es6 b/app/assets/javascripts/discourse/components/bread-crumbs.js.es6 index cd8157c828..e420fcce7c 100644 --- a/app/assets/javascripts/discourse/components/bread-crumbs.js.es6 +++ b/app/assets/javascripts/discourse/components/bread-crumbs.js.es6 @@ -1,13 +1,15 @@ +import { alias, filter, or } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; // A breadcrumb including category drop downs -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: ["hidden:hidden", ":category-breadcrumb"], tagName: "ol", - parentCategory: Ember.computed.alias("category.parentCategory"), + parentCategory: alias("category.parentCategory"), - parentCategories: Ember.computed.filter("categories", function(c) { + parentCategories: filter("categories", function(c) { if ( c.id === this.site.get("uncategorized_category_id") && !this.siteSettings.allow_uncategorized_topics @@ -33,7 +35,7 @@ export default Ember.Component.extend({ return this.site.mobileView && !category; }, - firstCategory: Ember.computed.or("{parentCategory,category}"), + firstCategory: or("{parentCategory,category}"), @computed("category", "parentCategory") secondCategory(category, parentCategory) { diff --git a/app/assets/javascripts/discourse/components/bulk-select-button.js.es6 b/app/assets/javascripts/discourse/components/bulk-select-button.js.es6 index 04d125b803..1070402ca0 100644 --- a/app/assets/javascripts/discourse/components/bulk-select-button.js.es6 +++ b/app/assets/javascripts/discourse/components/bulk-select-button.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import showModal from "discourse/lib/show-modal"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["bulk-select-container"], actions: { diff --git a/app/assets/javascripts/discourse/components/categories-and-latest-topics.js.es6 b/app/assets/javascripts/discourse/components/categories-and-latest-topics.js.es6 index 8da2cf8495..4f2b2c2497 100644 --- a/app/assets/javascripts/discourse/components/categories-and-latest-topics.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-and-latest-topics.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["categories-and-latest"] }); diff --git a/app/assets/javascripts/discourse/components/categories-and-top-topics.js.es6 b/app/assets/javascripts/discourse/components/categories-and-top-topics.js.es6 index 4f1c888692..7d9caf45c2 100644 --- a/app/assets/javascripts/discourse/components/categories-and-top-topics.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-and-top-topics.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["categories-and-top"] }); diff --git a/app/assets/javascripts/discourse/components/categories-boxes-topic.js.es6 b/app/assets/javascripts/discourse/components/categories-boxes-topic.js.es6 index c061cb55e9..b5536923ec 100644 --- a/app/assets/javascripts/discourse/components/categories-boxes-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-boxes-topic.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "li", @computed("topic.pinned", "topic.closed", "topic.archived") diff --git a/app/assets/javascripts/discourse/components/categories-boxes-with-topics.js.es6 b/app/assets/javascripts/discourse/components/categories-boxes-with-topics.js.es6 index ed9e4a87a7..40b16d03fa 100644 --- a/app/assets/javascripts/discourse/components/categories-boxes-with-topics.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-boxes-with-topics.js.es6 @@ -1,6 +1,8 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "section", classNameBindings: [ ":category-boxes-with-topics", @@ -10,7 +12,7 @@ export default Ember.Component.extend({ @computed("categories.[].uploaded_logo.url") anyLogos() { return this.categories.any(c => { - return !Ember.isEmpty(c.get("uploaded_logo.url")); + return !isEmpty(c.get("uploaded_logo.url")); }); } }); diff --git a/app/assets/javascripts/discourse/components/categories-boxes.js.es6 b/app/assets/javascripts/discourse/components/categories-boxes.js.es6 index f78bfbfcd7..11b76ed1d4 100644 --- a/app/assets/javascripts/discourse/components/categories-boxes.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-boxes.js.es6 @@ -1,7 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import DiscourseURL from "discourse/lib/url"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "section", classNameBindings: [ ":category-boxes", @@ -11,12 +13,12 @@ export default Ember.Component.extend({ @computed("categories.[].uploaded_logo.url") anyLogos() { - return this.categories.any(c => !Ember.isEmpty(c.get("uploaded_logo.url"))); + return this.categories.any(c => !isEmpty(c.get("uploaded_logo.url"))); }, @computed("categories.[].subcategories") hasSubcategories() { - return this.categories.any(c => !Ember.isEmpty(c.get("subcategories"))); + return this.categories.any(c => !isEmpty(c.get("subcategories"))); }, click(e) { diff --git a/app/assets/javascripts/discourse/components/categories-only.js.es6 b/app/assets/javascripts/discourse/components/categories-only.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/discourse/components/categories-only.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-only.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/discourse/components/categories-topic-list.js.es6 b/app/assets/javascripts/discourse/components/categories-topic-list.js.es6 index 9b102dc46c..ccc903e96e 100644 --- a/app/assets/javascripts/discourse/components/categories-topic-list.js.es6 +++ b/app/assets/javascripts/discourse/components/categories-topic-list.js.es6 @@ -1,2 +1,3 @@ +import Component from "@ember/component"; // Exists so plugins can use it -export default Ember.Component.extend(); +export default Component.extend(); diff --git a/app/assets/javascripts/discourse/components/category-title-before.js.es6 b/app/assets/javascripts/discourse/components/category-title-before.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/discourse/components/category-title-before.js.es6 +++ b/app/assets/javascripts/discourse/components/category-title-before.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/discourse/components/category-title-link.js.es6 b/app/assets/javascripts/discourse/components/category-title-link.js.es6 index 4a6fa5d604..c6dacce317 100644 --- a/app/assets/javascripts/discourse/components/category-title-link.js.es6 +++ b/app/assets/javascripts/discourse/components/category-title-link.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "h3" }); diff --git a/app/assets/javascripts/discourse/components/category-unread.js.es6 b/app/assets/javascripts/discourse/components/category-unread.js.es6 index 1d3bdc0353..5bf9ae8df8 100644 --- a/app/assets/javascripts/discourse/components/category-unread.js.es6 +++ b/app/assets/javascripts/discourse/components/category-unread.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "span" }); diff --git a/app/assets/javascripts/discourse/components/cdn-img.js.es6 b/app/assets/javascripts/discourse/components/cdn-img.js.es6 index f10b1d9e1e..338c71a1ee 100644 --- a/app/assets/javascripts/discourse/components/cdn-img.js.es6 +++ b/app/assets/javascripts/discourse/components/cdn-img.js.es6 @@ -1,6 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; +import { htmlSafe } from "@ember/template"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("src") @@ -11,7 +13,7 @@ export default Ember.Component.extend({ @computed("width", "height") style(width, height) { if (width && height) { - return Ember.String.htmlSafe(`--aspect-ratio: ${width / height};`); + return htmlSafe(`--aspect-ratio: ${width / height};`); } } }); diff --git a/app/assets/javascripts/discourse/components/choose-message.js.es6 b/app/assets/javascripts/discourse/components/choose-message.js.es6 index 581cc361d5..cb6c251355 100644 --- a/app/assets/javascripts/discourse/components/choose-message.js.es6 +++ b/app/assets/javascripts/discourse/components/choose-message.js.es6 @@ -1,8 +1,12 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import debounce from "discourse/lib/debounce"; import { searchForTerm } from "discourse/lib/search"; import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ loading: null, noResults: null, messages: null, @@ -29,7 +33,7 @@ export default Ember.Component.extend({ search: debounce(function(title) { const currentTopicId = this.currentTopicId; - if (Ember.isEmpty(title)) { + if (isEmpty(title)) { this.setProperties({ messages: null, loading: false }); return; } @@ -54,11 +58,9 @@ export default Ember.Component.extend({ actions: { chooseMessage(message) { - const messageId = Ember.get(message, "id"); + const messageId = get(message, "id"); this.set("selectedTopicId", messageId); - Ember.run.next(() => - $(`#choose-message-${messageId}`).prop("checked", "true") - ); + next(() => $(`#choose-message-${messageId}`).prop("checked", "true")); return false; } } diff --git a/app/assets/javascripts/discourse/components/choose-topic.js.es6 b/app/assets/javascripts/discourse/components/choose-topic.js.es6 index 4ee45b5eee..f2d4792414 100644 --- a/app/assets/javascripts/discourse/components/choose-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/choose-topic.js.es6 @@ -1,8 +1,11 @@ +import { isEmpty } from "@ember/utils"; +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import debounce from "discourse/lib/debounce"; import { searchForTerm } from "discourse/lib/search"; import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ loading: null, noResults: null, topics: null, @@ -37,7 +40,7 @@ export default Ember.Component.extend({ const currentTopicId = this.currentTopicId; - if (Ember.isEmpty(title)) { + if (isEmpty(title)) { this.setProperties({ topics: null, loading: false }); return; } @@ -61,7 +64,7 @@ export default Ember.Component.extend({ actions: { chooseTopic(topic) { this.set("selectedTopicId", topic.id); - Ember.run.next(() => { + next(() => { document.getElementById(`choose-topic-${topic.id}`).checked = true; }); return false; diff --git a/app/assets/javascripts/discourse/components/color-picker-choice.js.es6 b/app/assets/javascripts/discourse/components/color-picker-choice.js.es6 index 8ea284b8f3..a1933193d2 100644 --- a/app/assets/javascripts/discourse/components/color-picker-choice.js.es6 +++ b/app/assets/javascripts/discourse/components/color-picker-choice.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "button", attributeBindings: ["style", "title"], classNameBindings: [":colorpicker", "isUsed:used-color:unused-color"], diff --git a/app/assets/javascripts/discourse/components/color-picker.js.es6 b/app/assets/javascripts/discourse/components/color-picker.js.es6 index 8fc84886c7..c50fe34d6c 100644 --- a/app/assets/javascripts/discourse/components/color-picker.js.es6 +++ b/app/assets/javascripts/discourse/components/color-picker.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: "colors-container", actions: { diff --git a/app/assets/javascripts/discourse/components/composer-action-title.js.es6 b/app/assets/javascripts/discourse/components/composer-action-title.js.es6 index c4e014c5f7..8e4fd6c9f7 100644 --- a/app/assets/javascripts/discourse/components/composer-action-title.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-action-title.js.es6 @@ -1,3 +1,5 @@ +import { alias, equal } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { PRIVATE_MESSAGE, @@ -16,11 +18,11 @@ const TITLES = { [EDIT_SHARED_DRAFT]: "composer.edit_shared_draft" }; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["composer-action-title"], - options: Ember.computed.alias("model.replyOptions"), - action: Ember.computed.alias("model.action"), - isEditing: Ember.computed.equal("action", EDIT), + options: alias("model.replyOptions"), + action: alias("model.action"), + isEditing: equal("action", EDIT), @computed("options", "action") actionTitle(opts, action) { diff --git a/app/assets/javascripts/discourse/components/composer-body.js.es6 b/app/assets/javascripts/discourse/components/composer-body.js.es6 index 301e22452f..f265917279 100644 --- a/app/assets/javascripts/discourse/components/composer-body.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-body.js.es6 @@ -1,3 +1,9 @@ +import { throttle } from "@ember/runloop"; +import { run } from "@ember/runloop"; +import { cancel } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes @@ -20,7 +26,7 @@ function mouseYPos(e) { return e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY); } -export default Ember.Component.extend(KeyEnterEscape, { +export default Component.extend(KeyEnterEscape, { elementId: "reply-control", classNameBindings: [ @@ -59,7 +65,7 @@ export default Ember.Component.extend(KeyEnterEscape, { "composer.canEditTopicFeaturedLink" ) resize() { - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { if (!this.element || this.isDestroying || this.isDestroyed) { return; } @@ -77,8 +83,8 @@ export default Ember.Component.extend(KeyEnterEscape, { // One second from now, check to see if the last key was hit when // we recorded it. If it was, the user paused typing. - Ember.run.cancel(this._lastKeyTimeout); - this._lastKeyTimeout = Ember.run.later(() => { + cancel(this._lastKeyTimeout); + this._lastKeyTimeout = later(() => { if (lastKeyUp !== this._lastKeyUp) { return; } @@ -115,7 +121,7 @@ export default Ember.Component.extend(KeyEnterEscape, { const throttledPerformDrag = (event => { event.preventDefault(); - Ember.run.throttle(this, performDrag, event, THROTTLE_RATE); + throttle(this, performDrag, event, THROTTLE_RATE); }).bind(this); const endDrag = () => { @@ -152,7 +158,7 @@ export default Ember.Component.extend(KeyEnterEscape, { this._super(...arguments); this.setupComposerResizeEvents(); - const resize = () => Ember.run(() => this.resize()); + const resize = () => run(() => this.resize()); const triggerOpen = () => { if (this.get("composer.composeState") === Composer.OPEN) { this.appEvents.trigger("composer:opened"); diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 3c204ec0c7..876851b658 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -1,3 +1,9 @@ +import { throttle } from "@ember/runloop"; +import { next } from "@ember/runloop"; +import { debounce } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import userSearch from "discourse/lib/user-search"; import { default as computed, @@ -53,7 +59,7 @@ export function addComposerUploadHandler(extensions, method) { }); } -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: ["showToolbar:toolbar-visible", ":wmd-controls"], uploadProgress: 0, @@ -182,7 +188,7 @@ export default Ember.Component.extend({ transformComplete: v => v.username || v.name, afterComplete() { // ensures textarea scroll position is correct - Ember.run.scheduleOnce("afterRender", () => $input.blur().focus()); + scheduleOnce("afterRender", () => $input.blur().focus()); } }); } @@ -191,24 +197,10 @@ export default Ember.Component.extend({ this._initInputPreviewSync($input, $preview); } else { $input.on("scroll", () => - Ember.run.throttle( - this, - this._syncEditorAndPreviewScroll, - $input, - $preview, - 20 - ) + throttle(this, this._syncEditorAndPreviewScroll, $input, $preview, 20) ); } - if (!this.site.mobileView) { - $preview - .off("touchstart mouseenter", "img") - .on("touchstart mouseenter", "img", () => { - this._placeImageScaleButtons($preview); - }); - } - // Focus on the body unless we have a title if ( !this.get("composer.canEditTitle") && @@ -323,7 +315,7 @@ export default Ember.Component.extend({ this.appEvents.on(event, this, this._resetShouldBuildScrollMap); }); - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { $input.on("touchstart mouseenter", () => { if (!$preview.is(":visible")) return; $preview.off("scroll"); @@ -349,7 +341,7 @@ export default Ember.Component.extend({ this.set("shouldBuildScrollMap", false); } - Ember.run.throttle(this, $callback, $input, $preview, this.scrollMap, 20); + throttle(this, $callback, $input, $preview, this.scrollMap, 20); }, _teardownInputPreviewSync() { @@ -566,7 +558,7 @@ export default Ember.Component.extend({ }, _warnMentionedGroups($preview) { - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { var found = this.warnedGroupMentions || []; $preview.find(".mention-group.notify").each((idx, e) => { const $e = $(e); @@ -590,16 +582,11 @@ export default Ember.Component.extend({ _warnCannotSeeMention($preview) { const composerDraftKey = this.get("composer.draftKey"); - if ( - composerDraftKey === Composer.CREATE_TOPIC || - composerDraftKey === Composer.NEW_PRIVATE_MESSAGE_KEY || - composerDraftKey === Composer.REPLY_AS_NEW_TOPIC_KEY || - composerDraftKey === Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY - ) { + if (composerDraftKey === Composer.NEW_PRIVATE_MESSAGE_KEY) { return; } - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { let found = this.warnedCannotSeeMentions || []; $preview.find(".mention.cannot-see").each((idx, e) => { @@ -609,7 +596,7 @@ export default Ember.Component.extend({ if (found.indexOf(name) === -1) { // add a delay to allow for typing, so you don't open the warning right away // previously we would warn after @bob even if you were about to mention @bob2 - Ember.run.later( + later( this, () => { if ( @@ -630,7 +617,7 @@ export default Ember.Component.extend({ }, _resetUpload(removePlaceholder) { - Ember.run.next(() => { + next(() => { if (this._validUploads > 0) { this._validUploads--; } @@ -849,7 +836,11 @@ export default Ember.Component.extend({ return; } - const replacement = match.replace(imageScaleRegex, `$1,${scale}%$3`); + const replacement = match.replace( + imageScaleRegex, + `![$1|$2, ${scale}%]($4)` + ); + this.appEvents.trigger( "composer:replace-text", matchingPlaceholder[index], @@ -864,11 +855,18 @@ export default Ember.Component.extend({ // regex matches only upload placeholders with size defined, // which is required for resizing - // original string `![28|690x226,5%](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)` - // match 1 `![28|690x226` - // match 2 `5` - // match 3 `](upload://ceEfx3vO7bx7Cecv2co1SrnoTpW.png)` - const imageScaleRegex = /(!\[(?:\S*?(?=\|)\|)*?(?:\d{1,6}x\d{1,6})+?)(?:,?(\d{1,3})?%?)?(\]\(upload:\/\/\S*?\))/g; + // original string `![image|690x220, 50%](upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title")` + // group 1 `image` + // group 2 `690x220` + // group 3 `, 50%` + // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png' + // group 4 'upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title"' + + // Notes: + // Group 3 is optional. group 4 can match images with or without a markdown title. + // All matches are whitespace tolerant as long it's still valid markdown + + const imageScaleRegex = /!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?\]\((upload:\/\/.*?)\)/g; // wraps previewed upload markdown in a codeblock in its own class to keep a track // of indexes later on to replace the correct upload placeholder in the composer @@ -909,9 +907,9 @@ export default Ember.Component.extend({ @on("willDestroyElement") _composerClosed() { this.appEvents.trigger("composer:will-close"); - Ember.run.next(() => { + next(() => { // need to wait a bit for the "slide down" transition of the composer - Ember.run.later( + later( () => this.appEvents.trigger("composer:closed"), Ember.testing ? 0 : 400 ); @@ -932,8 +930,6 @@ export default Ember.Component.extend({ }, showPreview() { - const $preview = $(this.element.querySelector(".d-editor-preview-wrapper")); - this._placeImageScaleButtons($preview); this.send("togglePreview"); }, @@ -984,7 +980,7 @@ export default Ember.Component.extend({ // Paint mentions const unseenMentions = linkSeenMentions($preview, this.siteSettings); if (unseenMentions.length) { - Ember.run.debounce( + debounce( this, this._renderUnseenMentions, $preview, @@ -999,7 +995,7 @@ export default Ember.Component.extend({ // Paint category hashtags const unseenCategoryHashtags = linkSeenCategoryHashtags($preview); if (unseenCategoryHashtags.length) { - Ember.run.debounce( + debounce( this, this._renderUnseenCategoryHashtags, $preview, @@ -1012,7 +1008,7 @@ export default Ember.Component.extend({ if (this.siteSettings.tagging_enabled) { const unseenTagHashtags = linkSeenTagHashtags($preview); if (unseenTagHashtags.length) { - Ember.run.debounce( + debounce( this, this._renderUnseenTagHashtags, $preview, @@ -1023,7 +1019,7 @@ export default Ember.Component.extend({ } // Paint oneboxes - Ember.run.debounce( + debounce( this, () => { const oneboxes = {}; @@ -1082,9 +1078,7 @@ export default Ember.Component.extend({ ); } - if (this.site.mobileView && $preview.is(":visible")) { - this._placeImageScaleButtons($preview); - } + this._placeImageScaleButtons($preview); this.trigger("previewRefreshed", $preview); this.afterRefresh($preview); diff --git a/app/assets/javascripts/discourse/components/composer-message.js.es6 b/app/assets/javascripts/discourse/components/composer-message.js.es6 index 4cdda3fc49..6cb98b8018 100644 --- a/app/assets/javascripts/discourse/components/composer-message.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-message.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { getOwner } from "discourse-common/lib/get-owner"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [":composer-popup", ":hidden", "message.extraClass"], @computed("message.templateName") diff --git a/app/assets/javascripts/discourse/components/composer-messages.js.es6 b/app/assets/javascripts/discourse/components/composer-messages.js.es6 index 6a01d33950..e9860973a2 100644 --- a/app/assets/javascripts/discourse/components/composer-messages.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-messages.js.es6 @@ -1,8 +1,12 @@ +import { not } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import LinkLookup from "discourse/lib/link-lookup"; let _messagesCache = {}; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [":composer-popup-container", "hidden"], checkedMessages: false, messages: null, @@ -13,7 +17,7 @@ export default Ember.Component.extend({ _yourselfConfirm: null, similarTopics: null, - hidden: Ember.computed.not("composer.viewOpenOrFullscreen"), + hidden: not("composer.viewOpenOrFullscreen"), didInsertElement() { this._super(...arguments); @@ -22,7 +26,7 @@ export default Ember.Component.extend({ this.appEvents.on("composer:find-similar", this, this._findSimilar); this.appEvents.on("composer-messages:close", this, this._closeTop); this.appEvents.on("composer-messages:create", this, this._create); - Ember.run.scheduleOnce("afterRender", this, this.reset); + scheduleOnce("afterRender", this, this.reset); }, willDestroyElement() { @@ -121,7 +125,7 @@ export default Ember.Component.extend({ _create(info) { this.reset(); - this.send("popup", Ember.Object.create(info)); + this.send("popup", EmberObject.create(info)); }, _findSimilar() { diff --git a/app/assets/javascripts/discourse/components/composer-title.js.es6 b/app/assets/javascripts/discourse/components/composer-title.js.es6 index 5302ab85f4..556b24bda8 100644 --- a/app/assets/javascripts/discourse/components/composer-title.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-title.js.es6 @@ -1,15 +1,22 @@ +import { alias, or } from "@ember/object/computed"; +import { next } from "@ember/runloop"; +import { debounce } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; import InputValidation from "discourse/models/input-validation"; -import { load, lookupCache } from "pretty-text/oneboxer"; +import { load } from "pretty-text/oneboxer"; +import { lookupCache } from "pretty-text/oneboxer-cache"; import { ajax } from "discourse/lib/ajax"; import afterTransition from "discourse/lib/after-transition"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["title-input"], - watchForLink: Ember.computed.alias("composer.canEditTopicFeaturedLink"), + watchForLink: alias("composer.canEditTopicFeaturedLink"), + disabled: or("composer.loading", "composer.disableTitleInput"), didInsertElement() { this._super(...arguments); @@ -22,7 +29,7 @@ export default Ember.Component.extend({ } if (this.get("composer.titleLength") > 0) { - Ember.run.debounce(this, this._titleChanged, 10); + debounce(this, this._titleChanged, 10); } }, @@ -77,13 +84,13 @@ export default Ember.Component.extend({ } if (Ember.testing) { - Ember.run.next(() => + next(() => // not ideal but we don't want to run this in current // runloop to avoid an error in console this._checkForUrl() ); } else { - Ember.run.debounce(this, this._checkForUrl, 500); + debounce(this, this._checkForUrl, 500); } }, @@ -132,14 +139,14 @@ export default Ember.Component.extend({ }) .finally(() => { this.set("composer.loading", false); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector("input")).putCursorAtEnd(); }); }); } else { this._updatePost(loadOnebox); this.set("composer.loading", false); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element.querySelector("input")).putCursorAtEnd(); }); } diff --git a/app/assets/javascripts/discourse/components/composer-toggles.js.es6 b/app/assets/javascripts/discourse/components/composer-toggles.js.es6 index f618e1ca61..9f0547d641 100644 --- a/app/assets/javascripts/discourse/components/composer-toggles.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-toggles.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("composeState") diff --git a/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 b/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 index 04a1ba7dc5..3e9aa03784 100644 --- a/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-user-selector.js.es6 @@ -1,9 +1,11 @@ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ showSelector: true, shouldHide: false, defaultUsernameCount: 0, @@ -75,7 +77,7 @@ export default Ember.Component.extend({ toggleSelector() { this.set("showSelector", true); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element) .find("input") .focus(); diff --git a/app/assets/javascripts/discourse/components/conditional-loading-section.js.es6 b/app/assets/javascripts/discourse/components/conditional-loading-section.js.es6 index dd8f321635..fb6f310518 100644 --- a/app/assets/javascripts/discourse/components/conditional-loading-section.js.es6 +++ b/app/assets/javascripts/discourse/components/conditional-loading-section.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["conditional-loading-section"], classNameBindings: ["isLoading"], diff --git a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 index e0353315fe..1c6e37ec03 100644 --- a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 +++ b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [ ":loading-container", "containerClass", diff --git a/app/assets/javascripts/discourse/components/connector-container.js.es6 b/app/assets/javascripts/discourse/components/connector-container.js.es6 index 905ec1058e..6c29674578 100644 --- a/app/assets/javascripts/discourse/components/connector-container.js.es6 +++ b/app/assets/javascripts/discourse/components/connector-container.js.es6 @@ -1 +1,2 @@ -export default Ember.Component.extend(); +import Component from "@ember/component"; +export default Component.extend(); diff --git a/app/assets/javascripts/discourse/components/cook-text.js.es6 b/app/assets/javascripts/discourse/components/cook-text.js.es6 index 3e345df054..256636a3c5 100644 --- a/app/assets/javascripts/discourse/components/cook-text.js.es6 +++ b/app/assets/javascripts/discourse/components/cook-text.js.es6 @@ -1,7 +1,9 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import { cookAsync } from "discourse/lib/text"; import { ajax } from "discourse/lib/ajax"; -const CookText = Ember.Component.extend({ +const CookText = Component.extend({ tagName: "", cooked: null, @@ -11,7 +13,7 @@ const CookText = Ember.Component.extend({ this.set("cooked", cooked); // no choice but to defer this cause // pretty text may only be loaded now - Ember.run.next(() => + next(() => window .requireModule("pretty-text/upload-short-url") .resolveAllShortUrls(ajax) diff --git a/app/assets/javascripts/discourse/components/count-i18n.js.es6 b/app/assets/javascripts/discourse/components/count-i18n.js.es6 index 5ee48fb5ab..9bdb715dc5 100644 --- a/app/assets/javascripts/discourse/components/count-i18n.js.es6 +++ b/app/assets/javascripts/discourse/components/count-i18n.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "span", rerenderTriggers: ["count", "suffix"], diff --git a/app/assets/javascripts/discourse/components/create-account.js.es6 b/app/assets/javascripts/discourse/components/create-account.js.es6 index 9d91b58b35..e382244dc9 100644 --- a/app/assets/javascripts/discourse/components/create-account.js.es6 +++ b/app/assets/javascripts/discourse/components/create-account.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["create-account"], didInsertElement() { diff --git a/app/assets/javascripts/discourse/components/create-topic-button.js.es6 b/app/assets/javascripts/discourse/components/create-topic-button.js.es6 index a03702e98e..b2ab306a12 100644 --- a/app/assets/javascripts/discourse/components/create-topic-button.js.es6 +++ b/app/assets/javascripts/discourse/components/create-topic-button.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "", label: "topic.create" }); diff --git a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 index 1e7658cfd5..96c29f9081 100644 --- a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 @@ -1,8 +1,10 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { observes } from "ember-addons/ember-computed-decorators"; import LivePostCounts from "discourse/models/live-post-counts"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: ["hidden:hidden", ":create-topics-notice"], enabled: false, @@ -11,7 +13,7 @@ export default Ember.Component.extend({ publicPostCount: null, requiredTopics: 5, - requiredPosts: Ember.computed.alias("siteSettings.tl1_requires_read_posts"), + requiredPosts: alias("siteSettings.tl1_requires_read_posts"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/csv-uploader.js.es6 b/app/assets/javascripts/discourse/components/csv-uploader.js.es6 index a37e10f3cc..6fa3792d36 100644 --- a/app/assets/javascripts/discourse/components/csv-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/csv-uploader.js.es6 @@ -1,7 +1,9 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; +import { on } from "@ember/object/evented"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "csv", tagName: "span", uploadUrl: "/invites/upload_csv", @@ -31,7 +33,7 @@ export default Ember.Component.extend(UploadMixin, { return { autoUpload: false }; }, - _init: function() { + _init: on("didInsertElement", function() { const $upload = $(this.element); $upload.on("fileuploadadd", (e, data) => { @@ -42,5 +44,5 @@ export default Ember.Component.extend(UploadMixin, { result => (result ? data.submit() : data.abort()) ); }); - }.on("didInsertElement") + }) }); diff --git a/app/assets/javascripts/discourse/components/custom-html.js.es6 b/app/assets/javascripts/discourse/components/custom-html.js.es6 index b30649deb5..8dd3414e23 100644 --- a/app/assets/javascripts/discourse/components/custom-html.js.es6 +++ b/app/assets/javascripts/discourse/components/custom-html.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { getCustomHTML } from "discourse/helpers/custom-html"; import { getOwner } from "discourse-common/lib/get-owner"; -export default Ember.Component.extend({ +export default Component.extend({ triggerAppEvent: null, init() { diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6 index 2665e6e83b..359d058d24 100644 --- a/app/assets/javascripts/discourse/components/d-button.js.es6 +++ b/app/assets/javascripts/discourse/components/d-button.js.es6 @@ -1,14 +1,18 @@ +import { notEmpty, empty } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import DiscourseURL from "discourse/lib/url"; -export default Ember.Component.extend({ +export default Component.extend({ // subclasses need this layoutName: "components/d-button", form: null, + type: "button", + tagName: "button", - classNameBindings: [":btn", "noText", "btnType"], + classNameBindings: ["btnLink::btn", "btnLink", "noText", "btnType"], attributeBindings: [ "form", "disabled", @@ -18,7 +22,9 @@ export default Ember.Component.extend({ "type" ], - btnIcon: Ember.computed.notEmpty("icon"), + btnIcon: notEmpty("icon"), + + btnLink: Ember.computed.equal("display", "link"), @computed("icon", "translatedLabel") btnType(icon, translatedLabel) { @@ -29,7 +35,7 @@ export default Ember.Component.extend({ } }, - noText: Ember.computed.empty("translatedLabel"), + noText: empty("translatedLabel"), @computed("title") translatedTitle: { diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index dc2e9fe00a..3d926b9783 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -1,3 +1,10 @@ +import { next } from "@ember/runloop"; +import { debounce } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import { inject as service } from "@ember/service"; +import Component from "@ember/component"; /*global Mousetrap:true */ import { default as computed, @@ -22,6 +29,7 @@ import { translations } from "pretty-text/emoji/data"; import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji"; import { emojiUrlFor } from "discourse/lib/text"; import showModal from "discourse/lib/show-modal"; +import { Promise } from "rsvp"; // Our head can be a static string or a function that returns a string // based on input (like for numbered lists). @@ -211,14 +219,14 @@ export function onToolbarCreate(func) { addToolbarCallback(func); } -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["d-editor"], ready: false, lastSel: null, _mouseTrap: null, showLink: true, emojiPickerIsActive: false, - emojiStore: Ember.inject.service("emoji-store"), + emojiStore: service("emoji-store"), @computed("placeholder") placeholderTranslated(placeholder) { @@ -247,7 +255,7 @@ export default Ember.Component.extend({ this._applyEmojiAutocomplete($editorInput); this._applyCategoryHashtagAutocomplete($editorInput); - Ember.run.scheduleOnce("afterRender", this, this._readyNow); + scheduleOnce("afterRender", this, this._readyNow); const mouseTrap = Mousetrap(this.element.querySelector(".d-editor-input")); const shortcuts = this.get("toolbar.shortcuts"); @@ -346,7 +354,7 @@ export default Ember.Component.extend({ return; } this.set("preview", cooked); - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { if (this._state !== "inDOM") { return; } @@ -370,7 +378,7 @@ export default Ember.Component.extend({ if (Ember.testing) { this._updatePreview(); } else { - Ember.run.debounce(this, this._updatePreview, 30); + debounce(this, this._updatePreview, 30); } }, @@ -430,17 +438,14 @@ export default Ember.Component.extend({ emojiPickerIsActive: true }); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { const filterInput = document.querySelector( ".emoji-picker input[name='filter']" ); if (filterInput) { filterInput.value = v.term; - Ember.run.later( - () => filterInput.dispatchEvent(new Event("input")), - 50 - ); + later(() => filterInput.dispatchEvent(new Event("input")), 50); } }); @@ -449,7 +454,7 @@ export default Ember.Component.extend({ }, dataSource: term => { - return new Ember.RSVP.Promise(resolve => { + return new Promise(resolve => { const full = `:${term}`; term = term.toLowerCase(); @@ -545,7 +550,7 @@ export default Ember.Component.extend({ }, _selectText(from, length) { - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { const textarea = this.element.querySelector("textarea.d-editor-input"); const $textarea = $(textarea); const oldScrollPos = $textarea.scrollTop(); @@ -554,7 +559,7 @@ export default Ember.Component.extend({ } textarea.selectionStart = from; textarea.selectionEnd = from + length; - Ember.run.next(() => $textarea.trigger("change")); + next(() => $textarea.trigger("change")); $textarea.scrollTop(oldScrollPos); }); }, @@ -783,7 +788,7 @@ export default Ember.Component.extend({ $textarea.val(value); $textarea.prop("selectionStart", insert.length); $textarea.prop("selectionEnd", insert.length); - Ember.run.next(() => $textarea.trigger("change")); + next(() => $textarea.trigger("change")); this._focusTextArea(); }, @@ -884,7 +889,7 @@ export default Ember.Component.extend({ // ensures textarea scroll position is correct _focusTextArea() { const textarea = this.element.querySelector("textarea.d-editor-input"); - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { textarea.blur(); textarea.focus(); }); diff --git a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 index 8e8f01b0bc..a8543095ab 100644 --- a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Component.extend({ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; +export default Component.extend({ classNames: ["modal-body"], fixed: false, dismissable: true, @@ -13,7 +15,7 @@ export default Ember.Component.extend({ fixedParent.modal("show"); } - Ember.run.scheduleOnce("afterRender", this, this._afterFirstRender); + scheduleOnce("afterRender", this, this._afterFirstRender); this.appEvents.on("modal-body:flash", this, "_flash"); this.appEvents.on("modal-body:clearFlash", this, "_clearFlash"); }, diff --git a/app/assets/javascripts/discourse/components/d-modal-cancel.js.es6 b/app/assets/javascripts/discourse/components/d-modal-cancel.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/discourse/components/d-modal-cancel.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal-cancel.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/discourse/components/d-modal.js.es6 b/app/assets/javascripts/discourse/components/d-modal.js.es6 index 8c46fc48e1..19d4d2264c 100644 --- a/app/assets/javascripts/discourse/components/d-modal.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal.js.es6 @@ -1,6 +1,8 @@ +import { next } from "@ember/runloop"; import { on } from "ember-addons/ember-computed-decorators"; +import Component from "@ember/component"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [ ":modal", ":d-modal", @@ -31,11 +33,11 @@ export default Ember.Component.extend({ setUp() { $("html").on("keydown.discourse-modal", e => { if (e.which === 27 && this.dismissable) { - Ember.run.next(() => $(".modal-header a.close").click()); + next(() => $(".modal-header button.modal-close").click()); } if (e.which === 13 && this.triggerClickOnEnter(e)) { - Ember.run.next(() => $(".modal-footer .btn-primary").click()); + next(() => $(".modal-footer .btn-primary").click()); } }); @@ -72,7 +74,7 @@ export default Ember.Component.extend({ // 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(); + $(".modal-header button.modal-close").click(); } }, diff --git a/app/assets/javascripts/discourse/components/d-navigation.js.es6 b/app/assets/javascripts/discourse/components/d-navigation.js.es6 index 26870bcd02..b44ad95efd 100644 --- a/app/assets/javascripts/discourse/components/d-navigation.js.es6 +++ b/app/assets/javascripts/discourse/components/d-navigation.js.es6 @@ -1,7 +1,9 @@ +import { inject as service } from "@ember/service"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ - router: Ember.inject.service(), +export default Component.extend({ + router: service(), persistedQueryParams: null, tagName: "", diff --git a/app/assets/javascripts/discourse/components/d-section.js.es6 b/app/assets/javascripts/discourse/components/d-section.js.es6 index 1f1d07a676..ef1da4b0a0 100644 --- a/app/assets/javascripts/discourse/components/d-section.js.es6 +++ b/app/assets/javascripts/discourse/components/d-section.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { scrollTop } from "discourse/mixins/scroll-top"; // Can add a body class from within a component, also will scroll to the top automatically. -export default Ember.Component.extend({ +export default Component.extend({ tagName: "section", didInsertElement() { diff --git a/app/assets/javascripts/discourse/components/date-input.js.es6 b/app/assets/javascripts/discourse/components/date-input.js.es6 index d29962c02c..927be37881 100644 --- a/app/assets/javascripts/discourse/components/date-input.js.es6 +++ b/app/assets/javascripts/discourse/components/date-input.js.es6 @@ -1,3 +1,5 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; /* global Pikaday:true */ import loadScript from "discourse/lib/load-script"; import { @@ -5,7 +7,7 @@ import { on } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["d-date-input"], date: null, _picker: null, @@ -36,7 +38,7 @@ export default Ember.Component.extend({ _loadPikadayPicker(container) { loadScript("/javascripts/pikaday.js").then(() => { - Ember.run.next(() => { + next(() => { const default_opts = { field: this.element.querySelector(".date-picker"), container: container || this.element, diff --git a/app/assets/javascripts/discourse/components/date-picker.js.es6 b/app/assets/javascripts/discourse/components/date-picker.js.es6 index 2c7d073169..e9403326bb 100644 --- a/app/assets/javascripts/discourse/components/date-picker.js.es6 +++ b/app/assets/javascripts/discourse/components/date-picker.js.es6 @@ -1,3 +1,5 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; /* global Pikaday:true */ import loadScript from "discourse/lib/load-script"; import { @@ -7,7 +9,7 @@ import { const DATE_FORMAT = "YYYY-MM-DD"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["date-picker-wrapper"], _picker: null, value: null, @@ -29,7 +31,7 @@ export default Ember.Component.extend({ _loadPikadayPicker(container) { loadScript("/javascripts/pikaday.js").then(() => { - Ember.run.next(() => { + next(() => { const options = { field: this.element.querySelector(".date-picker"), container: container || null, diff --git a/app/assets/javascripts/discourse/components/date-time-input-range.js.es6 b/app/assets/javascripts/discourse/components/date-time-input-range.js.es6 index 3754be93cd..ec048ec730 100644 --- a/app/assets/javascripts/discourse/components/date-time-input-range.js.es6 +++ b/app/assets/javascripts/discourse/components/date-time-input-range.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Component.extend({ +import { equal } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ classNames: ["d-date-time-input-range"], from: null, @@ -10,8 +12,8 @@ export default Ember.Component.extend({ showToTime: true, error: null, - fromPanelActive: Ember.computed.equal("currentPanel", "from"), - toPanelActive: Ember.computed.equal("currentPanel", "to"), + fromPanelActive: equal("currentPanel", "from"), + toPanelActive: equal("currentPanel", "to"), _valid(state) { if (state.to < state.from) { diff --git a/app/assets/javascripts/discourse/components/date-time-input.js.es6 b/app/assets/javascripts/discourse/components/date-time-input.js.es6 index ce173e3d42..41b41a8d32 100644 --- a/app/assets/javascripts/discourse/components/date-time-input.js.es6 +++ b/app/assets/javascripts/discourse/components/date-time-input.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["d-date-time-input"], date: null, showTime: true, diff --git a/app/assets/javascripts/discourse/components/desktop-notification-config.js.es6 b/app/assets/javascripts/discourse/components/desktop-notification-config.js.es6 index 612d9d9f89..112723ba12 100644 --- a/app/assets/javascripts/discourse/components/desktop-notification-config.js.es6 +++ b/app/assets/javascripts/discourse/components/desktop-notification-config.js.es6 @@ -1,3 +1,5 @@ +import { or } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import KeyValueStore from "discourse/lib/key-value-store"; import { @@ -14,7 +16,7 @@ import { const keyValueStore = new KeyValueStore(context); -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["controls"], @computed("isNotSupported") @@ -78,7 +80,7 @@ export default Ember.Component.extend({ } }, - isEnabled: Ember.computed.or("isEnabledDesktop", "isEnabledPush"), + isEnabled: or("isEnabledDesktop", "isEnabledPush"), isPushNotificationsPreferred() { if (!this.site.mobileView) { diff --git a/app/assets/javascripts/discourse/components/directory-item.js.es6 b/app/assets/javascripts/discourse/components/directory-item.js.es6 index 79902869c8..05c085c2e9 100644 --- a/app/assets/javascripts/discourse/components/directory-item.js.es6 +++ b/app/assets/javascripts/discourse/components/directory-item.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { propertyEqual } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "tr", classNameBindings: ["me"], me: propertyEqual("item.user.id", "currentUser.id") diff --git a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 index 6765568078..d45e9ce9e7 100644 --- a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 +++ b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "th", classNames: ["sortable"], diff --git a/app/assets/javascripts/discourse/components/disabled-icon.js.es6 b/app/assets/javascripts/discourse/components/disabled-icon.js.es6 index e54647c155..433c5f4d72 100644 --- a/app/assets/javascripts/discourse/components/disabled-icon.js.es6 +++ b/app/assets/javascripts/discourse/components/disabled-icon.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "span", classNameBindings: [":fa-stack"] }); diff --git a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 index 6a84f538ca..6c8b18ea1e 100644 --- a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("user.dismissed_banner_key", "banner.key", "hide") visible(dismissedBannerKey, bannerKey, hide) { dismissedBannerKey = diff --git a/app/assets/javascripts/discourse/components/discourse-linked-text.js.es6 b/app/assets/javascripts/discourse/components/discourse-linked-text.js.es6 index 17398e4a21..fe4e7fd9c8 100644 --- a/app/assets/javascripts/discourse/components/discourse-linked-text.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-linked-text.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", @computed("text") diff --git a/app/assets/javascripts/discourse/components/discourse-tag-bound.js.es6 b/app/assets/javascripts/discourse/components/discourse-tag-bound.js.es6 index 9f151dc1fe..ea07e0d5fe 100644 --- a/app/assets/javascripts/discourse/components/discourse-tag-bound.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-tag-bound.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "a", classNameBindings: [":discourse-tag", "style", "tagClass"], attributeBindings: ["href"], diff --git a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 index 7e3011fb6e..c9484f6264 100644 --- a/app/assets/javascripts/discourse/components/discourse-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-topic.js.es6 @@ -1,3 +1,9 @@ +import { alias } from "@ember/object/computed"; +import { throttle } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import DiscourseURL from "discourse/lib/url"; import AddArchetypeClass from "discourse/mixins/add-archetype-class"; import ClickTrack from "discourse/lib/click-track"; @@ -14,12 +20,12 @@ function highlight(postNumber) { $contents.on("animationend", () => $contents.removeClass("highlighted")); } -export default Ember.Component.extend( +export default Component.extend( AddArchetypeClass, Scrolling, MobileScrollDirection, { - userFilters: Ember.computed.alias("topic.userFilters"), + userFilters: alias("topic.userFilters"), classNameBindings: [ "multiSelect", "topic.archetype", @@ -32,8 +38,8 @@ export default Ember.Component.extend( menuVisible: true, SHORT_POST: 1200, - postStream: Ember.computed.alias("topic.postStream"), - archetype: Ember.computed.alias("topic.archetype"), + postStream: alias("topic.postStream"), + archetype: alias("topic.archetype"), dockAt: 0, _lastShowTopic: null, @@ -49,13 +55,13 @@ export default Ember.Component.extend( const enteredAt = this.enteredAt; if (enteredAt && this.lastEnteredAt !== enteredAt) { this._lastShowTopic = null; - Ember.run.schedule("afterRender", () => this.scrolled()); + schedule("afterRender", () => this.scrolled()); this.set("lastEnteredAt", enteredAt); } }, _highlightPost(postNumber) { - Ember.run.scheduleOnce("afterRender", null, highlight, postNumber); + scheduleOnce("afterRender", null, highlight, postNumber); }, _hideTopicInHeader() { @@ -77,7 +83,7 @@ export default Ember.Component.extend( this.pauseHeaderTopicUpdate = true; this._lastShowTopic = true; - Ember.run.later(() => { + later(() => { this._lastShowTopic = false; this.pauseHeaderTopicUpdate = false; }, debounceDuration); @@ -191,7 +197,7 @@ export default Ember.Component.extend( // at the start of the scroll. This feels a lot more snappy compared to waiting // for the scroll to end if we debounce. if (this.site.mobileView && this.hasScrolled) { - Ember.run.throttle( + throttle( this, this.calculateDirection, offset, diff --git a/app/assets/javascripts/discourse/components/discovery-categories.js.es6 b/app/assets/javascripts/discourse/components/discovery-categories.js.es6 index 97bbc33009..d5c70bbf9a 100644 --- a/app/assets/javascripts/discourse/components/discovery-categories.js.es6 +++ b/app/assets/javascripts/discourse/components/discovery-categories.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import UrlRefresh from "discourse/mixins/url-refresh"; import { on } from "ember-addons/ember-computed-decorators"; const CATEGORIES_LIST_BODY_CLASS = "categories-list"; -export default Ember.Component.extend(UrlRefresh, { +export default Component.extend(UrlRefresh, { classNames: ["contents"], @on("didInsertElement") diff --git a/app/assets/javascripts/discourse/components/discovery-topics-list.js.es6 b/app/assets/javascripts/discourse/components/discovery-topics-list.js.es6 index 10a73fcd5e..6706cacd4a 100644 --- a/app/assets/javascripts/discourse/components/discovery-topics-list.js.es6 +++ b/app/assets/javascripts/discourse/components/discovery-topics-list.js.es6 @@ -1,60 +1,52 @@ +import { schedule } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { on, observes } from "ember-addons/ember-computed-decorators"; import LoadMore from "discourse/mixins/load-more"; import UrlRefresh from "discourse/mixins/url-refresh"; -const DiscoveryTopicsListComponent = Ember.Component.extend( - UrlRefresh, - LoadMore, - { - classNames: ["contents"], - eyelineSelector: ".topic-list-item", +const DiscoveryTopicsListComponent = Component.extend(UrlRefresh, LoadMore, { + classNames: ["contents"], + eyelineSelector: ".topic-list-item", - @on("didInsertElement") - @observes("model") - _readjustScrollPosition() { - const scrollTo = this.session.get("topicListScrollPosition"); - if (scrollTo && scrollTo >= 0) { - Ember.run.schedule("afterRender", () => - $(window).scrollTop(scrollTo + 1) - ); - } else { - Ember.run.scheduleOnce("afterRender", this, this.loadMoreUnlessFull); - } - }, + @on("didInsertElement") + @observes("model") + _readjustScrollPosition() { + const scrollTo = this.session.get("topicListScrollPosition"); + if (scrollTo && scrollTo >= 0) { + schedule("afterRender", () => $(window).scrollTop(scrollTo + 1)); + } else { + scheduleOnce("afterRender", this, this.loadMoreUnlessFull); + } + }, - @observes("topicTrackingState.states") - _updateTopics() { - this.topicTrackingState.updateTopics(this.model.topics); - }, + @observes("topicTrackingState.states") + _updateTopics() { + this.topicTrackingState.updateTopics(this.model.topics); + }, - @observes("incomingCount") - _updateTitle() { - Discourse.updateContextCount(this.incomingCount); - }, + @observes("incomingCount") + _updateTitle() { + Discourse.updateContextCount(this.incomingCount); + }, - saveScrollPosition() { - this.session.set("topicListScrollPosition", $(window).scrollTop()); - }, + saveScrollPosition() { + this.session.set("topicListScrollPosition", $(window).scrollTop()); + }, - scrolled() { - this._super(...arguments); - this.saveScrollPosition(); - }, - - actions: { - loadMore() { - Discourse.updateContextCount(0); - this.model.loadMore().then(hasMoreResults => { - Ember.run.schedule("afterRender", () => this.saveScrollPosition()); - if (!hasMoreResults) { - this.eyeline.flushRest(); - } else if ($(window).height() >= $(document).height()) { - this.send("loadMore"); - } - }); - } + actions: { + loadMore() { + Discourse.updateContextCount(0); + this.model.loadMore().then(hasMoreResults => { + schedule("afterRender", () => this.saveScrollPosition()); + if (!hasMoreResults) { + this.eyeline.flushRest(); + } else if ($(window).height() >= $(document).height()) { + this.send("loadMore"); + } + }); } } -); +}); export default DiscoveryTopicsListComponent; diff --git a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 b/app/assets/javascripts/discourse/components/edit-category-general.js.es6 index 9988120e59..e94e2a77d2 100644 --- a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-general.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import { not } from "@ember/object/computed"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; import { categoryBadgeHTML } from "discourse/helpers/category-link"; import Category from "discourse/models/category"; @@ -10,9 +12,7 @@ export default buildCategoryPanel("general", { this.foregroundColors = ["FFFFFF", "000000"]; }, - canSelectParentCategory: Ember.computed.not( - "category.isUncategorizedCategory" - ), + canSelectParentCategory: not("category.isUncategorizedCategory"), uncategorizedSiteSettingLink: Discourse.getURL( "/admin/site_settings/category/all_results?filter=allow_uncategorized_topics" ), @@ -85,7 +85,7 @@ export default buildCategoryPanel("general", { // We can change the parent if there are no children @computed("category.id") subCategories(categoryId) { - if (Ember.isEmpty(categoryId)) { + if (isEmpty(categoryId)) { return null; } return Category.list().filterBy("parent_category_id", categoryId); diff --git a/app/assets/javascripts/discourse/components/edit-category-images.js.es6 b/app/assets/javascripts/discourse/components/edit-category-images.js.es6 index f7b03702ec..2e12268885 100644 --- a/app/assets/javascripts/discourse/components/edit-category-images.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-images.js.es6 @@ -1,3 +1,4 @@ +import EmberObject from "@ember/object"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; import { default as computed } from "ember-addons/ember-computed-decorators"; @@ -33,7 +34,7 @@ export default buildCategoryPanel("images").extend({ _deleteUpload(path) { this.set( path, - Ember.Object.create({ + EmberObject.create({ id: null, url: null }) @@ -43,7 +44,7 @@ export default buildCategoryPanel("images").extend({ _setFromUpload(path, upload) { this.set( path, - Ember.Object.create({ + EmberObject.create({ url: upload.url, id: upload.id }) diff --git a/app/assets/javascripts/discourse/components/edit-category-panel.js.es6 b/app/assets/javascripts/discourse/components/edit-category-panel.js.es6 index 6a45839cf7..3161e31f35 100644 --- a/app/assets/javascripts/discourse/components/edit-category-panel.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-panel.js.es6 @@ -1,11 +1,13 @@ -const EditCategoryPanel = Ember.Component.extend({}); +import { equal } from "@ember/object/computed"; +import Component from "@ember/component"; +const EditCategoryPanel = Component.extend({}); export default EditCategoryPanel; export function buildCategoryPanel(tab, extras) { return EditCategoryPanel.extend( { - activeTab: Ember.computed.equal("selectedTab", tab), + activeTab: equal("selectedTab", tab), classNameBindings: [ ":modal-tab", "activeTab::hide", diff --git a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 index c32f8b0553..5d692cc6eb 100644 --- a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 @@ -1,3 +1,4 @@ +import { empty, and } from "@ember/object/computed"; import { setting } from "discourse/lib/computed"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; import computed from "ember-addons/ember-computed-decorators"; @@ -12,12 +13,12 @@ export function addCategorySortCriteria(criteria) { export default buildCategoryPanel("settings", { emailInEnabled: setting("email_in"), showPositionInput: setting("fixed_category_positions"), - isParentCategory: Ember.computed.empty("category.parent_category_id"), - showSubcategoryListStyle: Ember.computed.and( + isParentCategory: empty("category.parent_category_id"), + showSubcategoryListStyle: and( "category.show_subcategory_list", "isParentCategory" ), - isDefaultSortOrder: Ember.computed.empty("category.sort_order"), + isDefaultSortOrder: empty("category.sort_order"), @computed availableSubcategoryListStyles() { diff --git a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 index 5f2f6b4912..42be7233af 100644 --- a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 @@ -1,7 +1,9 @@ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { propertyEqual } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "li", classNameBindings: ["active", "tabClassName"], @@ -19,7 +21,7 @@ export default Ember.Component.extend({ didInsertElement() { this._super(...arguments); - Ember.run.scheduleOnce("afterRender", this, this._addToCollection); + scheduleOnce("afterRender", this, this._addToCollection); }, _addToCollection: function() { diff --git a/app/assets/javascripts/discourse/components/edit-category-tags.js.es6 b/app/assets/javascripts/discourse/components/edit-category-tags.js.es6 index 665975cf6b..aaca4b0e49 100644 --- a/app/assets/javascripts/discourse/components/edit-category-tags.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-tags.js.es6 @@ -1,10 +1,8 @@ +import { empty, and } from "@ember/object/computed"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; export default buildCategoryPanel("tags", { - allowedTagsEmpty: Ember.computed.empty("category.allowed_tags"), - allowedTagGroupsEmpty: Ember.computed.empty("category.allowed_tag_groups"), - disableAllowGlobalTags: Ember.computed.and( - "allowedTagsEmpty", - "allowedTagGroupsEmpty" - ) + allowedTagsEmpty: empty("category.allowed_tags"), + allowedTagGroupsEmpty: empty("category.allowed_tag_groups"), + disableAllowGlobalTags: and("allowedTagsEmpty", "allowedTagGroupsEmpty") }); diff --git a/app/assets/javascripts/discourse/components/edit-category-topic-template.js.es6 b/app/assets/javascripts/discourse/components/edit-category-topic-template.js.es6 index b1d5c79d81..c3254cc3d6 100644 --- a/app/assets/javascripts/discourse/components/edit-category-topic-template.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-topic-template.js.es6 @@ -1,9 +1,10 @@ +import { scheduleOnce } from "@ember/runloop"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; export default buildCategoryPanel("topic-template", { _activeTabChanged: function() { if (this.activeTab) { - Ember.run.scheduleOnce("afterRender", () => + scheduleOnce("afterRender", () => this.element.querySelector(".d-editor-input").focus() ); } diff --git a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6 b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6 index 1f65b8797d..5b774ca667 100644 --- a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { alias, equal, or } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes, @@ -13,23 +17,15 @@ import { BUMP_TYPE } from "discourse/controllers/edit-topic-timer"; -export default Ember.Component.extend({ - selection: Ember.computed.alias("topicTimer.status_type"), - autoOpen: Ember.computed.equal("selection", OPEN_STATUS_TYPE), - autoClose: Ember.computed.equal("selection", CLOSE_STATUS_TYPE), - autoDelete: Ember.computed.equal("selection", DELETE_STATUS_TYPE), - autoBump: Ember.computed.equal("selection", BUMP_TYPE), - publishToCategory: Ember.computed.equal( - "selection", - PUBLISH_TO_CATEGORY_STATUS_TYPE - ), - reminder: Ember.computed.equal("selection", REMINDER_TYPE), - showTimeOnly: Ember.computed.or( - "autoOpen", - "autoDelete", - "reminder", - "autoBump" - ), +export default Component.extend({ + selection: alias("topicTimer.status_type"), + autoOpen: equal("selection", OPEN_STATUS_TYPE), + autoClose: equal("selection", CLOSE_STATUS_TYPE), + autoDelete: equal("selection", DELETE_STATUS_TYPE), + autoBump: equal("selection", BUMP_TYPE), + publishToCategory: equal("selection", PUBLISH_TO_CATEGORY_STATUS_TYPE), + reminder: equal("selection", REMINDER_TYPE), + showTimeOnly: or("autoOpen", "autoDelete", "reminder", "autoBump"), @computed( "topicTimer.updateTime", @@ -39,7 +35,7 @@ export default Ember.Component.extend({ ) saveDisabled(updateTime, loading, publishToCategory, topicTimerCategoryId) { return ( - Ember.isEmpty(updateTime) || + isEmpty(updateTime) || loading || (publishToCategory && !topicTimerCategoryId) ); @@ -72,7 +68,7 @@ export default Ember.Component.extend({ @observes("selection") _updateBasedOnLastPost() { if (!this.autoClose) { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.set("topicTimer.based_on_last_post", false); }); } diff --git a/app/assets/javascripts/discourse/components/emoji-picker.js.es6 b/app/assets/javascripts/discourse/components/emoji-picker.js.es6 index dfe6287c67..52f9e8add4 100644 --- a/app/assets/javascripts/discourse/components/emoji-picker.js.es6 +++ b/app/assets/javascripts/discourse/components/emoji-picker.js.es6 @@ -1,3 +1,5 @@ +import { inject as service } from "@ember/service"; +import Component from "@ember/component"; import { on, observes } from "ember-addons/ember-computed-decorators"; import { findRawTemplate } from "discourse/lib/raw-templates"; import { emojiUrlFor } from "discourse/lib/text"; @@ -15,9 +17,9 @@ const customEmojis = _.keys(extendedEmojiList()).map(code => { return { code, src: emojiUrlFor(code) }; }); -export default Ember.Component.extend({ +export default Component.extend({ automaticPositioning: true, - emojiStore: Ember.inject.service("emoji-store"), + emojiStore: service("emoji-store"), close() { this._unbindEvents(); diff --git a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 index f3273d8322..37dfd5ea10 100644 --- a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 @@ -1,11 +1,13 @@ +import { notEmpty, not } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "emoji", uploadUrl: "/admin/customize/emojis", - hasName: Ember.computed.notEmpty("name"), - addDisabled: Ember.computed.not("hasName"), + hasName: notEmpty("name"), + addDisabled: not("hasName"), uploadOptions() { return { diff --git a/app/assets/javascripts/discourse/components/expand-post.js.es6 b/app/assets/javascripts/discourse/components/expand-post.js.es6 index 4bd2b8d4a5..1302e76795 100644 --- a/app/assets/javascripts/discourse/components/expand-post.js.es6 +++ b/app/assets/javascripts/discourse/components/expand-post.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", expanded: null, _loading: false, diff --git a/app/assets/javascripts/discourse/components/expanding-text-area.js.es6 b/app/assets/javascripts/discourse/components/expanding-text-area.js.es6 index 064764713f..d2b980a8f2 100644 --- a/app/assets/javascripts/discourse/components/expanding-text-area.js.es6 +++ b/app/assets/javascripts/discourse/components/expanding-text-area.js.es6 @@ -1,10 +1,11 @@ +import { scheduleOnce } from "@ember/runloop"; import { on, observes } from "ember-addons/ember-computed-decorators"; import autosize from "discourse/lib/autosize"; export default Ember.TextArea.extend({ @on("didInsertElement") _startWatching() { - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { $(this.element).focus(); autosize(this.element); }); @@ -12,6 +13,7 @@ export default Ember.TextArea.extend({ @observes("value") _updateAutosize() { + this.element.value = this.value; const evt = document.createEvent("Event"); evt.initEvent("autosize:update", true, false); this.element.dispatchEvent(evt); diff --git a/app/assets/javascripts/discourse/components/featured-topic.js.es6 b/app/assets/javascripts/discourse/components/featured-topic.js.es6 index eb0bde08ad..a975b893e9 100644 --- a/app/assets/javascripts/discourse/components/featured-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/featured-topic.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNameBindings: [":featured-topic"], click(e) { diff --git a/app/assets/javascripts/discourse/components/flag-action-type.js.es6 b/app/assets/javascripts/discourse/components/flag-action-type.js.es6 index 6a7a713d4e..c42818914d 100644 --- a/app/assets/javascripts/discourse/components/flag-action-type.js.es6 +++ b/app/assets/javascripts/discourse/components/flag-action-type.js.es6 @@ -1,7 +1,9 @@ +import { and, not, equal } from "@ember/object/computed"; +import Component from "@ember/component"; import { MAX_MESSAGE_LENGTH } from "discourse/models/post-action-type"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["flag-action-type"], @computed("flag.name_key") @@ -23,9 +25,9 @@ export default Ember.Component.extend({ return flag === selectedFlag; }, - showMessageInput: Ember.computed.and("flag.is_custom_flag", "selected"), - showDescription: Ember.computed.not("showMessageInput"), - isNotifyUser: Ember.computed.equal("flag.name_key", "notify_user"), + showMessageInput: and("flag.is_custom_flag", "selected"), + showDescription: not("showMessageInput"), + isNotifyUser: equal("flag.name_key", "notify_user"), @computed("flag.description", "flag.short_description") description(long_description, short_description) { diff --git a/app/assets/javascripts/discourse/components/flag-selection.js.es6 b/app/assets/javascripts/discourse/components/flag-selection.js.es6 index 8499713ce2..b52f544907 100644 --- a/app/assets/javascripts/discourse/components/flag-selection.js.es6 +++ b/app/assets/javascripts/discourse/components/flag-selection.js.es6 @@ -1,7 +1,9 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import { observes } from "ember-addons/ember-computed-decorators"; // Mostly hacks because `flag.hbs` didn't use `radio-button` -export default Ember.Component.extend({ +export default Component.extend({ _selectRadio() { this.element.querySelector("input[type='radio']").checked = false; @@ -15,6 +17,6 @@ export default Ember.Component.extend({ @observes("nameKey") selectedChanged() { - Ember.run.next(this, this._selectRadio); + next(this, this._selectRadio); } }); diff --git a/app/assets/javascripts/discourse/components/flat-button.js.es6 b/app/assets/javascripts/discourse/components/flat-button.js.es6 index bcac9cc01f..1348836907 100644 --- a/app/assets/javascripts/discourse/components/flat-button.js.es6 +++ b/app/assets/javascripts/discourse/components/flat-button.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "button", classNames: ["btn-flat"], attributeBindings: ["disabled", "translatedTitle:title"], diff --git a/app/assets/javascripts/discourse/components/footer-message.js.es6 b/app/assets/javascripts/discourse/components/footer-message.js.es6 index 22263eca31..e829a884c5 100644 --- a/app/assets/javascripts/discourse/components/footer-message.js.es6 +++ b/app/assets/javascripts/discourse/components/footer-message.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["footer-message"] }); diff --git a/app/assets/javascripts/discourse/components/footer-nav.js.es6 b/app/assets/javascripts/discourse/components/footer-nav.js.es6 index 7ac143225a..d94910364e 100644 --- a/app/assets/javascripts/discourse/components/footer-nav.js.es6 +++ b/app/assets/javascripts/discourse/components/footer-nav.js.es6 @@ -1,3 +1,4 @@ +import { throttle } from "@ember/runloop"; import MountWidget from "discourse/components/mount-widget"; import MobileScrollDirection from "discourse/mixins/mobile-scroll-direction"; import Scrolling from "discourse/mixins/scrolling"; @@ -78,7 +79,7 @@ const FooterNavComponent = MountWidget.extend( const offset = window.pageYOffset || $("html").scrollTop(); - Ember.run.throttle( + throttle( this, this.calculateDirection, offset, diff --git a/app/assets/javascripts/discourse/components/future-date-input.js.es6 b/app/assets/javascripts/discourse/components/future-date-input.js.es6 index 9386c1b3f7..8746cfb0ef 100644 --- a/app/assets/javascripts/discourse/components/future-date-input.js.es6 +++ b/app/assets/javascripts/discourse/components/future-date-input.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { equal, and, empty } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed, observes @@ -5,17 +8,14 @@ import { import { FORMAT } from "select-kit/components/future-date-input-selector"; import { PUBLISH_TO_CATEGORY_STATUS_TYPE } from "discourse/controllers/edit-topic-timer"; -export default Ember.Component.extend({ +export default Component.extend({ selection: null, date: null, time: null, includeDateTime: true, - isCustom: Ember.computed.equal("selection", "pick_date_and_time"), - isBasedOnLastPost: Ember.computed.equal( - "selection", - "set_based_on_last_post" - ), - displayDateAndTimePicker: Ember.computed.and("includeDateTime", "isCustom"), + isCustom: equal("selection", "pick_date_and_time"), + isBasedOnLastPost: equal("selection", "set_based_on_last_post"), + displayDateAndTimePicker: and("includeDateTime", "isCustom"), displayLabel: null, init() { @@ -36,7 +36,7 @@ export default Ember.Component.extend({ } }, - timeInputDisabled: Ember.computed.empty("date"), + timeInputDisabled: empty("date"), @observes("date", "time") _updateInput() { @@ -107,10 +107,7 @@ export default Ember.Component.extend({ ) { if (!statusType || willCloseImmediately) return false; - if ( - statusType === PUBLISH_TO_CATEGORY_STATUS_TYPE && - Ember.isEmpty(categoryId) - ) { + if (statusType === PUBLISH_TO_CATEGORY_STATUS_TYPE && isEmpty(categoryId)) { return false; } diff --git a/app/assets/javascripts/discourse/components/generated-invite-link.js.es6 b/app/assets/javascripts/discourse/components/generated-invite-link.js.es6 index 74426a45b6..8b475cbbdb 100644 --- a/app/assets/javascripts/discourse/components/generated-invite-link.js.es6 +++ b/app/assets/javascripts/discourse/components/generated-invite-link.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ didInsertElement() { this._super(...arguments); $(this.element.querySelector("input")) diff --git a/app/assets/javascripts/discourse/components/global-notice.js.es6 b/app/assets/javascripts/discourse/components/global-notice.js.es6 index 3d8c46679b..e16243f207 100644 --- a/app/assets/javascripts/discourse/components/global-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/global-notice.js.es6 @@ -1,9 +1,11 @@ +import { bind } from "@ember/runloop"; +import Component from "@ember/component"; import { on } from "ember-addons/ember-computed-decorators"; import { iconHTML } from "discourse-common/lib/icon-library"; import LogsNotice from "discourse/services/logs-notice"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ rerenderTriggers: ["site.isReadOnly", "siteSettings.disable_emails"], @@ -65,7 +67,7 @@ export default Ember.Component.extend( notices.push([ LogsNotice.currentProp("message"), "alert-logs-notice", - `
${iconHTML("times")}
` + `` ]); } @@ -87,13 +89,10 @@ export default Ember.Component.extend( @on("didInsertElement") _setupLogsNotice() { - this._boundRerenderBuffer = Ember.run.bind(this, this.rerenderBuffer); + this._boundRerenderBuffer = bind(this, this.rerenderBuffer); LogsNotice.current().addObserver("hidden", this._boundRerenderBuffer); - this._boundResetCurrentProp = Ember.run.bind( - this, - this._resetCurrentProp - ); + this._boundResetCurrentProp = bind(this, this._resetCurrentProp); $(this.element).on( "click.global-notice", ".alert-logs-notice .close", diff --git a/app/assets/javascripts/discourse/components/google-search.js.es6 b/app/assets/javascripts/discourse/components/google-search.js.es6 index e99e862f8e..246e7ab2a3 100644 --- a/app/assets/javascripts/discourse/components/google-search.js.es6 +++ b/app/assets/javascripts/discourse/components/google-search.js.es6 @@ -1,10 +1,12 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["google-search-form"], classNameBindings: ["hidden:hidden"], - hidden: Ember.computed.alias("siteSettings.login_required"), + hidden: alias("siteSettings.login_required"), @computed siteUrl() { diff --git a/app/assets/javascripts/discourse/components/group-activity-filter.js.es6 b/app/assets/javascripts/discourse/components/group-activity-filter.js.es6 index 145b770e51..790c675e49 100644 --- a/app/assets/javascripts/discourse/components/group-activity-filter.js.es6 +++ b/app/assets/javascripts/discourse/components/group-activity-filter.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "li" }); diff --git a/app/assets/javascripts/discourse/components/group-card-contents.js.es6 b/app/assets/javascripts/discourse/components/group-card-contents.js.es6 index 2c3df56b1f..bd6d029e49 100644 --- a/app/assets/javascripts/discourse/components/group-card-contents.js.es6 +++ b/app/assets/javascripts/discourse/components/group-card-contents.js.es6 @@ -1,3 +1,5 @@ +import { alias, match, gt, or } from "@ember/object/computed"; +import Component from "@ember/component"; import { setting } from "discourse/lib/computed"; import { default as computed } from "ember-addons/ember-computed-decorators"; import CardContentsBase from "discourse/mixins/card-contents-base"; @@ -6,7 +8,7 @@ import { groupPath } from "discourse/lib/url"; const maxMembersToDisplay = 10; -export default Ember.Component.extend(CardContentsBase, CleansUp, { +export default Component.extend(CardContentsBase, CleansUp, { elementId: "group-card", triggeringLinkClass: "mention-group", classNames: ["no-bg"], @@ -20,11 +22,11 @@ export default Ember.Component.extend(CardContentsBase, CleansUp, { allowBackgrounds: setting("allow_profile_backgrounds"), showBadges: setting("enable_badges"), - postStream: Ember.computed.alias("topic.postStream"), - viewingTopic: Ember.computed.match("currentPath", /^topic\./), + postStream: alias("topic.postStream"), + viewingTopic: match("currentPath", /^topic\./), - showMoreMembers: Ember.computed.gt("moreMembersCount", 0), - hasMembersOrIsMember: Ember.computed.or( + showMoreMembers: gt("moreMembersCount", 0), + hasMembersOrIsMember: or( "group.members", "group.is_group_owner_display", "group.is_group_user" diff --git a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 index f16d48827e..7b2b7110a0 100644 --- a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 +++ b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 @@ -1,10 +1,13 @@ +import { debounce } from "@ember/runloop"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { observes } from "ember-addons/ember-computed-decorators"; import { escapeExpression } from "discourse/lib/utilities"; import { convertIconClass } from "discourse-common/lib/icon-library"; import { ajax } from "discourse/lib/ajax"; +import { htmlSafe } from "@ember/template"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["group-flair-inputs"], @computed @@ -24,7 +27,7 @@ export default Ember.Component.extend({ @observes("model.flair_url") _loadSVGIcon() { - Ember.run.debounce(this, this._loadIcon, 1000); + debounce(this, this._loadIcon, 1000); }, _loadIcon() { @@ -75,7 +78,7 @@ export default Ember.Component.extend({ if (flairHexColor) style += `color: #${flairHexColor};`; - return Ember.String.htmlSafe(style); + return htmlSafe(style); }, @computed("model.flairBackgroundHexColor") diff --git a/app/assets/javascripts/discourse/components/group-index-toggle.js.es6 b/app/assets/javascripts/discourse/components/group-index-toggle.js.es6 index 8a35118a89..247b7e1829 100644 --- a/app/assets/javascripts/discourse/components/group-index-toggle.js.es6 +++ b/app/assets/javascripts/discourse/components/group-index-toggle.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "th", classNames: ["sortable"], diff --git a/app/assets/javascripts/discourse/components/group-manage-logs-filter.js.es6 b/app/assets/javascripts/discourse/components/group-manage-logs-filter.js.es6 index 0944c3ddf1..a6712bf498 100644 --- a/app/assets/javascripts/discourse/components/group-manage-logs-filter.js.es6 +++ b/app/assets/javascripts/discourse/components/group-manage-logs-filter.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("type") diff --git a/app/assets/javascripts/discourse/components/group-manage-logs-row.js.es6 b/app/assets/javascripts/discourse/components/group-manage-logs-row.js.es6 index b7765f9620..acba43f2b7 100644 --- a/app/assets/javascripts/discourse/components/group-manage-logs-row.js.es6 +++ b/app/assets/javascripts/discourse/components/group-manage-logs-row.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "", expandDetails: false, diff --git a/app/assets/javascripts/discourse/components/group-manage-save-button.js.es6 b/app/assets/javascripts/discourse/components/group-manage-save-button.js.es6 index 1487151fde..726bfede36 100644 --- a/app/assets/javascripts/discourse/components/group-manage-save-button.js.es6 +++ b/app/assets/javascripts/discourse/components/group-manage-save-button.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ saving: null, @computed("saving") diff --git a/app/assets/javascripts/discourse/components/group-member.js.es6 b/app/assets/javascripts/discourse/components/group-member.js.es6 index be68373fa7..1c511cab15 100644 --- a/app/assets/javascripts/discourse/components/group-member.js.es6 +++ b/app/assets/javascripts/discourse/components/group-member.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["item"], actions: { diff --git a/app/assets/javascripts/discourse/components/group-members-input.js.es6 b/app/assets/javascripts/discourse/components/group-members-input.js.es6 index 8ef63b5a50..e1f701f96c 100644 --- a/app/assets/javascripts/discourse/components/group-members-input.js.es6 +++ b/app/assets/javascripts/discourse/components/group-members-input.js.es6 @@ -1,8 +1,11 @@ +import { isEmpty } from "@ember/utils"; +import { lte } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { propertyEqual } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["group-members-input"], addButton: true, @@ -28,7 +31,7 @@ export default Ember.Component.extend({ return !usernames || !(usernames.length > 0); }, - showingFirst: Ember.computed.lte("currentPage", 1), + showingFirst: lte("currentPage", 1), showingLast: propertyEqual("currentPage", "totalPages"), actions: { @@ -60,7 +63,7 @@ export default Ember.Component.extend({ }, addMembers() { - if (Ember.isEmpty(this.get("model.usernames"))) { + if (isEmpty(this.get("model.usernames"))) { return; } this.model.addMembers(this.get("model.usernames")).catch(popupAjaxError); diff --git a/app/assets/javascripts/discourse/components/group-membership-button.js.es6 b/app/assets/javascripts/discourse/components/group-membership-button.js.es6 index 31ac171734..6b58c5370d 100644 --- a/app/assets/javascripts/discourse/components/group-membership-button.js.es6 +++ b/app/assets/javascripts/discourse/components/group-membership-button.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; import showModal from "discourse/lib/show-modal"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["group-membership-button"], @computed("model.public_admission", "userIsGroupUser") diff --git a/app/assets/javascripts/discourse/components/group-navigation.js.es6 b/app/assets/javascripts/discourse/components/group-navigation.js.es6 index 91ad923ffc..89720fbbe8 100644 --- a/app/assets/javascripts/discourse/components/group-navigation.js.es6 +++ b/app/assets/javascripts/discourse/components/group-navigation.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "" }); diff --git a/app/assets/javascripts/discourse/components/group-post.js.es6 b/app/assets/javascripts/discourse/components/group-post.js.es6 index f94f36dc8d..5a3a096f49 100644 --- a/app/assets/javascripts/discourse/components/group-post.js.es6 +++ b/app/assets/javascripts/discourse/components/group-post.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("post.url") postUrl: Discourse.getURL }); diff --git a/app/assets/javascripts/discourse/components/group-selector.js.es6 b/app/assets/javascripts/discourse/components/group-selector.js.es6 index c70c51fbc7..4d4b431888 100644 --- a/app/assets/javascripts/discourse/components/group-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/group-selector.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; import { on, observes, @@ -5,7 +7,7 @@ import { } from "ember-addons/ember-computed-decorators"; import { findRawTemplate } from "discourse/lib/raw-templates"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("placeholderKey") placeholder(placeholderKey) { return placeholderKey ? I18n.t(placeholderKey) : ""; @@ -26,7 +28,7 @@ export default Ember.Component.extend({ allowAny: false, items: _.isArray(groupNames) ? groupNames - : Ember.isEmpty(groupNames) + : isEmpty(groupNames) ? [] : [groupNames], single: this.single, diff --git a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 index f4756978a6..e4d1e6bb79 100644 --- a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 index 7a9849463a..1115786b08 100644 --- a/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/groups-form-profile-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-profile-fields.js.es6 index 15c2efbd96..98eabcea3f 100644 --- a/app/assets/javascripts/discourse/components/groups-form-profile-fields.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-form-profile-fields.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { not } from "@ember/object/computed"; +import Component from "@ember/component"; import { default as computed, observes @@ -6,7 +9,7 @@ import Group from "discourse/models/group"; import InputValidation from "discourse/models/input-validation"; import debounce from "discourse/lib/debounce"; -export default Ember.Component.extend({ +export default Component.extend({ disableSave: null, nameInput: null, @@ -21,7 +24,7 @@ export default Ember.Component.extend({ } }, - canEdit: Ember.computed.not("model.automatic"), + canEdit: not("model.automatic"), @computed("basicNameValidation", "uniqueNameValidation") nameValidation(basicNameValidation, uniqueNameValidation) { @@ -63,7 +66,7 @@ export default Ember.Component.extend({ checkGroupName: debounce(function() { name = this.nameInput; - if (Ember.isEmpty(name)) return; + if (isEmpty(name)) return; Group.checkName(name).then(response => { const validationName = "uniqueNameValidation"; diff --git a/app/assets/javascripts/discourse/components/groups-info.js.es6 b/app/assets/javascripts/discourse/components/groups-info.js.es6 index a95c9da337..cf439ef7d0 100644 --- a/app/assets/javascripts/discourse/components/groups-info.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-info.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", classNames: ["group-info-details"], diff --git a/app/assets/javascripts/discourse/components/hide-modal-trigger.js.es6 b/app/assets/javascripts/discourse/components/hide-modal-trigger.js.es6 index e3951d5277..df632e2557 100644 --- a/app/assets/javascripts/discourse/components/hide-modal-trigger.js.es6 +++ b/app/assets/javascripts/discourse/components/hide-modal-trigger.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ didInsertElement() { this._super(...arguments); $(".d-modal.fixed-modal") diff --git a/app/assets/javascripts/discourse/components/highlight-text.js.es6 b/app/assets/javascripts/discourse/components/highlight-text.js.es6 index 6e8be431dc..a98ffdb653 100644 --- a/app/assets/javascripts/discourse/components/highlight-text.js.es6 +++ b/app/assets/javascripts/discourse/components/highlight-text.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import highlightText from "discourse/lib/highlight-text"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", _highlightOnInsert: function() { diff --git a/app/assets/javascripts/discourse/components/honeypot-input.js.es6 b/app/assets/javascripts/discourse/components/honeypot-input.js.es6 new file mode 100644 index 0000000000..06895b0586 --- /dev/null +++ b/app/assets/javascripts/discourse/components/honeypot-input.js.es6 @@ -0,0 +1,16 @@ +import { on } from "ember-addons/ember-computed-decorators"; + +export default Ember.TextField.extend({ + @on("init") + _init() { + // Chrome autocomplete is buggy per: + // https://bugs.chromium.org/p/chromium/issues/detail?id=987293 + // work around issue while leaving a semi useable honeypot for + // bots that are running full Chrome + if (navigator.userAgent.indexOf("Chrome") > -1) { + this.set("type", "text"); + } else { + this.set("type", "password"); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/ignored-user-list-item.js.es6 b/app/assets/javascripts/discourse/components/ignored-user-list-item.js.es6 index 5bf27c13a1..6f26b5700b 100644 --- a/app/assets/javascripts/discourse/components/ignored-user-list-item.js.es6 +++ b/app/assets/javascripts/discourse/components/ignored-user-list-item.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "div", items: null, actions: { diff --git a/app/assets/javascripts/discourse/components/ignored-user-list.js.es6 b/app/assets/javascripts/discourse/components/ignored-user-list.js.es6 index ac81cc505d..f73ac290e4 100644 --- a/app/assets/javascripts/discourse/components/ignored-user-list.js.es6 +++ b/app/assets/javascripts/discourse/components/ignored-user-list.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import { popupAjaxError } from "discourse/lib/ajax-error"; import showModal from "discourse/lib/show-modal"; import User from "discourse/models/user"; -export default Ember.Component.extend({ +export default Component.extend({ item: null, actions: { removeIgnoredUser(item) { diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6 index df9ce3e2b2..514a985223 100644 --- a/app/assets/javascripts/discourse/components/image-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6 @@ -1,10 +1,13 @@ +import { isEmpty } from "@ember/utils"; +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; import lightbox from "discourse/lib/lightbox"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { classNames: ["image-uploader"], loadingLightbox: false, @@ -28,7 +31,7 @@ export default Ember.Component.extend(UploadMixin, { @computed("placeholderUrl") placeholderStyle(url) { - if (Ember.isEmpty(url)) { + if (isEmpty(url)) { return "".htmlSafe(); } return `background-image: url(${url})`.htmlSafe(); @@ -36,7 +39,7 @@ export default Ember.Component.extend(UploadMixin, { @computed("imageUrl") imageCDNURL(url) { - if (Ember.isEmpty(url)) { + if (isEmpty(url)) { return "".htmlSafe(); } @@ -50,7 +53,7 @@ export default Ember.Component.extend(UploadMixin, { @computed("imageUrl") imageBaseName(imageUrl) { - if (Ember.isEmpty(imageUrl)) return; + if (isEmpty(imageUrl)) return; return imageUrl.split("/").slice(-1)[0]; }, @@ -76,13 +79,13 @@ export default Ember.Component.extend(UploadMixin, { }, _openLightbox() { - Ember.run.next(() => + next(() => $(this.element.querySelector("a.lightbox")).magnificPopup("open") ); }, _applyLightbox() { - if (this.imageUrl) Ember.run.next(() => lightbox($(this.element))); + if (this.imageUrl) next(() => lightbox($(this.element))); }, actions: { diff --git a/app/assets/javascripts/discourse/components/images-uploader.js.es6 b/app/assets/javascripts/discourse/components/images-uploader.js.es6 index 23b8fbe688..d3a9d6c3b7 100644 --- a/app/assets/javascripts/discourse/components/images-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/images-uploader.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; -export default Ember.Component.extend(UploadMixin, { +export default Component.extend(UploadMixin, { type: "avatar", tagName: "span", diff --git a/app/assets/javascripts/discourse/components/input-tip.js.es6 b/app/assets/javascripts/discourse/components/input-tip.js.es6 index aceafa7458..28e73eb0a2 100644 --- a/app/assets/javascripts/discourse/components/input-tip.js.es6 +++ b/app/assets/javascripts/discourse/components/input-tip.js.es6 @@ -1,13 +1,15 @@ +import { alias, not } from "@ember/object/computed"; +import Component from "@ember/component"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { iconHTML } from "discourse-common/lib/icon-library"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNameBindings: [":tip", "good", "bad"], rerenderTriggers: ["validation"], - bad: Ember.computed.alias("validation.failed"), - good: Ember.computed.not("bad"), + bad: alias("validation.failed"), + good: not("bad"), buildBuffer(buffer) { const reason = this.get("validation.reason"); diff --git a/app/assets/javascripts/discourse/components/invite-panel.js.es6 b/app/assets/javascripts/discourse/components/invite-panel.js.es6 index 432a0b7325..b1743d4f99 100644 --- a/app/assets/javascripts/discourse/components/invite-panel.js.es6 +++ b/app/assets/javascripts/discourse/components/invite-panel.js.es6 @@ -1,14 +1,18 @@ +import { isEmpty } from "@ember/utils"; +import { alias, and, equal } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import Component from "@ember/component"; import { emailValid } from "discourse/lib/utilities"; import computed from "ember-addons/ember-computed-decorators"; import Group from "discourse/models/group"; import Invite from "discourse/models/invite"; import { i18n } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: null, - inviteModel: Ember.computed.alias("panel.model.inviteModel"), - userInvitedShow: Ember.computed.alias("panel.model.userInvitedShow"), + inviteModel: alias("panel.model.inviteModel"), + userInvitedShow: alias("panel.model.userInvitedShow"), // If this isn't defined, it will proxy to the user topic on the preferences // page which is wrong. @@ -18,7 +22,7 @@ export default Ember.Component.extend({ inviteIcon: "envelope", invitingExistingUserToTopic: false, - isAdmin: Ember.computed.alias("currentUser.admin"), + isAdmin: alias("currentUser.admin"), willDestroyElement() { this._super(...arguments); @@ -45,7 +49,7 @@ export default Ember.Component.extend({ can_invite_to ) { if (saving) return true; - if (Ember.isEmpty(emailOrUsername)) return true; + if (isEmpty(emailOrUsername)) return true; const emailTrimmed = emailOrUsername.trim(); @@ -60,11 +64,7 @@ export default Ember.Component.extend({ } // when inviting to private topic via email, group name must be specified - if ( - isPrivateTopic && - Ember.isEmpty(groupNames) && - emailValid(emailTrimmed) - ) { + if (isPrivateTopic && isEmpty(groupNames) && emailValid(emailTrimmed)) { return true; } @@ -91,7 +91,7 @@ export default Ember.Component.extend({ ) { if (hasCustomMessage) return true; if (saving) return true; - if (Ember.isEmpty(emailOrUsername)) return true; + if (isEmpty(emailOrUsername)) return true; const email = emailOrUsername.trim(); @@ -106,7 +106,7 @@ export default Ember.Component.extend({ } // when inviting to private topic via email, group name must be specified - if (isPrivateTopic && Ember.isEmpty(groupNames) && emailValid(email)) { + if (isPrivateTopic && isEmpty(groupNames) && emailValid(email)) { return true; } @@ -135,18 +135,18 @@ export default Ember.Component.extend({ return canInviteViaEmail && !isPM; }, - topicId: Ember.computed.alias("inviteModel.id"), + topicId: alias("inviteModel.id"), // eg: visible only to specific group members - isPrivateTopic: Ember.computed.and( + isPrivateTopic: and( "invitingToTopic", "inviteModel.category.read_restricted" ), - isPM: Ember.computed.equal("inviteModel.archetype", "private_message"), + isPM: equal("inviteModel.archetype", "private_message"), // scope to allowed usernames - allowExistingMembers: Ember.computed.alias("invitingToTopic"), + allowExistingMembers: alias("invitingToTopic"), @computed("isAdmin", "inviteModel.group_users") isGroupOwnerOrAdmin(isAdmin, groupUsers) { @@ -215,7 +215,7 @@ export default Ember.Component.extend({ return I18n.t("topic.invite_reply.to_username"); } else { // when inviting to a topic, display instructions based on provided entity - if (Ember.isEmpty(emailOrUsername)) { + if (isEmpty(emailOrUsername)) { return I18n.t("topic.invite_reply.to_topic_blank"); } else if (emailValid(emailOrUsername)) { this.set("inviteIcon", "envelope"); @@ -323,7 +323,7 @@ export default Ember.Component.extend({ .then(data => { model.setProperties({ saving: false, finished: true }); this.get("inviteModel.details.allowed_groups").pushObject( - Ember.Object.create(data.group) + EmberObject.create(data.group) ); this.appEvents.trigger("post-stream:refresh"); }) @@ -349,7 +349,7 @@ export default Ember.Component.extend({ }); } else if (this.isPM && result && result.user) { this.get("inviteModel.details.allowed_users").pushObject( - Ember.Object.create(result.user) + EmberObject.create(result.user) ); this.appEvents.trigger("post-stream:refresh"); } else if ( diff --git a/app/assets/javascripts/discourse/components/latest-topic-list-item.js.es6 b/app/assets/javascripts/discourse/components/latest-topic-list-item.js.es6 index 487ae8aa46..f0e3ee875c 100644 --- a/app/assets/javascripts/discourse/components/latest-topic-list-item.js.es6 +++ b/app/assets/javascripts/discourse/components/latest-topic-list-item.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import { showEntrance, navigateToTopic } from "discourse/components/topic-list-item"; -export default Ember.Component.extend({ +export default Component.extend({ attributeBindings: ["topic.id:data-topic-id"], classNameBindings: [ ":latest-topic-list-item", diff --git a/app/assets/javascripts/discourse/components/link-to-input.js.es6 b/app/assets/javascripts/discourse/components/link-to-input.js.es6 index 0afdbd304b..19015ec0e8 100644 --- a/app/assets/javascripts/discourse/components/link-to-input.js.es6 +++ b/app/assets/javascripts/discourse/components/link-to-input.js.es6 @@ -1,10 +1,12 @@ -export default Ember.Component.extend({ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; +export default Component.extend({ showInput: false, click() { this.onClick(); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $(this.element) .find("input") .focus(); diff --git a/app/assets/javascripts/discourse/components/links-redirect.js.es6 b/app/assets/javascripts/discourse/components/links-redirect.js.es6 index 84d5f890f0..0ddd92b21b 100644 --- a/app/assets/javascripts/discourse/components/links-redirect.js.es6 +++ b/app/assets/javascripts/discourse/components/links-redirect.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import ClickTrack from "discourse/lib/click-track"; -export default Ember.Component.extend({ +export default Component.extend({ didInsertElement() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/load-more.js.es6 b/app/assets/javascripts/discourse/components/load-more.js.es6 index f81b33b764..8668fa5742 100644 --- a/app/assets/javascripts/discourse/components/load-more.js.es6 +++ b/app/assets/javascripts/discourse/components/load-more.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import LoadMore from "discourse/mixins/load-more"; -export default Ember.Component.extend(LoadMore, { +export default Component.extend(LoadMore, { init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/login-buttons.js.es6 b/app/assets/javascripts/discourse/components/login-buttons.js.es6 index 3279bda5cc..a5a0967411 100644 --- a/app/assets/javascripts/discourse/components/login-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/login-buttons.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { findAll } from "discourse/models/login-method"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "login-buttons", classNameBindings: ["hidden"], diff --git a/app/assets/javascripts/discourse/components/login-modal.js.es6 b/app/assets/javascripts/discourse/components/login-modal.js.es6 index 59939542cb..2ee72f8722 100644 --- a/app/assets/javascripts/discourse/components/login-modal.js.es6 +++ b/app/assets/javascripts/discourse/components/login-modal.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Component.extend({ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; +export default Component.extend({ didInsertElement() { this._super(...arguments); @@ -13,7 +15,7 @@ export default Ember.Component.extend({ this.set("loginName", $.cookie("email")); } - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $( "#login-account-password, #login-account-name, #login-second-factor" ).keydown(e => { diff --git a/app/assets/javascripts/discourse/components/mobile-category-topic.js.es6 b/app/assets/javascripts/discourse/components/mobile-category-topic.js.es6 index 4c47f0e126..fcd85640e6 100644 --- a/app/assets/javascripts/discourse/components/mobile-category-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/mobile-category-topic.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { showEntrance } from "discourse/components/topic-list-item"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "tr", classNameBindings: [ ":category-topic-link", diff --git a/app/assets/javascripts/discourse/components/mobile-nav.js.es6 b/app/assets/javascripts/discourse/components/mobile-nav.js.es6 index 49392fc336..a47c09c5c4 100644 --- a/app/assets/javascripts/discourse/components/mobile-nav.js.es6 +++ b/app/assets/javascripts/discourse/components/mobile-nav.js.es6 @@ -1,6 +1,8 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import { on, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @on("init") _init() { if (!this.get("site.mobileView")) { @@ -20,7 +22,7 @@ export default Ember.Component.extend({ @observes("currentPath") currentPathChanged() { this.set("expanded", false); - Ember.run.next(() => this._updateSelectedHtml()); + next(() => this._updateSelectedHtml()); }, _updateSelectedHtml() { @@ -40,7 +42,7 @@ export default Ember.Component.extend({ toggleExpanded() { this.toggleProperty("expanded"); - Ember.run.next(() => { + next(() => { if (this.expanded) { $(window) .off("click.mobile-nav") diff --git a/app/assets/javascripts/discourse/components/modal-panel.js.es6 b/app/assets/javascripts/discourse/components/modal-panel.js.es6 index b441457a7d..254dd32b73 100644 --- a/app/assets/javascripts/discourse/components/modal-panel.js.es6 +++ b/app/assets/javascripts/discourse/components/modal-panel.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { fmt } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ panel: null, panelComponent: fmt("panel.id", "%@-panel"), diff --git a/app/assets/javascripts/discourse/components/modal-tab.js.es6 b/app/assets/javascripts/discourse/components/modal-tab.js.es6 index c7a392507c..94ff00ef9d 100644 --- a/app/assets/javascripts/discourse/components/modal-tab.js.es6 +++ b/app/assets/javascripts/discourse/components/modal-tab.js.es6 @@ -1,14 +1,16 @@ +import { equal, alias } from "@ember/object/computed"; +import Component from "@ember/component"; import { propertyEqual } from "discourse/lib/computed"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "li", classNames: ["modal-tab"], panel: null, selectedPanel: null, panelsLength: null, classNameBindings: ["isActive", "singleTab", "panel.id"], - singleTab: Ember.computed.equal("panelsLength", 1), - title: Ember.computed.alias("panel.title"), + singleTab: equal("panelsLength", 1), + title: alias("panel.title"), isActive: propertyEqual("panel.id", "selectedPanel.id"), click() { diff --git a/app/assets/javascripts/discourse/components/mount-widget.js.es6 b/app/assets/javascripts/discourse/components/mount-widget.js.es6 index d8431f2820..e62b7acab3 100644 --- a/app/assets/javascripts/discourse/components/mount-widget.js.es6 +++ b/app/assets/javascripts/discourse/components/mount-widget.js.es6 @@ -1,8 +1,12 @@ +import { cancel } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { diff, patch } from "virtual-dom"; import { WidgetClickHook } from "discourse/widgets/hooks"; import { queryRegistry } from "discourse/widgets/widget"; import { getRegister } from "discourse-common/lib/get-owner"; import DirtyKeys from "discourse/lib/dirty-keys"; +import { camelize } from "@ember/string"; let _cleanCallbacks = {}; export function addWidgetCleanCallback(widgetName, fn) { @@ -14,7 +18,7 @@ export function resetWidgetCleanCallbacks() { _cleanCallbacks = {}; } -export default Ember.Component.extend({ +export default Component.extend({ _tree: null, _rootNode: null, _timeout: null, @@ -49,7 +53,7 @@ export default Ember.Component.extend({ this._rootNode = document.createElement("div"); this.element.appendChild(this._rootNode); - this._timeout = Ember.run.scheduleOnce("render", this, this.rerenderWidget); + this._timeout = scheduleOnce("render", this, this.rerenderWidget); }, willClearRender() { @@ -67,7 +71,7 @@ export default Ember.Component.extend({ const [eventName, caller] = evt; this.appEvents.off(eventName, this, caller); }); - Ember.run.cancel(this._timeout); + cancel(this._timeout); }, afterRender() {}, @@ -77,7 +81,7 @@ export default Ember.Component.extend({ afterPatch() {}, eventDispatched(eventName, key, refreshArg) { - const onRefresh = Ember.String.camelize(eventName.replace(/:/, "-")); + const onRefresh = camelize(eventName.replace(/:/, "-")); this.dirtyKeys.keyDirty(key, { onRefresh, refreshArg }); this.queueRerender(); }, @@ -96,13 +100,13 @@ export default Ember.Component.extend({ this._renderCallback = callback; } - Ember.run.scheduleOnce("render", this, this.rerenderWidget); + scheduleOnce("render", this, this.rerenderWidget); }, buildArgs() {}, rerenderWidget() { - Ember.run.cancel(this._timeout); + cancel(this._timeout); if (this._rootNode) { if (!this._widgetClass) { diff --git a/app/assets/javascripts/discourse/components/nav-item.js.es6 b/app/assets/javascripts/discourse/components/nav-item.js.es6 index 2cff295403..d648e892d3 100644 --- a/app/assets/javascripts/discourse/components/nav-item.js.es6 +++ b/app/assets/javascripts/discourse/components/nav-item.js.es6 @@ -1,11 +1,13 @@ +import { inject as service } from "@ember/service"; +import Component from "@ember/component"; /* You might be looking for navigation-item. */ import { iconHTML } from "discourse-common/lib/icon-library"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "li", classNameBindings: ["active"], - router: Ember.inject.service(), + router: service(), @computed("label", "i18nLabel", "icon") contents(label, i18nLabel, icon) { diff --git a/app/assets/javascripts/discourse/components/navigation-bar.js.es6 b/app/assets/javascripts/discourse/components/navigation-bar.js.es6 index 4be9c2c055..eb8cb454b3 100644 --- a/app/assets/javascripts/discourse/components/navigation-bar.js.es6 +++ b/app/assets/javascripts/discourse/components/navigation-bar.js.es6 @@ -1,3 +1,5 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes @@ -5,7 +7,7 @@ import { import DiscourseURL from "discourse/lib/url"; import { renderedConnectorsFor } from "discourse/lib/plugin-connectors"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "ul", classNameBindings: [":nav", ":nav-pills"], elementId: "navigation-bar", @@ -20,9 +22,11 @@ export default Ember.Component.extend({ if (filterMode.indexOf("top/") === 0) { filterMode = "top"; } - var item = navItems.find( - i => i.get("filterMode").indexOf(filterMode) === 0 - ); + let item = navItems.find(i => i.active === true); + + item = + item || navItems.find(i => i.get("filterMode").indexOf(filterMode) === 0); + if (!item) { let connectors = this.connectors; let category = this.category; @@ -68,7 +72,7 @@ export default Ember.Component.extend({ if (this.expanded) { DiscourseURL.appEvents.on("dom:clean", this, this.ensureDropClosed); - Ember.run.next(() => { + next(() => { if (!this.expanded) { return; } @@ -76,7 +80,7 @@ export default Ember.Component.extend({ $(this.element.querySelector(".drop a")).on("click", () => { this.element.querySelector(".drop").style.display = "none"; - Ember.run.next(() => { + next(() => { if (!this.element || this.isDestroying || this.isDestroyed) { return; } diff --git a/app/assets/javascripts/discourse/components/navigation-item.js.es6 b/app/assets/javascripts/discourse/components/navigation-item.js.es6 index 10290334a7..6d55112a94 100644 --- a/app/assets/javascripts/discourse/components/navigation-item.js.es6 +++ b/app/assets/javascripts/discourse/components/navigation-item.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "li", classNameBindings: [ @@ -14,8 +15,11 @@ export default Ember.Component.extend( hidden: false, rerenderTriggers: ["content.count"], - @computed("content.filterMode", "filterMode") - active(contentFilterMode, filterMode) { + @computed("content.filterMode", "filterMode", "content.active") + active(contentFilterMode, filterMode, active) { + if (active !== undefined) { + return active; + } return ( contentFilterMode === filterMode || filterMode.indexOf(contentFilterMode) === 0 diff --git a/app/assets/javascripts/discourse/components/plugin-connector.js.es6 b/app/assets/javascripts/discourse/components/plugin-connector.js.es6 index 76590147ce..715cb62965 100644 --- a/app/assets/javascripts/discourse/components/plugin-connector.js.es6 +++ b/app/assets/javascripts/discourse/components/plugin-connector.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 index 36b8929157..14e3805964 100644 --- a/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 +++ b/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 @@ -1,3 +1,4 @@ +import Component from "@ember/component"; /** A plugin outlet is an extension point for templates where other templates can be inserted by plugins. @@ -31,7 +32,7 @@ **/ import { renderedConnectorsFor } from "discourse/lib/plugin-connectors"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", connectors: null, diff --git a/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 index 5f4fda605c..38930d57e4 100644 --- a/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 +++ b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 @@ -1,3 +1,5 @@ +import { alias, not } from "@ember/object/computed"; +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { default as computed, @@ -5,7 +7,7 @@ import { } from "ember-addons/ember-computed-decorators"; import { bufferedRender } from "discourse-common/lib/buffered-render"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNameBindings: [":popup-tip", "good", "bad", "lastShownAt::hide"], animateAttribute: null, @@ -18,8 +20,8 @@ export default Ember.Component.extend( this.set("validation.lastShownAt", null); }, - bad: Ember.computed.alias("validation.failed"), - good: Ember.computed.not("bad"), + bad: alias("validation.failed"), + good: not("bad"), @computed("shownAt", "validation.lastShownAt") lastShownAt(shownAt, lastShownAt) { diff --git a/app/assets/javascripts/discourse/components/preference-checkbox.js.es6 b/app/assets/javascripts/discourse/components/preference-checkbox.js.es6 index b0e84c117d..7ae299f5de 100644 --- a/app/assets/javascripts/discourse/components/preference-checkbox.js.es6 +++ b/app/assets/javascripts/discourse/components/preference-checkbox.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["controls"], @computed("labelKey") diff --git a/app/assets/javascripts/discourse/components/pwa-install-banner.js.es6 b/app/assets/javascripts/discourse/components/pwa-install-banner.js.es6 index 458fa3cebd..e2e60f3d88 100644 --- a/app/assets/javascripts/discourse/components/pwa-install-banner.js.es6 +++ b/app/assets/javascripts/discourse/components/pwa-install-banner.js.es6 @@ -1,3 +1,5 @@ +import { bind } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, on @@ -5,7 +7,7 @@ import { const USER_DISMISSED_PROMPT_KEY = "dismissed-pwa-install-banner"; -export default Ember.Component.extend({ +export default Component.extend({ deferredInstallPromptEvent: null, _handleInstallPromptEvent(event) { @@ -17,10 +19,7 @@ export default Ember.Component.extend({ @on("didInsertElement") _registerListener() { - this._promptEventHandler = Ember.run.bind( - this, - this._handleInstallPromptEvent - ); + this._promptEventHandler = bind(this, this._handleInstallPromptEvent); window.addEventListener("beforeinstallprompt", this._promptEventHandler); }, diff --git a/app/assets/javascripts/discourse/components/quote-button.js.es6 b/app/assets/javascripts/discourse/components/quote-button.js.es6 index 0bde5b4ffa..ec8b8c47e8 100644 --- a/app/assets/javascripts/discourse/components/quote-button.js.es6 +++ b/app/assets/javascripts/discourse/components/quote-button.js.es6 @@ -1,7 +1,9 @@ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import debounce from "discourse/lib/debounce"; import { selectedText } from "discourse/lib/utilities"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["quote-button"], classNameBindings: ["visible"], visible: false, @@ -102,15 +104,18 @@ export default Ember.Component.extend({ } // change the position of the button - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { let top = markerOffset.top; let left = markerOffset.left + Math.max(0, parentScrollLeft); if (showAtEnd) { - top = top + 20; + const nearRightEdgeOfScreen = + $(window).width() - $quoteButton.outerWidth() < left + 10; + + top = nearRightEdgeOfScreen ? top + 50 : top + 20; left = Math.min( left + 10, - $(window).width() - $quoteButton.outerWidth() + $(window).width() - $quoteButton.outerWidth() - 10 ); } else { top = top - $quoteButton.outerHeight() - 5; diff --git a/app/assets/javascripts/discourse/components/radio-button.js.es6 b/app/assets/javascripts/discourse/components/radio-button.js.es6 index 4a7929d058..b6d44b4a99 100644 --- a/app/assets/javascripts/discourse/components/radio-button.js.es6 +++ b/app/assets/javascripts/discourse/components/radio-button.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "input", type: "radio", attributeBindings: [ @@ -13,10 +14,15 @@ export default Ember.Component.extend({ click() { const value = $(this.element).val(); - if (this.selection === value) { - this.set("selection", undefined); + + if (this.onChange) { + this.onChange(value); + } else { + if (this.selection === value) { + this.set("selection", undefined); + } + this.set("selection", value); } - this.set("selection", value); }, @computed("value", "selection") diff --git a/app/assets/javascripts/discourse/components/related-messages.js.es6 b/app/assets/javascripts/discourse/components/related-messages.js.es6 index e7d65a4591..bf95279941 100644 --- a/app/assets/javascripts/discourse/components/related-messages.js.es6 +++ b/app/assets/javascripts/discourse/components/related-messages.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { iconHTML } from "discourse-common/lib/icon-library"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "related-messages", classNames: ["suggested-topics"], diff --git a/app/assets/javascripts/discourse/components/reviewable-bundled-action.js.es6 b/app/assets/javascripts/discourse/components/reviewable-bundled-action.js.es6 index d42a2dd290..2b3cc0fdf4 100644 --- a/app/assets/javascripts/discourse/components/reviewable-bundled-action.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-bundled-action.js.es6 @@ -1,8 +1,10 @@ -export default Ember.Component.extend({ +import { gt, alias } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ tagName: "", - multiple: Ember.computed.gt("bundle.actions.length", 1), - first: Ember.computed.alias("bundle.actions.firstObject"), + multiple: gt("bundle.actions.length", 1), + first: alias("bundle.actions.firstObject"), actions: { performById(id) { diff --git a/app/assets/javascripts/discourse/components/reviewable-claimed-topic.js.es6 b/app/assets/javascripts/discourse/components/reviewable-claimed-topic.js.es6 index d73a32d304..0583a4605f 100644 --- a/app/assets/javascripts/discourse/components/reviewable-claimed-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-claimed-topic.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed diff --git a/app/assets/javascripts/discourse/components/reviewable-conversation-post.js.es6 b/app/assets/javascripts/discourse/components/reviewable-conversation-post.js.es6 index b57e6aa5de..9fc360d10c 100644 --- a/app/assets/javascripts/discourse/components/reviewable-conversation-post.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-conversation-post.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Component.extend({ - showUsername: Ember.computed.gte("index", 1) +import { gte } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ + showUsername: gte("index", 1) }); diff --git a/app/assets/javascripts/discourse/components/reviewable-flagged-post.js.es6 b/app/assets/javascripts/discourse/components/reviewable-flagged-post.js.es6 index 1916a96125..58c48d1bbf 100644 --- a/app/assets/javascripts/discourse/components/reviewable-flagged-post.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-flagged-post.js.es6 @@ -1,10 +1,12 @@ +import { gt } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { longDate } from "discourse/lib/formatter"; import { historyHeat } from "discourse/widgets/post-edits-indicator"; import showModal from "discourse/lib/show-modal"; -export default Ember.Component.extend({ - hasEdits: Ember.computed.gt("reviewable.post_version", 1), +export default Component.extend({ + hasEdits: gt("reviewable.post_version", 1), @computed("reviewable.post_updated_at") historyClass(updatedAt) { diff --git a/app/assets/javascripts/discourse/components/reviewable-histories.js.es6 b/app/assets/javascripts/discourse/components/reviewable-histories.js.es6 index a5f1a7932e..f52c1c4000 100644 --- a/app/assets/javascripts/discourse/components/reviewable-histories.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-histories.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Component.extend({ - filteredHistories: Ember.computed.filterBy("histories", "created", false) +import { filterBy } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ + filteredHistories: filterBy("histories", "created", false) }); diff --git a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 index 4507704d95..c5aaba8b7b 100644 --- a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 @@ -1,13 +1,16 @@ +import Component from "@ember/component"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; import Category from "discourse/models/category"; import optionalService from "discourse/lib/optional-service"; import showModal from "discourse/lib/show-modal"; +import { dasherize } from "@ember/string"; +import { set } from "@ember/object"; let _components = {}; -export default Ember.Component.extend({ +export default Component.extend({ adminTools: optionalService(), tagName: "", updating: null, @@ -64,7 +67,7 @@ export default Ember.Component.extend({ return _components[type]; } - let dasherized = Ember.String.dasherize(type); + let dasherized = dasherize(type); let templatePath = `components/${dasherized}`; let template = Ember.TEMPLATES[`${templatePath}`] || @@ -184,7 +187,7 @@ export default Ember.Component.extend({ }, valueChanged(fieldId, event) { - Ember.set(this._updates, fieldId, event.target.value); + set(this._updates, fieldId, event.target.value); }, perform(action) { diff --git a/app/assets/javascripts/discourse/components/reviewable-queued-post.js.es6 b/app/assets/javascripts/discourse/components/reviewable-queued-post.js.es6 index 1255c5bddc..2e17ce9423 100644 --- a/app/assets/javascripts/discourse/components/reviewable-queued-post.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-queued-post.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import showModal from "discourse/lib/show-modal"; -export default Ember.Component.extend({ +export default Component.extend({ actions: { showRawEmail() { showModal("raw-email").set("rawEmail", this.reviewable.payload.raw_email); diff --git a/app/assets/javascripts/discourse/components/reviewable-user.js.es6 b/app/assets/javascripts/discourse/components/reviewable-user.js.es6 index f071ba7b33..ec065a0bde 100644 --- a/app/assets/javascripts/discourse/components/reviewable-user.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-user.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("reviewable.user_fields") userFields(fields) { return this.site.collectUserFields(fields); diff --git a/app/assets/javascripts/discourse/components/scroll-tracker.js.es6 b/app/assets/javascripts/discourse/components/scroll-tracker.js.es6 index caad7dc87a..7637845c1e 100644 --- a/app/assets/javascripts/discourse/components/scroll-tracker.js.es6 +++ b/app/assets/javascripts/discourse/components/scroll-tracker.js.es6 @@ -1,6 +1,8 @@ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; import Scrolling from "discourse/mixins/scrolling"; -export default Ember.Component.extend(Scrolling, { +export default Component.extend(Scrolling, { didReceiveAttrs() { this._super(...arguments); @@ -18,7 +20,7 @@ export default Ember.Component.extend(Scrolling, { const data = this.session.get(this.trackerName); if (data && data.position >= 0 && data.tag === this.tag) { - Ember.run.next(() => $(window).scrollTop(data.position + 1)); + next(() => $(window).scrollTop(data.position + 1)); } }, diff --git a/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 b/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 index 89a48126f3..04f0897eb6 100644 --- a/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 +++ b/app/assets/javascripts/discourse/components/scrolling-post-stream.js.es6 @@ -1,3 +1,6 @@ +import { next } from "@ember/runloop"; +import { debounce } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; import DiscourseURL from "discourse/lib/url"; import MountWidget from "discourse/components/mount-widget"; import { cloak, uncloak } from "discourse/widgets/post-stream"; @@ -204,7 +207,7 @@ export default MountWidget.extend({ // will cause the browser to scroll to the top of the document // in Chrome. This makes sure the scroll works correctly if that // happens. - Ember.run.next(() => $("html, body").scrollTop(whereY)); + next(() => $("html, body").scrollTop(whereY)); } }); }; @@ -270,7 +273,7 @@ export default MountWidget.extend({ }, _scrollTriggered() { - Ember.run.scheduleOnce("afterRender", this, this.scrolled); + scheduleOnce("afterRender", this, this.scrolled); }, _posted(staged) { @@ -306,13 +309,12 @@ export default MountWidget.extend({ }, _debouncedScroll() { - Ember.run.debounce(this, this._scrollTriggered, 10); + debounce(this, this._scrollTriggered, 10); }, didInsertElement() { this._super(...arguments); - const debouncedScroll = () => - Ember.run.debounce(this, this._scrollTriggered, 10); + const debouncedScroll = () => debounce(this, this._scrollTriggered, 10); this._previouslyNearby = {}; diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 50da93e6c2..8f1779487d 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -1,3 +1,6 @@ +import { debounce } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { observes } from "ember-addons/ember-computed-decorators"; import { escapeExpression } from "discourse/lib/utilities"; import Group from "discourse/models/group"; @@ -28,7 +31,7 @@ const REGEXP_POST_TIME_WHEN = /^(before|after)/gi; const IN_OPTIONS_MAPPING = { images: "with" }; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["search-advanced-options"], init() { @@ -71,13 +74,13 @@ export default Ember.Component.extend({ this._init(); - Ember.run.scheduleOnce("afterRender", () => this._update()); + scheduleOnce("afterRender", () => this._update()); }, @observes("searchTerm") _updateOptions() { this._update(); - Ember.run.debounce(this, this._update, 250); + debounce(this, this._update, 250); }, _init() { diff --git a/app/assets/javascripts/discourse/components/second-factor-form.js.es6 b/app/assets/javascripts/discourse/components/second-factor-form.js.es6 index 572fd509f7..ce332c23b1 100644 --- a/app/assets/javascripts/discourse/components/second-factor-form.js.es6 +++ b/app/assets/javascripts/discourse/components/second-factor-form.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("secondFactorMethod") secondFactorTitle(secondFactorMethod) { switch (secondFactorMethod) { diff --git a/app/assets/javascripts/discourse/components/second-factor-input.js.es6 b/app/assets/javascripts/discourse/components/second-factor-input.js.es6 index 00e27039a4..97ce1a4fa7 100644 --- a/app/assets/javascripts/discourse/components/second-factor-input.js.es6 +++ b/app/assets/javascripts/discourse/components/second-factor-input.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; -export default Ember.Component.extend({ +export default Component.extend({ @computed("secondFactorMethod") type(secondFactorMethod) { if (secondFactorMethod === SECOND_FACTOR_METHODS.TOTP) return "tel"; diff --git a/app/assets/javascripts/discourse/components/security-key-form.js.es6 b/app/assets/javascripts/discourse/components/security-key-form.js.es6 index 3161831869..d315bf6889 100644 --- a/app/assets/javascripts/discourse/components/security-key-form.js.es6 +++ b/app/assets/javascripts/discourse/components/security-key-form.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; -export default Ember.Component.extend({ +export default Component.extend({ actions: { useAnotherMethod() { this.set("showSecurityKey", false); diff --git a/app/assets/javascripts/discourse/components/share-panel.js.es6 b/app/assets/javascripts/discourse/components/share-panel.js.es6 index 136e6a9ccc..3a7b94b645 100644 --- a/app/assets/javascripts/discourse/components/share-panel.js.es6 +++ b/app/assets/javascripts/discourse/components/share-panel.js.es6 @@ -1,13 +1,17 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { escapeExpression } from "discourse/lib/utilities"; import { default as computed } from "ember-addons/ember-computed-decorators"; import Sharing from "discourse/lib/sharing"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: null, - type: Ember.computed.alias("panel.model.type"), + type: alias("panel.model.type"), - topic: Ember.computed.alias("panel.model.topic"), + topic: alias("panel.model.topic"), @computed sources() { @@ -24,7 +28,7 @@ export default Ember.Component.extend({ shareUrl(forcedShareUrl, shareUrl) { shareUrl = forcedShareUrl || shareUrl; - if (Ember.isEmpty(shareUrl)) { + if (isEmpty(shareUrl)) { return; } @@ -46,7 +50,7 @@ export default Ember.Component.extend({ this.element.querySelector(".topic-share-url-for-touch a") ); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { if (!this.capabilities.touch) { $linkForTouch.parent().remove(); diff --git a/app/assets/javascripts/discourse/components/share-popup.js.es6 b/app/assets/javascripts/discourse/components/share-popup.js.es6 index dad5d68949..4f9d0b9792 100644 --- a/app/assets/javascripts/discourse/components/share-popup.js.es6 +++ b/app/assets/javascripts/discourse/components/share-popup.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { bind } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import { longDateNoYear } from "discourse/lib/formatter"; import { @@ -7,7 +11,7 @@ import { import Sharing from "discourse/lib/sharing"; import { nativeShare } from "discourse/lib/pwa-utils"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "share-link", classNameBindings: ["visible"], link: null, @@ -56,7 +60,7 @@ export default Ember.Component.extend({ const $currentTargetOffset = $target.offset(); const $this = $(this.element); - if (Ember.isEmpty(url)) { + if (isEmpty(url)) { return; } @@ -85,10 +89,10 @@ export default Ember.Component.extend({ if (!this.site.mobileView) { $this.css({ left: "" + x + "px" }); } - this.set("link", encodeURI(url)); + this.set("link", url); this.set("visible", true); - Ember.run.scheduleOnce("afterRender", this, this._focusUrl); + scheduleOnce("afterRender", this, this._focusUrl); }, _mouseDownHandler(event) { @@ -153,9 +157,9 @@ export default Ember.Component.extend({ @on("init") _setupHandlers() { - this._boundMouseDownHandler = Ember.run.bind(this, this._mouseDownHandler); - this._boundClickHandler = Ember.run.bind(this, this._clickHandler); - this._boundKeydownHandler = Ember.run.bind(this, this._keydownHandler); + this._boundMouseDownHandler = bind(this, this._mouseDownHandler); + this._boundClickHandler = bind(this, this._clickHandler); + this._boundKeydownHandler = bind(this, this._keydownHandler); }, didInsertElement() { diff --git a/app/assets/javascripts/discourse/components/share-source.js.es6 b/app/assets/javascripts/discourse/components/share-source.js.es6 index 0eb7020886..1ce8f6e5da 100644 --- a/app/assets/javascripts/discourse/components/share-source.js.es6 +++ b/app/assets/javascripts/discourse/components/share-source.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNameBindings: [":social-link"], actions: { diff --git a/app/assets/javascripts/discourse/components/shared-draft-controls.js.es6 b/app/assets/javascripts/discourse/components/shared-draft-controls.js.es6 index 002a13e7da..b408ee87a1 100644 --- a/app/assets/javascripts/discourse/components/shared-draft-controls.js.es6 +++ b/app/assets/javascripts/discourse/components/shared-draft-controls.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", publishing: false, diff --git a/app/assets/javascripts/discourse/components/signup-cta.js.es6 b/app/assets/javascripts/discourse/components/signup-cta.js.es6 index dbbc7ad1d5..7d6f1623e4 100644 --- a/app/assets/javascripts/discourse/components/signup-cta.js.es6 +++ b/app/assets/javascripts/discourse/components/signup-cta.js.es6 @@ -1,4 +1,8 @@ -export default Ember.Component.extend({ +import { later } from "@ember/runloop"; +import Component from "@ember/component"; +import { on } from "@ember/object/evented"; + +export default Component.extend({ action: "showCreateAccount", actions: { @@ -9,16 +13,13 @@ export default Ember.Component.extend({ hideForSession() { this.session.set("hideSignupCta", true); this.keyValueStore.setItem("anon-cta-hidden", new Date().getTime()); - Ember.run.later( - () => this.session.set("showSignupCta", false), - 20 * 1000 - ); + later(() => this.session.set("showSignupCta", false), 20 * 1000); } }, - _turnOffIfHidden: function() { + _turnOffIfHidden: on("willDestroyElement", function() { if (this.session.get("hideSignupCta")) { this.session.set("showSignupCta", false); } - }.on("willDestroyElement") + }) }); diff --git a/app/assets/javascripts/discourse/components/site-header.js.es6 b/app/assets/javascripts/discourse/components/site-header.js.es6 index 41c71a48e5..b7b82071c1 100644 --- a/app/assets/javascripts/discourse/components/site-header.js.es6 +++ b/app/assets/javascripts/discourse/components/site-header.js.es6 @@ -1,3 +1,6 @@ +import { cancel } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; +import { later } from "@ember/runloop"; import MountWidget from "discourse/components/mount-widget"; import { observes } from "ember-addons/ember-computed-decorators"; import Docking from "discourse/mixins/docking"; @@ -38,7 +41,7 @@ const SiteHeaderComponent = MountWidget.extend(Docking, PanEvents, { _animateClosing($panel, menuOrigin, windowWidth) { $panel.css(menuOrigin, -windowWidth); this._animate = true; - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.eventDispatched("dom:clean", "header"); this._panMenuOffset = 0; }); @@ -222,7 +225,7 @@ const SiteHeaderComponent = MountWidget.extend(Docking, PanEvents, { this.appEvents.off("header:hide-topic", this, "setTopic"); this.appEvents.off("dom:clean", this, "_cleanDom"); - Ember.run.cancel(this._scheduledRemoveAnimate); + cancel(this._scheduledRemoveAnimate); window.cancelAnimationFrame(this._scheduledMovingAnimation); }, @@ -346,7 +349,7 @@ const SiteHeaderComponent = MountWidget.extend(Docking, PanEvents, { if (this._animate) { $panel.addClass("animate"); $headerCloak.addClass("animate"); - this._scheduledRemoveAnimate = Ember.run.later(() => { + this._scheduledRemoveAnimate = later(() => { $panel.removeClass("animate"); $headerCloak.removeClass("animate"); }, 200); diff --git a/app/assets/javascripts/discourse/components/suggested-topics.js.es6 b/app/assets/javascripts/discourse/components/suggested-topics.js.es6 index b5756b859c..11b6cbf20d 100644 --- a/app/assets/javascripts/discourse/components/suggested-topics.js.es6 +++ b/app/assets/javascripts/discourse/components/suggested-topics.js.es6 @@ -1,8 +1,10 @@ +import { get } from "@ember/object"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { categoryBadgeHTML } from "discourse/helpers/category-link"; import { iconHTML } from "discourse-common/lib/icon-library"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "suggested-topics", classNames: ["suggested-topics"], @@ -34,7 +36,7 @@ export default Ember.Component.extend({ if ( category && - Ember.get(category, "id") === + get(category, "id") === Discourse.Site.currentProp("uncategorized_category_id") ) { category = null; diff --git a/app/assets/javascripts/discourse/components/tag-drop-link.js.es6 b/app/assets/javascripts/discourse/components/tag-drop-link.js.es6 index ab41561429..73d20d7922 100644 --- a/app/assets/javascripts/discourse/components/tag-drop-link.js.es6 +++ b/app/assets/javascripts/discourse/components/tag-drop-link.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import DiscourseURL from "discourse/lib/url"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "a", classNameBindings: [ ":tag-badge-wrapper", diff --git a/app/assets/javascripts/discourse/components/tag-groups-form.js.es6 b/app/assets/javascripts/discourse/components/tag-groups-form.js.es6 new file mode 100644 index 0000000000..2dddb086e8 --- /dev/null +++ b/app/assets/javascripts/discourse/components/tag-groups-form.js.es6 @@ -0,0 +1,70 @@ +import { isEmpty } from "@ember/utils"; +import Component from "@ember/component"; +import computed from "ember-addons/ember-computed-decorators"; +import { bufferedProperty } from "discourse/mixins/buffered-content"; +import PermissionType from "discourse/models/permission-type"; + +export default Component.extend(bufferedProperty("model"), { + tagName: "", + + @computed("buffered.isSaving", "buffered.name", "buffered.tag_names") + savingDisabled(isSaving, name, tagNames) { + return isSaving || isEmpty(name) || isEmpty(tagNames); + }, + + actions: { + setPermissions(permissionName) { + if (permissionName === "private") { + this.buffered.set("permissions", { + staff: PermissionType.FULL + }); + } else if (permissionName === "visible") { + this.buffered.set("permissions", { + staff: PermissionType.FULL, + everyone: PermissionType.READONLY + }); + } else { + this.buffered.set("permissions", { + everyone: PermissionType.FULL + }); + } + }, + + save() { + const attrs = this.buffered.getProperties( + "name", + "tag_names", + "parent_tag_name", + "one_per_topic", + "permissions" + ); + + this.model.save(attrs).then(() => { + this.commitBuffer(); + + if (this.onSave) { + this.onSave(); + } + }); + }, + + destroy() { + return bootbox.confirm( + I18n.t("tagging.groups.confirm_delete"), + I18n.t("no_value"), + I18n.t("yes_value"), + destroy => { + if (!destroy) { + return; + } + + this.model.destroyRecord().then(() => { + if (this.onDestroy) { + this.onDestroy(); + } + }); + } + ); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/tag-list.js.es6 b/app/assets/javascripts/discourse/components/tag-list.js.es6 index a6578bb398..551b70c93d 100644 --- a/app/assets/javascripts/discourse/components/tag-list.js.es6 +++ b/app/assets/javascripts/discourse/components/tag-list.js.es6 @@ -1,10 +1,12 @@ +import { sort } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ - classNameBindings: [":tag-list", "categoryClass"], +export default Component.extend({ + classNameBindings: [":tag-list", "categoryClass", "tagGroupNameClass"], isPrivateMessage: false, - sortedTags: Ember.computed.sort("tags", "sortProperties"), + sortedTags: sort("tags", "sortProperties"), @computed("titleKey") title(titleKey) { @@ -19,5 +21,16 @@ export default Ember.Component.extend({ @computed("category.fullSlug") categoryClass(slug) { return slug && `tag-list-${slug}`; + }, + + @computed("tagGroupName") + tagGroupNameClass(groupName) { + if (groupName) { + groupName = groupName + .replace(/\s+/g, "-") + .replace(/[!\"#$%&'\(\)\*\+,\.\/:;<=>\?\@\[\\\]\^`\{\|\}~]/g, "") + .toLowerCase(); + return groupName && `tag-group-${groupName}`; + } } }); diff --git a/app/assets/javascripts/discourse/components/text-overflow.js.es6 b/app/assets/javascripts/discourse/components/text-overflow.js.es6 index a63b6fed5d..d5bc066fb0 100644 --- a/app/assets/javascripts/discourse/components/text-overflow.js.es6 +++ b/app/assets/javascripts/discourse/components/text-overflow.js.es6 @@ -1,7 +1,9 @@ -export default Ember.Component.extend({ +import { next } from "@ember/runloop"; +import Component from "@ember/component"; +export default Component.extend({ didInsertElement() { this._super(...arguments); - Ember.run.next(null, () => { + next(null, () => { const $this = $(this.element); if ($this) { diff --git a/app/assets/javascripts/discourse/components/time-input.js.es6 b/app/assets/javascripts/discourse/components/time-input.js.es6 index bdeb1b3a72..e636380a77 100644 --- a/app/assets/javascripts/discourse/components/time-input.js.es6 +++ b/app/assets/javascripts/discourse/components/time-input.js.es6 @@ -1,14 +1,17 @@ +import { oneWay, or } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { isNumeric } from "discourse/lib/utilities"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["d-time-input"], hours: null, minutes: null, - _hours: Ember.computed.oneWay("hours"), - _minutes: Ember.computed.oneWay("minutes"), - isSafari: Ember.computed.oneWay("capabilities.isSafari"), - isMobile: Ember.computed.oneWay("site.mobileView"), - nativePicker: Ember.computed.or("isSafari", "isMobile"), + _hours: oneWay("hours"), + _minutes: oneWay("minutes"), + isSafari: oneWay("capabilities.isSafari"), + isMobile: oneWay("site.mobileView"), + nativePicker: or("isSafari", "isMobile"), actions: { onInput(options, event) { @@ -35,7 +38,7 @@ export default Ember.Component.extend({ this._processMinutesChange(value); } - Ember.run.schedule("afterRender", () => (event.target.value = value)); + schedule("afterRender", () => (event.target.value = value)); } }, diff --git a/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 b/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 index 059b1a1468..9c01cf1a1d 100644 --- a/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["top-title-buttons"], @computed("period") diff --git a/app/assets/javascripts/discourse/components/topic-category.js.es6 b/app/assets/javascripts/discourse/components/topic-category.js.es6 index 97fcde13cd..3f003c8d77 100644 --- a/app/assets/javascripts/discourse/components/topic-category.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-category.js.es6 @@ -1,2 +1,3 @@ +import Component from "@ember/component"; // Injections don't occur without a class -export default Ember.Component.extend(); +export default Component.extend(); diff --git a/app/assets/javascripts/discourse/components/topic-entrance.js.es6 b/app/assets/javascripts/discourse/components/topic-entrance.js.es6 index e90ccd5857..ead6913e82 100644 --- a/app/assets/javascripts/discourse/components/topic-entrance.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-entrance.js.es6 @@ -1,3 +1,5 @@ +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import DiscourseURL from "discourse/lib/url"; import CleansUp from "discourse/mixins/cleans-up"; import computed from "ember-addons/ember-computed-decorators"; @@ -25,7 +27,7 @@ function entranceDate(dt, showTime) { ); } -export default Ember.Component.extend(CleansUp, { +export default Component.extend(CleansUp, { elementId: "topic-entrance", classNameBindings: ["visible::hidden"], _position: null, @@ -76,7 +78,7 @@ export default Ember.Component.extend(CleansUp, { this.setProperties({ topic: data.topic, visible: true }); - Ember.run.scheduleOnce("afterRender", this, this._setCSS); + scheduleOnce("afterRender", this, this._setCSS); $("html") .off("mousedown.topic-entrance") diff --git a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 index 0c487e7353..7c13728bff 100644 --- a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 @@ -1,7 +1,9 @@ +import { alias, or, and } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { getTopicFooterButtons } from "discourse/lib/register-topic-footer-button"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "topic-footer-buttons", // Allow us to extend it @@ -30,15 +32,11 @@ export default Ember.Component.extend({ return !isPM || this.siteSettings.enable_personal_messages; }, - canInviteTo: Ember.computed.alias("topic.details.can_invite_to"), + canInviteTo: alias("topic.details.can_invite_to"), - canDefer: Ember.computed.alias("currentUser.enable_defer"), + canDefer: alias("currentUser.enable_defer"), - inviteDisabled: Ember.computed.or( - "topic.archived", - "topic.closed", - "topic.deleted" - ), + inviteDisabled: or("topic.archived", "topic.closed", "topic.deleted"), @computed showAdminButton() { @@ -49,10 +47,7 @@ export default Ember.Component.extend({ ); }, - showEditOnFooter: Ember.computed.and( - "topic.isPrivateMessage", - "site.can_tag_pms" - ), + showEditOnFooter: and("topic.isPrivateMessage", "site.can_tag_pms"), @computed("topic.message_archived") archiveIcon: archived => (archived ? "envelope" : "folder"), diff --git a/app/assets/javascripts/discourse/components/topic-join-group-notice.js.es6 b/app/assets/javascripts/discourse/components/topic-join-group-notice.js.es6 index 1fd4f9264d..114e02aa04 100644 --- a/app/assets/javascripts/discourse/components/topic-join-group-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-join-group-notice.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ classNames: ["topic-notice"], @computed("model.group.{full_name,name,allow_membership_requests}") diff --git a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 index 1116d97e61..10161d7b51 100644 --- a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 @@ -1,8 +1,11 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import DiscourseURL from "discourse/lib/url"; import computed from "ember-addons/ember-computed-decorators"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { findRawTemplate } from "discourse/lib/raw-templates"; import { wantsNewWindow } from "discourse/lib/intercept-click"; +import { on } from "@ember/object/evented"; export function showEntrance(e) { let target = $(e.target); @@ -33,7 +36,7 @@ export const ListItemDefaults = { tagName: "tr", classNameBindings: [":topic-list-item", "unboundClassNames", "topic.visited"], attributeBindings: ["data-topic-id"], - "data-topic-id": Ember.computed.alias("topic.id"), + "data-topic-id": alias("topic.id"), didInsertElement() { this._super(...arguments); @@ -202,7 +205,7 @@ export const ListItemDefaults = { $topic.on("animationend", () => $topic.removeClass("highlighted")); }, - _highlightIfNeeded: function() { + _highlightIfNeeded: on("didInsertElement", function() { // highlight the last topic viewed if (this.session.get("lastTopicIdViewed") === this.get("topic.id")) { this.session.set("lastTopicIdViewed", null); @@ -212,10 +215,10 @@ export const ListItemDefaults = { this.set("topic.highlight", false); this.highlight(); } - }.on("didInsertElement") + }) }; -export default Ember.Component.extend( +export default Component.extend( ListItemDefaults, bufferedRender({ rerenderTriggers: ["bulkSelectEnabled", "topic.pinned"], diff --git a/app/assets/javascripts/discourse/components/topic-list.js.es6 b/app/assets/javascripts/discourse/components/topic-list.js.es6 index 44846d5b0d..6d3ea337e2 100644 --- a/app/assets/javascripts/discourse/components/topic-list.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-list.js.es6 @@ -1,23 +1,28 @@ +import { alias, reads } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; +import LoadMore from "discourse/mixins/load-more"; +import { on } from "@ember/object/evented"; -export default Ember.Component.extend({ +export default Component.extend(LoadMore, { tagName: "table", classNames: ["topic-list"], showTopicPostBadges: true, listTitle: "topic.title", // Overwrite this to perform client side filtering of topics, if desired - filteredTopics: Ember.computed.alias("topics"), + filteredTopics: alias("topics"), - _init: function() { + _init: on("init", function() { this.addObserver("hideCategory", this.rerender); this.addObserver("order", this.rerender); this.addObserver("ascending", this.rerender); this.refreshLastVisited(); - }.on("init"), + }), @computed("bulkSelectEnabled") toggleInTitle(bulkSelectEnabled) { @@ -29,7 +34,7 @@ export default Ember.Component.extend({ return !!this.changeSort; }, - skipHeader: Ember.computed.reads("site.mobileView"), + skipHeader: reads("site.mobileView"), @computed("order") showLikes(order) { @@ -54,6 +59,28 @@ export default Ember.Component.extend({ this.refreshLastVisited(); }, + scrolled() { + this._super(...arguments); + let onScroll = this.onScroll; + if (!onScroll) return; + + onScroll.call(this); + }, + + scrollToLastPosition() { + if (!this.scrollOnLoad) return; + + let scrollTo = this.session.get("topicListScrollPosition"); + if (scrollTo && scrollTo >= 0) { + schedule("afterRender", () => $(window).scrollTop(scrollTo + 1)); + } + }, + + didInsertElement() { + this._super(...arguments); + this.scrollToLastPosition(); + }, + _updateLastVisitedTopic(topics, order, ascending, top) { this.set("lastVisitedTopic", null); diff --git a/app/assets/javascripts/discourse/components/topic-navigation.js.es6 b/app/assets/javascripts/discourse/components/topic-navigation.js.es6 index 28cf8b4ae7..b2115e755d 100644 --- a/app/assets/javascripts/discourse/components/topic-navigation.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-navigation.js.es6 @@ -1,3 +1,7 @@ +import EmberObject from "@ember/object"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import { observes } from "ember-addons/ember-computed-decorators"; import showModal from "discourse/lib/show-modal"; import PanEvents, { @@ -6,14 +10,14 @@ import PanEvents, { SWIPE_VELOCITY_THRESHOLD } from "discourse/mixins/pan-events"; -export default Ember.Component.extend(PanEvents, { +export default Component.extend(PanEvents, { composerOpen: null, info: null, isPanning: false, init() { this._super(...arguments); - this.set("info", Ember.Object.create()); + this.set("info", EmberObject.create()); }, _performCheckSize() { @@ -50,7 +54,7 @@ export default Ember.Component.extend(PanEvents, { }, _checkSize() { - Ember.run.scheduleOnce("afterRender", this, this._performCheckSize); + scheduleOnce("afterRender", this, this._performCheckSize); }, // we need to store this so topic progress has something to init with @@ -86,7 +90,7 @@ export default Ember.Component.extend(PanEvents, { composerOpened() { this.set("composerOpen", true); // we need to do the check after animation is done - Ember.run.later(() => this._checkSize(), 500); + later(() => this._checkSize(), 500); }, composerClosed() { @@ -97,7 +101,7 @@ export default Ember.Component.extend(PanEvents, { _collapseFullscreen() { if (this.get("info.topicProgressExpanded")) { $(".timeline-fullscreen").removeClass("show"); - Ember.run.later(() => { + later(() => { if (!this.element || this.isDestroying || this.isDestroyed) { return; } @@ -135,7 +139,7 @@ export default Ember.Component.extend(PanEvents, { } else if (offset <= 0) { $timelineContainer.css("bottom", ""); } else { - Ember.run.later(() => this._handlePanDone(offset, event), 20); + later(() => this._handlePanDone(offset, event), 20); } }, diff --git a/app/assets/javascripts/discourse/components/topic-post-badges.js.es6 b/app/assets/javascripts/discourse/components/topic-post-badges.js.es6 index 69235be0ca..e6b70ab212 100644 --- a/app/assets/javascripts/discourse/components/topic-post-badges.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-post-badges.js.es6 @@ -1,3 +1,4 @@ +import Component from "@ember/component"; import { bufferedRender } from "discourse-common/lib/buffered-render"; // Creates a link @@ -12,7 +13,7 @@ function link(buffer, prop, url, cssClass, i18nKey, text) { ); } -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ tagName: "span", classNameBindings: [":topic-post-badges"], diff --git a/app/assets/javascripts/discourse/components/topic-progress.js.es6 b/app/assets/javascripts/discourse/components/topic-progress.js.es6 index e37d5821c2..9d5cb2103f 100644 --- a/app/assets/javascripts/discourse/components/topic-progress.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-progress.js.es6 @@ -1,14 +1,17 @@ +import { alias } from "@ember/object/computed"; +import { scheduleOnce } from "@ember/runloop"; +import Component from "@ember/component"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ elementId: "topic-progress-wrapper", classNameBindings: ["docked"], docked: false, progressPosition: null, - postStream: Ember.computed.alias("topic.postStream"), + postStream: alias("topic.postStream"), _streamPercentage: null, @computed("progressPosition") @@ -72,7 +75,7 @@ export default Ember.Component.extend({ @observes("postStream.stream.[]") _updateBar() { - Ember.run.scheduleOnce("afterRender", this, this._updateProgressBar); + scheduleOnce("afterRender", this, this._updateProgressBar); }, _topicScrolled(event) { @@ -99,16 +102,11 @@ export default Ember.Component.extend({ const prevEvent = this.prevEvent; if (prevEvent) { - Ember.run.scheduleOnce( - "afterRender", - this, - this._topicScrolled, - prevEvent - ); + scheduleOnce("afterRender", this, this._topicScrolled, prevEvent); } else { - Ember.run.scheduleOnce("afterRender", this, this._updateProgressBar); + scheduleOnce("afterRender", this, this._updateProgressBar); } - Ember.run.scheduleOnce("afterRender", this, this._dock); + scheduleOnce("afterRender", this, this._dock); }, willDestroyElement() { diff --git a/app/assets/javascripts/discourse/components/topic-status.js.es6 b/app/assets/javascripts/discourse/components/topic-status.js.es6 index d063847e83..dc3e0d14f6 100644 --- a/app/assets/javascripts/discourse/components/topic-status.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-status.js.es6 @@ -1,10 +1,11 @@ +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import { escapeExpression } from "discourse/lib/utilities"; import TopicStatusIcons from "discourse/helpers/topic-status-icons"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNames: ["topic-statuses"], diff --git a/app/assets/javascripts/discourse/components/topic-timeline.js.es6 b/app/assets/javascripts/discourse/components/topic-timeline.js.es6 index 17709a5fc7..9aa6541065 100644 --- a/app/assets/javascripts/discourse/components/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-timeline.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; import MountWidget from "discourse/components/mount-widget"; import Docking from "discourse/mixins/docking"; import { observes } from "ember-addons/ember-computed-decorators"; @@ -58,7 +59,8 @@ export default MountWidget.extend(Docking, { const mainOffset = $("#main").offset(); const offsetTop = mainOffset ? mainOffset.top : 0; const topicTop = $(".container.posts").offset().top - offsetTop; - const topicBottom = $("#topic-bottom").offset().top; + const topicBottom = + $("#topic-bottom").offset().top - $("#main-outlet").offset().top; const timeline = this.element.querySelector(".timeline-container"); const timelineHeight = (timeline && timeline.offsetHeight) || 400; const footerHeight = $(".timeline-footer-controls").outerHeight(true) || 0; @@ -93,7 +95,7 @@ export default MountWidget.extend(Docking, { this._super(...arguments); if (this.fullscreen && !this.addShowClass) { - Ember.run.next(() => { + next(() => { this.set("addShowClass", true); this.queueRerender(); }); diff --git a/app/assets/javascripts/discourse/components/topic-timer-info.js.es6 b/app/assets/javascripts/discourse/components/topic-timer-info.js.es6 index 288e61b3bb..bb26e0caba 100644 --- a/app/assets/javascripts/discourse/components/topic-timer-info.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-timer-info.js.es6 @@ -1,10 +1,13 @@ +import { cancel } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import { bufferedRender } from "discourse-common/lib/buffered-render"; import Category from "discourse/models/category"; import computed from "ember-addons/ember-computed-decorators"; import { REMINDER_TYPE } from "discourse/controllers/edit-topic-timer"; -export default Ember.Component.extend( +export default Component.extend( bufferedRender({ classNames: ["topic-status-info"], _delayedRerender: null, @@ -84,11 +87,7 @@ export default Ember.Component.extend( // TODO Sam: concerned this can cause a heavy rerender loop if (!Ember.testing) { - this._delayedRerender = Ember.run.later( - this, - this.rerender, - rerenderDelay - ); + this._delayedRerender = later(this, this.rerender, rerenderDelay); } } }, @@ -109,7 +108,7 @@ export default Ember.Component.extend( $(this.element).off("click.topic-timer-remove", this.removeTopicTimer); if (this._delayedRerender) { - Ember.run.cancel(this._delayedRerender); + cancel(this._delayedRerender); } }, diff --git a/app/assets/javascripts/discourse/components/topic-title.js.es6 b/app/assets/javascripts/discourse/components/topic-title.js.es6 index 17f99b48ee..7bbc478cb3 100644 --- a/app/assets/javascripts/discourse/components/topic-title.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-title.js.es6 @@ -1,5 +1,6 @@ +import Component from "@ember/component"; import KeyEnterEscape from "discourse/mixins/key-enter-escape"; -export default Ember.Component.extend(KeyEnterEscape, { +export default Component.extend(KeyEnterEscape, { elementId: "topic-title" }); diff --git a/app/assets/javascripts/discourse/components/track-selected.js.es6 b/app/assets/javascripts/discourse/components/track-selected.js.es6 index bf720378b7..241cb64c7c 100644 --- a/app/assets/javascripts/discourse/components/track-selected.js.es6 +++ b/app/assets/javascripts/discourse/components/track-selected.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "span", selectionChanged: function() { const selected = this.selected; diff --git a/app/assets/javascripts/discourse/components/user-badge.js.es6 b/app/assets/javascripts/discourse/components/user-badge.js.es6 index bca90d4435..85de291634 100644 --- a/app/assets/javascripts/discourse/components/user-badge.js.es6 +++ b/app/assets/javascripts/discourse/components/user-badge.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "span", @computed("count") diff --git a/app/assets/javascripts/discourse/components/user-card-contents.js.es6 b/app/assets/javascripts/discourse/components/user-card-contents.js.es6 index 981cbb125d..d7c6eac785 100644 --- a/app/assets/javascripts/discourse/components/user-card-contents.js.es6 +++ b/app/assets/javascripts/discourse/components/user-card-contents.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { alias, gte, and, gt, not, or } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import Component from "@ember/component"; import { default as computed, observes @@ -9,214 +13,196 @@ import CanCheckEmails from "discourse/mixins/can-check-emails"; import CardContentsBase from "discourse/mixins/card-contents-base"; import CleansUp from "discourse/mixins/cleans-up"; import { prioritizeNameInUx } from "discourse/lib/settings"; +import { set } from "@ember/object"; -export default Ember.Component.extend( - CardContentsBase, - CanCheckEmails, - CleansUp, - { - elementId: "user-card", - triggeringLinkClass: "mention", - classNameBindings: [ - "visible:show", - "showBadges", - "user.card_background::no-bg", - "isFixed:fixed", - "usernameClass" - ], - allowBackgrounds: setting("allow_profile_backgrounds"), - showBadges: setting("enable_badges"), +export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { + elementId: "user-card", + triggeringLinkClass: "mention", + classNameBindings: [ + "visible:show", + "showBadges", + "user.card_background::no-bg", + "isFixed:fixed", + "usernameClass" + ], + allowBackgrounds: setting("allow_profile_backgrounds"), + showBadges: setting("enable_badges"), - postStream: Ember.computed.alias("topic.postStream"), - enoughPostsForFiltering: Ember.computed.gte("topicPostCount", 2), - showFilter: Ember.computed.and( - "viewingTopic", - "postStream.hasNoFilters", - "enoughPostsForFiltering" - ), - showName: propertyNotEqual("user.name", "user.username"), - hasUserFilters: Ember.computed.gt("postStream.userFilters.length", 0), - showMoreBadges: Ember.computed.gt("moreBadgesCount", 0), - showDelete: Ember.computed.and( - "viewingAdmin", - "showName", - "user.canBeDeleted" - ), - linkWebsite: Ember.computed.not("user.isBasic"), - hasLocationOrWebsite: Ember.computed.or( - "user.location", - "user.website_name" - ), - isSuspendedOrHasBio: Ember.computed.or( - "user.suspend_reason", - "user.bio_cooked" - ), - showCheckEmail: Ember.computed.and("user.staged", "canCheckEmails"), + postStream: alias("topic.postStream"), + enoughPostsForFiltering: gte("topicPostCount", 2), + showFilter: and( + "viewingTopic", + "postStream.hasNoFilters", + "enoughPostsForFiltering" + ), + showName: propertyNotEqual("user.name", "user.username"), + hasUserFilters: gt("postStream.userFilters.length", 0), + showMoreBadges: gt("moreBadgesCount", 0), + showDelete: and("viewingAdmin", "showName", "user.canBeDeleted"), + linkWebsite: not("user.isBasic"), + hasLocationOrWebsite: or("user.location", "user.website_name"), + isSuspendedOrHasBio: or("user.suspend_reason", "user.bio_cooked"), + showCheckEmail: and("user.staged", "canCheckEmails"), - user: null, + user: null, - // If inside a topic - topicPostCount: null, + // If inside a topic + topicPostCount: null, - @computed("user.staff") - staff: isStaff => (isStaff ? "staff" : ""), + @computed("user.staff") + staff: isStaff => (isStaff ? "staff" : ""), - @computed("user.trust_level") - newUser: trustLevel => (trustLevel === 0 ? "new-user" : ""), + @computed("user.trust_level") + newUser: trustLevel => (trustLevel === 0 ? "new-user" : ""), - @computed("user.name") - nameFirst(name) { - return prioritizeNameInUx(name, this.siteSettings); - }, + @computed("user.name") + nameFirst(name) { + return prioritizeNameInUx(name, this.siteSettings); + }, - @computed("username") - usernameClass: username => (username ? `user-card-${username}` : ""), + @computed("username") + usernameClass: username => (username ? `user-card-${username}` : ""), - @computed("username", "topicPostCount") - togglePostsLabel(username, count) { - return I18n.t("topic.filter_to", { username, count }); - }, + @computed("username", "topicPostCount") + togglePostsLabel(username, count) { + return I18n.t("topic.filter_to", { username, count }); + }, - @computed("user.user_fields.@each.value") - publicUserFields() { - const siteUserFields = this.site.get("user_fields"); - if (!Ember.isEmpty(siteUserFields)) { - const userFields = this.get("user.user_fields"); - return siteUserFields - .filterBy("show_on_user_card", true) - .sortBy("position") - .map(field => { - Ember.set(field, "dasherized_name", field.get("name").dasherize()); - const value = userFields ? userFields[field.get("id")] : null; - return Ember.isEmpty(value) - ? null - : Ember.Object.create({ value, field }); - }) - .compact(); - } - }, - - @computed("user.trust_level") - removeNoFollow(trustLevel) { - return trustLevel > 2 && !this.siteSettings.tl3_links_no_follow; - }, - - @computed("user.badge_count", "user.featured_user_badges.length") - moreBadgesCount: (badgeCount, badgeLength) => badgeCount - badgeLength, - - @computed("user.time_read", "user.recent_time_read") - showRecentTimeRead(timeRead, recentTimeRead) { - return timeRead !== recentTimeRead && recentTimeRead !== 0; - }, - - @computed("user.recent_time_read") - recentTimeRead(recentTimeReadSeconds) { - return durationTiny(recentTimeReadSeconds); - }, - - @computed("showRecentTimeRead", "user.time_read", "recentTimeRead") - timeReadTooltip(showRecent, timeRead, recentTimeRead) { - if (showRecent) { - return I18n.t("time_read_recently_tooltip", { - time_read: durationTiny(timeRead), - recent_time_read: recentTimeRead - }); - } else { - return I18n.t("time_read_tooltip", { - time_read: durationTiny(timeRead) - }); - } - }, - - @observes("user.card_background_upload_url") - addBackground() { - if (!this.allowBackgrounds) { - return; - } - - const thisElem = this.element; - if (!thisElem) { - return; - } - - const url = this.get("user.card_background_upload_url"); - const bg = Ember.isEmpty(url) - ? "" - : `url(${Discourse.getURLWithCDN(url)})`; - thisElem.style.backgroundImage = bg; - }, - - _showCallback(username, $target) { - this._positionCard($target); - this.setProperties({ visible: true, loading: true }); - - const args = { stats: false }; - args.include_post_count_for = this.get("topic.id"); - User.findByUsername(username, args) - .then(user => { - if (user.topic_post_count) { - this.set( - "topicPostCount", - user.topic_post_count[args.include_post_count_for] - ); - } - this.setProperties({ user }); + @computed("user.user_fields.@each.value") + publicUserFields() { + const siteUserFields = this.site.get("user_fields"); + if (!isEmpty(siteUserFields)) { + const userFields = this.get("user.user_fields"); + return siteUserFields + .filterBy("show_on_user_card", true) + .sortBy("position") + .map(field => { + set(field, "dasherized_name", field.get("name").dasherize()); + const value = userFields ? userFields[field.get("id")] : null; + return isEmpty(value) ? null : EmberObject.create({ value, field }); }) - .catch(() => this._close()) - .finally(() => this.set("loading", null)); - }, + .compact(); + } + }, - _close() { - this._super(...arguments); + @computed("user.trust_level") + removeNoFollow(trustLevel) { + return trustLevel > 2 && !this.siteSettings.tl3_links_no_follow; + }, - this.setProperties({ - user: null, - topicPostCount: null + @computed("user.badge_count", "user.featured_user_badges.length") + moreBadgesCount: (badgeCount, badgeLength) => badgeCount - badgeLength, + + @computed("user.time_read", "user.recent_time_read") + showRecentTimeRead(timeRead, recentTimeRead) { + return timeRead !== recentTimeRead && recentTimeRead !== 0; + }, + + @computed("user.recent_time_read") + recentTimeRead(recentTimeReadSeconds) { + return durationTiny(recentTimeReadSeconds); + }, + + @computed("showRecentTimeRead", "user.time_read", "recentTimeRead") + timeReadTooltip(showRecent, timeRead, recentTimeRead) { + if (showRecent) { + return I18n.t("time_read_recently_tooltip", { + time_read: durationTiny(timeRead), + recent_time_read: recentTimeRead }); - }, + } else { + return I18n.t("time_read_tooltip", { + time_read: durationTiny(timeRead) + }); + } + }, - cleanUp() { + @observes("user.card_background_upload_url") + addBackground() { + if (!this.allowBackgrounds) { + return; + } + + const thisElem = this.element; + if (!thisElem) { + return; + } + + const url = this.get("user.card_background_upload_url"); + const bg = isEmpty(url) ? "" : `url(${Discourse.getURLWithCDN(url)})`; + thisElem.style.backgroundImage = bg; + }, + + _showCallback(username, $target) { + this._positionCard($target); + this.setProperties({ visible: true, loading: true }); + + const args = { stats: false }; + args.include_post_count_for = this.get("topic.id"); + User.findByUsername(username, args) + .then(user => { + if (user.topic_post_count) { + this.set( + "topicPostCount", + user.topic_post_count[args.include_post_count_for] + ); + } + this.setProperties({ user }); + }) + .catch(() => this._close()) + .finally(() => this.set("loading", null)); + }, + + _close() { + this._super(...arguments); + + this.setProperties({ + user: null, + topicPostCount: null + }); + }, + + cleanUp() { + this._close(); + }, + + actions: { + close() { this._close(); }, - actions: { - close() { - this._close(); - }, + composePM(user, post) { + this._close(); - composePM(user, post) { - this._close(); + Ember.getOwner(this) + .lookup("router:main") + .send("composePrivateMessage", user, post); + }, - Ember.getOwner(this) - .lookup("router:main") - .send("composePrivateMessage", user, post); - }, + cancelFilter() { + const postStream = this.postStream; + postStream.cancelFilter(); + postStream.refresh(); + this._close(); + }, - cancelFilter() { - const postStream = this.postStream; - postStream.cancelFilter(); - postStream.refresh(); - this._close(); - }, + togglePosts() { + this.togglePosts(this.user); + this._close(); + }, - togglePosts() { - this.togglePosts(this.user); - this._close(); - }, + deleteUser() { + this.user.delete(); + this._close(); + }, - deleteUser() { - this.user.delete(); - this._close(); - }, + showUser(username) { + this.showUser(username); + this._close(); + }, - showUser(username) { - this.showUser(username); - this._close(); - }, - - checkEmail(user) { - user.checkEmail(); - } + checkEmail(user) { + user.checkEmail(); } } -); +}); diff --git a/app/assets/javascripts/discourse/components/user-field.js.es6 b/app/assets/javascripts/discourse/components/user-field.js.es6 index 1585e9a3a5..b54cbafd0a 100644 --- a/app/assets/javascripts/discourse/components/user-field.js.es6 +++ b/app/assets/javascripts/discourse/components/user-field.js.es6 @@ -1,12 +1,24 @@ +import Component from "@ember/component"; import { fmt } from "discourse/lib/computed"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ - classNameBindings: [":user-field", "field.field_type"], +export default Component.extend({ + classNameBindings: [":user-field", "field.field_type", "customFieldClass"], layoutName: fmt("field.field_type", "components/user-fields/%@"), @computed noneLabel() { return "user_fields.none"; + }, + + @computed("field.name") + customFieldClass(fieldName) { + if (fieldName) { + fieldName = fieldName + .replace(/\s+/g, "-") + .replace(/[!\"#$%&'\(\)\*\+,\.\/:;<=>\?\@\[\\\]\^`\{\|\}~]/g, "") + .toLowerCase(); + return fieldName && `user-field-${fieldName}`; + } } }); diff --git a/app/assets/javascripts/discourse/components/user-flag-percentage.js.es6 b/app/assets/javascripts/discourse/components/user-flag-percentage.js.es6 index 874f19c7bb..5c24fb70af 100644 --- a/app/assets/javascripts/discourse/components/user-flag-percentage.js.es6 +++ b/app/assets/javascripts/discourse/components/user-flag-percentage.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("percentage") diff --git a/app/assets/javascripts/discourse/components/user-info.js.es6 b/app/assets/javascripts/discourse/components/user-info.js.es6 index 21a1347775..5873829a25 100644 --- a/app/assets/javascripts/discourse/components/user-info.js.es6 +++ b/app/assets/javascripts/discourse/components/user-info.js.es6 @@ -1,3 +1,5 @@ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; import { userPath } from "discourse/lib/url"; @@ -5,7 +7,7 @@ export function normalize(name) { return name.replace(/[\-\_ \.]/g, "").toLowerCase(); } -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [":user-info", "size"], attributeBindings: ["data-username"], size: "small", @@ -15,10 +17,10 @@ export default Ember.Component.extend({ return userPath(username); }, - "data-username": Ember.computed.alias("user.username"), + "data-username": alias("user.username"), // TODO: In later ember releases `hasBlock` works without this - hasBlock: Ember.computed.alias("template"), + hasBlock: alias("template"), @computed("user.name", "user.username") name(name, username) { diff --git a/app/assets/javascripts/discourse/components/user-link.js.es6 b/app/assets/javascripts/discourse/components/user-link.js.es6 index 7b86bed4fd..6ea395e5f0 100644 --- a/app/assets/javascripts/discourse/components/user-link.js.es6 +++ b/app/assets/javascripts/discourse/components/user-link.js.es6 @@ -1,6 +1,8 @@ -export default Ember.Component.extend({ +import { alias } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ tagName: "a", attributeBindings: ["href", "data-user-card"], - href: Ember.computed.alias("user.path"), - "data-user-card": Ember.computed.alias("user.username") + href: alias("user.path"), + "data-user-card": alias("user.username") }); diff --git a/app/assets/javascripts/discourse/components/user-selector.js.es6 b/app/assets/javascripts/discourse/components/user-selector.js.es6 index 2cc95441ed..772777543c 100644 --- a/app/assets/javascripts/discourse/components/user-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/user-selector.js.es6 @@ -1,3 +1,4 @@ +import { isEmpty } from "@ember/utils"; import { on, observes } from "ember-addons/ember-computed-decorators"; import TextField from "discourse/components/text-field"; import userSearch from "discourse/lib/user-search"; @@ -130,7 +131,7 @@ export default TextField.extend({ // THIS IS A HUGE HACK TO SUPPORT CLEARING THE INPUT @observes("usernames") _clearInput() { - if (arguments.length > 1 && Ember.isEmpty(this.usernames)) { + if (arguments.length > 1 && isEmpty(this.usernames)) { $(this.element) .parent() .find("a") diff --git a/app/assets/javascripts/discourse/components/user-stat.js.es6 b/app/assets/javascripts/discourse/components/user-stat.js.es6 index 879198734c..1f3fe86644 100644 --- a/app/assets/javascripts/discourse/components/user-stat.js.es6 +++ b/app/assets/javascripts/discourse/components/user-stat.js.es6 @@ -1,6 +1,8 @@ -export default Ember.Component.extend({ +import { equal } from "@ember/object/computed"; +import Component from "@ember/component"; +export default Component.extend({ classNames: ["user-stat"], type: "number", - isNumber: Ember.computed.equal("type", "number"), - isDuration: Ember.computed.equal("type", "duration") + isNumber: equal("type", "number"), + isDuration: equal("type", "duration") }); diff --git a/app/assets/javascripts/discourse/components/user-stream-item.js.es6 b/app/assets/javascripts/discourse/components/user-stream-item.js.es6 index 332e16520d..f0c5ca36e5 100644 --- a/app/assets/javascripts/discourse/components/user-stream-item.js.es6 +++ b/app/assets/javascripts/discourse/components/user-stream-item.js.es6 @@ -1,7 +1,8 @@ +import Component from "@ember/component"; import { propertyEqual } from "discourse/lib/computed"; import { actionDescription } from "discourse/widgets/post-small-action"; -export default Ember.Component.extend({ +export default Component.extend({ classNameBindings: [ ":user-stream-item", ":item", // DEPRECATED: 'item' class diff --git a/app/assets/javascripts/discourse/components/user-stream.js.es6 b/app/assets/javascripts/discourse/components/user-stream.js.es6 index 7054358457..79543dd394 100644 --- a/app/assets/javascripts/discourse/components/user-stream.js.es6 +++ b/app/assets/javascripts/discourse/components/user-stream.js.es6 @@ -1,3 +1,5 @@ +import { schedule } from "@ember/runloop"; +import Component from "@ember/component"; import LoadMore from "discourse/mixins/load-more"; import ClickTrack from "discourse/lib/click-track"; import Post from "discourse/models/post"; @@ -5,9 +7,10 @@ import DiscourseURL from "discourse/lib/url"; import Draft from "discourse/models/draft"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { getOwner } from "discourse-common/lib/get-owner"; +import { on } from "@ember/object/evented"; -export default Ember.Component.extend(LoadMore, { - _initialize: function() { +export default Component.extend(LoadMore, { + _initialize: on("init", function() { const filter = this.get("stream.filter"); if (filter) { this.set("classNames", [ @@ -15,17 +18,17 @@ export default Ember.Component.extend(LoadMore, { "filter-" + filter.toString().replace(",", "-") ]); } - }.on("init"), + }), loading: false, eyelineSelector: ".user-stream .item", classNames: ["user-stream"], _scrollTopOnModelChange: function() { - Ember.run.schedule("afterRender", () => $(document).scrollTop(0)); + schedule("afterRender", () => $(document).scrollTop(0)); }.observes("stream.user.id"), - _inserted: function() { + _inserted: on("didInsertElement", function() { this.bindScrolling({ name: "user-stream-view" }); $(window).on("resize.discourse-on-scroll", () => this.scrolled()); @@ -38,17 +41,17 @@ export default Ember.Component.extend(LoadMore, { $(this.element).on("click.discourse-redirect", ".excerpt a", function(e) { return ClickTrack.trackClick(e); }); - }.on("didInsertElement"), + }), // This view is being removed. Shut down operations - _destroyed: function() { + _destroyed: on("willDestroyElement", function() { this.unbindScrolling("user-stream-view"); $(window).unbind("resize.discourse-on-scroll"); $(this.element).off("click.details-disabled", "details.disabled"); // Unbind link tracking $(this.element).off("click.discourse-redirect", ".excerpt a"); - }.on("willDestroyElement"), + }), actions: { removeBookmark(userAction) { diff --git a/app/assets/javascripts/discourse/components/user-summary-category-search.js.es6 b/app/assets/javascripts/discourse/components/user-summary-category-search.js.es6 index 86def06ee1..5206a83988 100644 --- a/app/assets/javascripts/discourse/components/user-summary-category-search.js.es6 +++ b/app/assets/javascripts/discourse/components/user-summary-category-search.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("user", "category") diff --git a/app/assets/javascripts/discourse/components/user-summary-section.js.es6 b/app/assets/javascripts/discourse/components/user-summary-section.js.es6 index b5deb64dc4..d566ee18ab 100644 --- a/app/assets/javascripts/discourse/components/user-summary-section.js.es6 +++ b/app/assets/javascripts/discourse/components/user-summary-section.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ classNames: ["top-sub-section"] }); diff --git a/app/assets/javascripts/discourse/components/user-summary-topic.js.es6 b/app/assets/javascripts/discourse/components/user-summary-topic.js.es6 index 145b770e51..790c675e49 100644 --- a/app/assets/javascripts/discourse/components/user-summary-topic.js.es6 +++ b/app/assets/javascripts/discourse/components/user-summary-topic.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "li" }); diff --git a/app/assets/javascripts/discourse/components/user-summary-topics-list.js.es6 b/app/assets/javascripts/discourse/components/user-summary-topics-list.js.es6 index 5035daa2a7..39970994da 100644 --- a/app/assets/javascripts/discourse/components/user-summary-topics-list.js.es6 +++ b/app/assets/javascripts/discourse/components/user-summary-topics-list.js.es6 @@ -1,9 +1,10 @@ +import Component from "@ember/component"; import computed from "ember-addons/ember-computed-decorators"; // should be kept in sync with 'UserSummary::MAX_SUMMARY_RESULTS' const MAX_SUMMARY_RESULTS = 6; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", @computed("items.length") diff --git a/app/assets/javascripts/discourse/components/user-summary-user.js.es6 b/app/assets/javascripts/discourse/components/user-summary-user.js.es6 index 145b770e51..790c675e49 100644 --- a/app/assets/javascripts/discourse/components/user-summary-user.js.es6 +++ b/app/assets/javascripts/discourse/components/user-summary-user.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; +export default Component.extend({ tagName: "li" }); diff --git a/app/assets/javascripts/discourse/components/watch-read.js.es6 b/app/assets/javascripts/discourse/components/watch-read.js.es6 index 68b1d1f480..16cc583f4f 100644 --- a/app/assets/javascripts/discourse/components/watch-read.js.es6 +++ b/app/assets/javascripts/discourse/components/watch-read.js.es6 @@ -1,6 +1,7 @@ +import Component from "@ember/component"; import isElementInViewport from "discourse/lib/is-element-in-viewport"; -export default Ember.Component.extend({ +export default Component.extend({ didInsertElement() { this._super(...arguments); const currentUser = this.currentUser; diff --git a/app/assets/javascripts/discourse/controllers/about.js.es6 b/app/assets/javascripts/discourse/controllers/about.js.es6 index f17aac609b..85f26757ae 100644 --- a/app/assets/javascripts/discourse/controllers/about.js.es6 +++ b/app/assets/javascripts/discourse/controllers/about.js.es6 @@ -1,7 +1,9 @@ +import { gt } from "@ember/object/computed"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - faqOverriden: Ember.computed.gt("siteSettings.faq_url.length", 0), +export default Controller.extend({ + faqOverriden: gt("siteSettings.faq_url.length", 0), @computed contactInfo() { diff --git a/app/assets/javascripts/discourse/controllers/account-created-edit-email.js.es6 b/app/assets/javascripts/discourse/controllers/account-created-edit-email.js.es6 index b22fd6de9a..1002a90752 100644 --- a/app/assets/javascripts/discourse/controllers/account-created-edit-email.js.es6 +++ b/app/assets/javascripts/discourse/controllers/account-created-edit-email.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { changeEmail } from "discourse/lib/user-activation"; import computed from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ accountCreated: null, newEmail: null, diff --git a/app/assets/javascripts/discourse/controllers/account-created-index.js.es6 b/app/assets/javascripts/discourse/controllers/account-created-index.js.es6 index ed822d3d3b..00d381a080 100644 --- a/app/assets/javascripts/discourse/controllers/account-created-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/account-created-index.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import { resendActivationEmail } from "discourse/lib/user-activation"; -export default Ember.Controller.extend({ +export default Controller.extend({ actions: { sendActivationEmail() { resendActivationEmail(this.get("accountCreated.username")).then(() => { diff --git a/app/assets/javascripts/discourse/controllers/activation-edit.js.es6 b/app/assets/javascripts/discourse/controllers/activation-edit.js.es6 index ebe73984d0..8fc90f6cf0 100644 --- a/app/assets/javascripts/discourse/controllers/activation-edit.js.es6 +++ b/app/assets/javascripts/discourse/controllers/activation-edit.js.es6 @@ -1,10 +1,12 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { extractError } from "discourse/lib/ajax-error"; import { changeEmail } from "discourse/lib/user-activation"; -export default Ember.Controller.extend(ModalFunctionality, { - login: Ember.inject.controller(), +export default Controller.extend(ModalFunctionality, { + login: inject(), currentEmail: null, newEmail: null, diff --git a/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6 b/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6 index 13c3927d4a..83883ca5aa 100644 --- a/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6 +++ b/app/assets/javascripts/discourse/controllers/add-post-notice.js.es6 @@ -1,8 +1,10 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import computed from "ember-addons/ember-computed-decorators"; import { cookAsync } from "discourse/lib/text"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { post: null, resolve: null, reject: null, @@ -12,7 +14,7 @@ export default Ember.Controller.extend(ModalFunctionality, { @computed("saving", "notice") disabled(saving, notice) { - return saving || Ember.isEmpty(notice); + return saving || isEmpty(notice); }, onShow() { diff --git a/app/assets/javascripts/discourse/controllers/application.js.es6 b/app/assets/javascripts/discourse/controllers/application.js.es6 index 7cd2898bf1..610e745e64 100644 --- a/app/assets/javascripts/discourse/controllers/application.js.es6 +++ b/app/assets/javascripts/discourse/controllers/application.js.es6 @@ -1,10 +1,12 @@ +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { isAppWebview, isiOSPWA } from "discourse/lib/utilities"; -export default Ember.Controller.extend({ +export default Controller.extend({ showTop: true, showFooter: false, - router: Ember.inject.service(), + router: service(), @computed canSignUp() { diff --git a/app/assets/javascripts/discourse/controllers/associate-account-confirm.js.es6 b/app/assets/javascripts/discourse/controllers/associate-account-confirm.js.es6 index e9685e0cf9..e138dc71db 100644 --- a/app/assets/javascripts/discourse/controllers/associate-account-confirm.js.es6 +++ b/app/assets/javascripts/discourse/controllers/associate-account-confirm.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { actions: { finishConnect() { ajax({ diff --git a/app/assets/javascripts/discourse/controllers/auth-token.js.es6 b/app/assets/javascripts/discourse/controllers/auth-token.js.es6 index 1d933fb191..a24f6a53b1 100644 --- a/app/assets/javascripts/discourse/controllers/auth-token.js.es6 +++ b/app/assets/javascripts/discourse/controllers/auth-token.js.es6 @@ -1,8 +1,10 @@ +import { next } from "@ember/runloop"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; import { userPath } from "discourse/lib/url"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { expanded: false, onShow() { @@ -23,7 +25,7 @@ export default Ember.Controller.extend(ModalFunctionality, { highlightSecure() { this.send("closeModal"); - Ember.run.next(() => { + next(() => { const $prefPasswordDiv = $(".pref-password"); $prefPasswordDiv.addClass("highlighted"); diff --git a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 index 624eb3ab22..1a23033580 100644 --- a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 @@ -1,10 +1,11 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; import { allowsImages } from "discourse/lib/utilities"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @computed( "selected", "user.system_avatar_upload_id", diff --git a/app/assets/javascripts/discourse/controllers/badges/index.js.es6 b/app/assets/javascripts/discourse/controllers/badges/index.js.es6 index eb36dbe521..c1c4d8db27 100644 --- a/app/assets/javascripts/discourse/controllers/badges/index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/index.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ @computed("model") badgeGroups(model) { var sorted = _.sortBy(model, function(badge) { diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index d3411ae6d3..d1093c13bc 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -1,15 +1,18 @@ +import { inject } from "@ember/controller"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; +import Badge from "discourse/models/badge"; import UserBadge from "discourse/models/user-badge"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -import BadgeSelectController from "discourse/mixins/badge-select-controller"; -export default Ember.Controller.extend(BadgeSelectController, { +export default Controller.extend({ queryParams: ["username"], noMoreBadges: false, userBadges: null, - application: Ember.inject.controller(), + application: inject(), hiddenSetTitle: true, @computed("userBadgesAll") @@ -17,6 +20,16 @@ export default Ember.Controller.extend(BadgeSelectController, { return userBadgesAll.filterBy("badge.allow_title", true); }, + @computed("filteredList") + selectableUserBadges(filteredList) { + return [ + EmberObject.create({ + badge: Badge.create({ name: I18n.t("badges.none") }) + }), + ...filteredList.uniqBy("badge.name") + ]; + }, + @computed("username") user(username) { if (username) { diff --git a/app/assets/javascripts/discourse/controllers/basic-modal-body.js.es6 b/app/assets/javascripts/discourse/controllers/basic-modal-body.js.es6 index 1ee99a7549..03d95d5cb2 100644 --- a/app/assets/javascripts/discourse/controllers/basic-modal-body.js.es6 +++ b/app/assets/javascripts/discourse/controllers/basic-modal-body.js.es6 @@ -1,5 +1,6 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { modal: null }); diff --git a/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6 b/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6 index f34195bf8a..0d8ac58ca2 100644 --- a/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6 +++ b/app/assets/javascripts/discourse/controllers/bulk-notification-level.js.es6 @@ -1,9 +1,12 @@ +import { empty } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { topicLevels } from "discourse/lib/notification-levels"; // Support for changing the notification level of various topics -export default Ember.Controller.extend({ - topicBulkActions: Ember.inject.controller(), +export default Controller.extend({ + topicBulkActions: inject(), notificationLevelId: null, @computed @@ -17,7 +20,7 @@ export default Ember.Controller.extend({ }); }, - disabled: Ember.computed.empty("notificationLevelId"), + disabled: empty("notificationLevelId"), actions: { changeNotificationLevel() { diff --git a/app/assets/javascripts/discourse/controllers/change-owner.js.es6 b/app/assets/javascripts/discourse/controllers/change-owner.js.es6 index 0738db8740..10ed05c04f 100644 --- a/app/assets/javascripts/discourse/controllers/change-owner.js.es6 +++ b/app/assets/javascripts/discourse/controllers/change-owner.js.es6 @@ -1,28 +1,24 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import { next } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import DiscourseURL from "discourse/lib/url"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(ModalFunctionality, { - topicController: Ember.inject.controller("topic"), +export default Controller.extend(ModalFunctionality, { + topicController: inject("topic"), saving: false, new_user: null, - selectedPostsCount: Ember.computed.alias( - "topicController.selectedPostsCount" - ), - selectedPostsUsername: Ember.computed.alias( - "topicController.selectedPostsUsername" - ), + selectedPostsCount: alias("topicController.selectedPostsCount"), + selectedPostsUsername: alias("topicController.selectedPostsUsername"), @computed("saving", "new_user") buttonDisabled(saving, newUser) { - return saving || Ember.isEmpty(newUser); - }, - - @computed("saving") - buttonTitle(saving) { - return saving ? I18n.t("saving") : I18n.t("topic.change_owner.action"); + return saving || isEmpty(newUser); }, onShow() { @@ -51,7 +47,7 @@ export default Ember.Controller.extend(ModalFunctionality, { if (this.get("topicController.multiSelect")) { this.topicController.send("toggleMultiSelect"); } - Ember.run.next(() => + next(() => DiscourseURL.routeTo(this.get("topicController.model.url")) ); }, diff --git a/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6 b/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6 index 6d64eb32e8..9a29c747d7 100644 --- a/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6 +++ b/app/assets/javascripts/discourse/controllers/change-timestamp.js.es6 @@ -1,11 +1,15 @@ +import { isEmpty } from "@ember/utils"; +import { next } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import computed from "ember-addons/ember-computed-decorators"; import DiscourseURL from "discourse/lib/url"; import Topic from "discourse/models/topic"; // Modal related to changing the timestamp of posts -export default Ember.Controller.extend(ModalFunctionality, { - topicController: Ember.inject.controller("topic"), +export default Controller.extend(ModalFunctionality, { + topicController: inject("topic"), saving: false, date: "", time: "", @@ -28,7 +32,7 @@ export default Ember.Controller.extend(ModalFunctionality, { @computed("saving", "date", "validTimestamp") buttonDisabled(saving, date, validTimestamp) { if (saving || validTimestamp) return true; - return Ember.isEmpty(date); + return isEmpty(date); }, onShow() { @@ -45,7 +49,7 @@ export default Ember.Controller.extend(ModalFunctionality, { .then(() => { this.send("closeModal"); this.setProperties({ date: "", time: "", saving: false }); - Ember.run.next(() => DiscourseURL.routeTo(topic.url)); + next(() => DiscourseURL.routeTo(topic.url)); }) .catch(() => this.flash(I18n.t("topic.change_timestamp.error"), "alert-error") diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index b96051e906..df26812280 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -1,3 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import { and, or, alias, reads } from "@ember/object/computed"; +import { debounce } from "@ember/runloop"; +import { inject as service } from "@ember/service"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import DiscourseURL from "discourse/lib/url"; import Quote from "discourse/lib/quote"; import Draft from "discourse/models/draft"; @@ -18,6 +24,7 @@ import { import { emojiUnescape } from "discourse/lib/text"; import { shortDate } from "discourse/lib/formatter"; import { SAVE_LABELS, SAVE_ICONS } from "discourse/models/composer"; +import { Promise } from "rsvp"; function loadDraft(store, opts) { opts = opts || {}; @@ -39,26 +46,21 @@ function loadDraft(store, opts) { ((draft.title && draft.title !== "") || (draft.reply && draft.reply !== "")) ) { const composer = store.createRecord("composer"); + const serializedFields = Composer.serializedFieldsForDraft(); - composer.open({ + let attrs = { draftKey, draftSequence, - action: draft.action, - title: draft.title, - categoryId: draft.categoryId || opts.categoryId, - postId: draft.postId, - archetypeId: draft.archetypeId, - reply: draft.reply, - metaData: draft.metaData, - usernames: draft.usernames, draft: true, - composerState: Composer.DRAFT, - composerTime: draft.composerTime, - typingTime: draft.typingTime, - whisper: draft.whisper, - tags: draft.tags, - noBump: draft.noBump + composerState: Composer.DRAFT + }; + + serializedFields.forEach(f => { + attrs[f] = draft[f] || opts[f]; }); + + composer.open(attrs); + return composer; } } @@ -79,18 +81,10 @@ export function addPopupMenuOptionsCallback(callback) { _popupMenuOptionsCallbacks.push(callback); } -export default Ember.Controller.extend({ - topicController: Ember.inject.controller("topic"), - router: Ember.inject.service(), +export default Controller.extend({ + topicController: inject("topic"), + router: service(), - replyAsNewTopicDraft: Ember.computed.equal( - "model.draftKey", - Composer.REPLY_AS_NEW_TOPIC_KEY - ), - replyAsNewPrivateMessageDraft: Ember.computed.equal( - "model.draftKey", - Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY - ), checkedMessages: false, messageCount: null, showEditReason: false, @@ -103,9 +97,9 @@ export default Ember.Controller.extend({ topic: null, linkLookup: null, showPreview: true, - forcePreview: Ember.computed.and("site.mobileView", "showPreview"), - whisperOrUnlistTopic: Ember.computed.or("isWhispering", "model.unlistTopic"), - categories: Ember.computed.alias("site.categoriesList"), + forcePreview: and("site.mobileView", "showPreview"), + whisperOrUnlistTopic: or("isWhispering", "model.unlistTopic"), + categories: alias("site.categoriesList"), @on("init") _setupPreview() { @@ -187,7 +181,7 @@ export default Ember.Controller.extend({ } }), - topicModel: Ember.computed.alias("topicController.model"), + topicModel: alias("topicController.model"), @computed("model.canEditTitle", "model.creatingPrivateMessage") canEditTags(canEditTitle, creatingPrivateMessage) { @@ -199,9 +193,19 @@ export default Ember.Controller.extend({ ); }, - isStaffUser: Ember.computed.reads("currentUser.staff"), + @computed("model.editingPost", "model.topic.details.can_edit") + disableCategoryChooser(editingPost, canEditTopic) { + return editingPost && !canEditTopic; + }, - canUnlistTopic: Ember.computed.and("model.creatingTopic", "isStaffUser"), + @computed("model.editingPost", "model.topic.canEditTags") + disableTagsChooser(editingPost, canEditTags) { + return editingPost && !canEditTags; + }, + + isStaffUser: reads("currentUser.staff"), + + canUnlistTopic: and("model.creatingTopic", "isStaffUser"), @computed("canWhisper", "replyingToWhisper") showWhisperToggle(canWhisper, replyingToWhisper) { @@ -215,7 +219,7 @@ export default Ember.Controller.extend({ ); }, - isWhispering: Ember.computed.or("replyingToWhisper", "model.whisper"), + isWhispering: or("replyingToWhisper", "model.whisper"), @computed("model.action", "isWhispering") saveIcon(action, isWhispering) { @@ -300,7 +304,7 @@ export default Ember.Controller.extend({ // We need exactly one user to issue a warning if ( - Ember.isEmpty(usernames) || + isEmpty(usernames) || usernames.split(",").length !== 1 || hasTargetGroups ) { @@ -439,8 +443,8 @@ export default Ember.Controller.extend({ this.closeAutocomplete(); if ( - Ember.isEmpty(this.get("model.reply")) && - Ember.isEmpty(this.get("model.title")) + isEmpty(this.get("model.reply")) && + isEmpty(this.get("model.title")) ) { this.close(); } else { @@ -589,7 +593,7 @@ export default Ember.Controller.extend({ } }, - disableSubmit: Ember.computed.or("model.loading", "isUploading"), + disableSubmit: or("model.loading", "isUploading"), save(force) { if (this.disableSubmit) return; @@ -682,20 +686,13 @@ export default Ember.Controller.extend({ } } - this.destroyDraft(); - this.close(); - this.appEvents.trigger("post-stream:refresh"); - return result; + return this.destroyDraft().then(() => { + this.close(); + this.appEvents.trigger("post-stream:refresh"); + return result; + }); } - // If user "created a new topic/post" or "replied as a new topic" successfully, remove the draft. - if ( - result.responseJson.action === "create_post" || - this.replyAsNewTopicDraft || - this.replyAsNewPrivateMessageDraft - ) { - this.destroyDraft(); - } if (this.get("model.editingPost")) { this.appEvents.trigger("post-stream:refresh", { id: parseInt(result.responseJson.id) @@ -726,7 +723,9 @@ export default Ember.Controller.extend({ }) .catch(error => { composer.set("disableDrafts", false); - this.appEvents.one("composer:will-open", () => bootbox.alert(error)); + if (error) { + this.appEvents.one("composer:will-open", () => bootbox.alert(error)); + } }); if ( @@ -747,21 +746,21 @@ export default Ember.Controller.extend({ // Notify the composer messages controller that a reply has been typed. Some // messages only appear after typing. checkReplyLength() { - if (!Ember.isEmpty("model.reply")) { + if (!isEmpty("model.reply")) { this.appEvents.trigger("composer:typed-reply"); } }, /** - Open the composer view + Open the composer view - @method open - @param {Object} opts Options for creating a post - @param {String} opts.action The action we're performing: edit, reply or createTopic - @param {Discourse.Post} [opts.post] The post we're replying to - @param {Discourse.Topic} [opts.topic] The topic we're replying to - @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making - **/ + @method open + @param {Object} opts Options for creating a post + @param {String} opts.action The action we're performing: edit, reply or createTopic + @param {Discourse.Post} [opts.post] The post we're replying to + @param {Discourse.Topic} [opts.topic] The topic we're replying to + @param {String} [opts.quote] If we're opening a reply from a quote, the quote we're making + **/ open(opts) { opts = opts || {}; @@ -786,11 +785,7 @@ export default Ember.Controller.extend({ }); // Scope the categories drop down to the category we opened the composer with. - if ( - opts.categoryId && - opts.draftKey !== "reply_as_new_topic" && - !opts.disableScopedCategory - ) { + if (opts.categoryId && !opts.disableScopedCategory) { const category = this.site.categories.findBy("id", opts.categoryId); if (category) { this.set("scopedCategoryId", opts.categoryId); @@ -807,7 +802,7 @@ export default Ember.Controller.extend({ composerModel = null; } - return new Ember.RSVP.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (composerModel && composerModel.replyDirty) { // If we're already open, we don't have to do anything if ( @@ -850,7 +845,6 @@ export default Ember.Controller.extend({ data.draft = undefined; return data; } - return this.confirmDraftAbandon(data); }) .then(data => { @@ -865,7 +859,9 @@ export default Ember.Controller.extend({ // otherwise, do the draft check async else if (!opts.draft && !opts.skipDraftCheck) { Draft.get(opts.draftKey) - .then(data => this.confirmDraftAbandon(data)) + .then(data => { + return this.confirmDraftAbandon(data); + }) .then(data => { if (data.draft) { opts.draft = data.draft; @@ -946,9 +942,11 @@ export default Ember.Controller.extend({ this.send("clearTopicDraft"); } - Draft.clear(key, this.get("model.draftSequence")).then(() => + return Draft.clear(key, this.get("model.draftSequence")).then(() => this.appEvents.trigger("draft:destroyed", key) ); + } else { + return Promise.resolve(); } }, @@ -965,7 +963,7 @@ export default Ember.Controller.extend({ } if (_checkDraftPopup) { - return new Ember.RSVP.Promise(resolve => { + return new Promise(resolve => { bootbox.dialog(I18n.t("drafts.abandon.confirm"), [ { label: I18n.t("drafts.abandon.no_value"), @@ -988,13 +986,16 @@ export default Ember.Controller.extend({ }, cancelComposer(differentDraft = false) { - return new Ember.RSVP.Promise(resolve => { + const keyPrefix = + this.model.action === "edit" ? "post.abandon_edit" : "post.abandon"; + + return new Promise(resolve => { if (this.get("model.hasMetaData") || this.get("model.replyDirty")) { - bootbox.dialog(I18n.t("post.abandon.confirm"), [ + bootbox.dialog(I18n.t(keyPrefix + ".confirm"), [ { label: differentDraft - ? I18n.t("post.abandon.no_save_draft") - : I18n.t("post.abandon.no_value"), + ? I18n.t(keyPrefix + ".no_save_draft") + : I18n.t(keyPrefix + ".no_value"), callback: () => { // cancel composer without destroying draft on new draft context if (differentDraft) { @@ -1005,24 +1006,26 @@ export default Ember.Controller.extend({ } }, { - label: I18n.t("post.abandon.yes_value"), + label: I18n.t(keyPrefix + ".yes_value"), class: "btn-danger", callback: result => { if (result) { - this.destroyDraft(); - this.model.clearState(); - this.close(); - resolve(); + this.destroyDraft().then(() => { + this.model.clearState(); + this.close(); + resolve(); + }); } } } ]); } else { // it is possible there is some sort of crazy draft with no body ... just give up on it - this.destroyDraft(); - this.model.clearState(); - this.close(); - resolve(); + this.destroyDraft().then(() => { + this.model.clearState(); + this.close(); + resolve(); + }); } }); }, @@ -1047,7 +1050,7 @@ export default Ember.Controller.extend({ @observes("model.reply", "model.title") _shouldSaveDraft() { - Ember.run.debounce(this, this._saveDraft, 2000); + debounce(this, this._saveDraft, 2000); }, @computed("model.categoryId", "lastValidatedAt") diff --git a/app/assets/javascripts/discourse/controllers/convert-to-public-topic.js.es6 b/app/assets/javascripts/discourse/controllers/convert-to-public-topic.js.es6 index 58ccfbcf88..2c08ff7884 100644 --- a/app/assets/javascripts/discourse/controllers/convert-to-public-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/convert-to-public-topic.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { publicCategoryId: null, saving: true, diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6 index 1c8ecb254a..beb87d2d3a 100644 --- a/app/assets/javascripts/discourse/controllers/create-account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { notEmpty, or, not } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { setting } from "discourse/lib/computed"; @@ -14,27 +18,27 @@ import UserFieldsValidation from "discourse/mixins/user-fields-validation"; import { userPath } from "discourse/lib/url"; import { findAll } from "discourse/models/login-method"; -export default Ember.Controller.extend( +export default Controller.extend( ModalFunctionality, PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, { - login: Ember.inject.controller(), + login: inject(), complete: false, - accountPasswordConfirm: 0, accountChallenge: 0, + accountHoneypot: 0, formSubmitted: false, rejectedEmails: Ember.A([]), prefilledUsername: null, userFields: null, isDeveloper: false, - hasAuthOptions: Ember.computed.notEmpty("authOptions"), + hasAuthOptions: notEmpty("authOptions"), canCreateLocal: setting("enable_local_logins"), - showCreateForm: Ember.computed.or("hasAuthOptions", "canCreateLocal"), + showCreateForm: or("hasAuthOptions", "canCreateLocal"), resetForm() { // We wrap the fields in a structure so we can assign a value @@ -76,7 +80,7 @@ export default Ember.Controller.extend( return false; }, - usernameRequired: Ember.computed.not("authOptions.omit_username"), + usernameRequired: not("authOptions.omit_username"), @computed fullnameRequired() { @@ -88,7 +92,7 @@ export default Ember.Controller.extend( @computed("authOptions.auth_provider") passwordRequired(authProvider) { - return Ember.isEmpty(authProvider); + return isEmpty(authProvider); }, @computed @@ -105,7 +109,7 @@ export default Ember.Controller.extend( @computed("accountEmail", "rejectedEmails.[]") emailValidation(email, rejectedEmails) { // If blank, fail without a reason - if (Ember.isEmpty(email)) { + if (isEmpty(email)) { return InputValidation.create({ failed: true }); @@ -173,7 +177,7 @@ export default Ember.Controller.extend( } if ( this.get("emailValidation.ok") && - (Ember.isEmpty(this.accountUsername) || this.get("authOptions.email")) + (isEmpty(this.accountUsername) || this.get("authOptions.email")) ) { // If email is valid and username has not been entered yet, // or email and username were filled automatically by 3rd parth auth, @@ -191,8 +195,16 @@ export default Ember.Controller.extend( @on("init") fetchConfirmationValue() { return ajax(userPath("hp.json")).then(json => { + this._challengeDate = new Date(); + // remove 30 seconds for jitter, make sure this works for at least + // 30 seconds so we don't have hard loops + this._challengeExpiry = parseInt(json.expires_in, 10) - 30; + if (this._challengeExpiry < 30) { + this._challengeExpiry = 30; + } + this.setProperties({ - accountPasswordConfirm: json.value, + accountHoneypot: json.value, accountChallenge: json.challenge .split("") .reverse() @@ -201,85 +213,100 @@ export default Ember.Controller.extend( }); }, + performAccountCreation() { + const attrs = this.getProperties( + "accountName", + "accountEmail", + "accountPassword", + "accountUsername", + "accountChallenge" + ); + + attrs["accountPasswordConfirm"] = this.accountHoneypot; + + const userFields = this.userFields; + const destinationUrl = this.get("authOptions.destination_url"); + + if (!isEmpty(destinationUrl)) { + $.cookie("destination_url", destinationUrl, { path: "/" }); + } + + // Add the userfields to the data + if (!isEmpty(userFields)) { + attrs.userFields = {}; + userFields.forEach( + f => (attrs.userFields[f.get("field.id")] = f.get("value")) + ); + } + + this.set("formSubmitted", true); + return Discourse.User.createAccount(attrs).then( + result => { + this.set("isDeveloper", false); + if (result.success) { + // invalidate honeypot + this._challengeExpiry = 1; + + // Trigger the browser's password manager using the hidden static login form: + const $hidden_login_form = $("#hidden-login-form"); + $hidden_login_form + .find("input[name=username]") + .val(attrs.accountUsername); + $hidden_login_form + .find("input[name=password]") + .val(attrs.accountPassword); + $hidden_login_form + .find("input[name=redirect]") + .val(userPath("account-created")); + $hidden_login_form.submit(); + } else { + this.flash( + result.message || I18n.t("create_account.failed"), + "error" + ); + if (result.is_developer) { + this.set("isDeveloper", true); + } + if ( + result.errors && + result.errors.email && + result.errors.email.length > 0 && + result.values + ) { + this.rejectedEmails.pushObject(result.values.email); + } + if ( + result.errors && + result.errors.password && + result.errors.password.length > 0 + ) { + this.rejectedPasswords.pushObject(attrs.accountPassword); + } + this.set("formSubmitted", false); + $.removeCookie("destination_url"); + } + }, + () => { + this.set("formSubmitted", false); + $.removeCookie("destination_url"); + return this.flash(I18n.t("create_account.failed"), "error"); + } + ); + }, + actions: { externalLogin(provider) { this.login.send("externalLogin", provider); }, createAccount() { - const attrs = this.getProperties( - "accountName", - "accountEmail", - "accountPassword", - "accountUsername", - "accountPasswordConfirm", - "accountChallenge" - ); - const userFields = this.userFields; - const destinationUrl = this.get("authOptions.destination_url"); - - if (!Ember.isEmpty(destinationUrl)) { - $.cookie("destination_url", destinationUrl, { path: "/" }); - } - - // Add the userfields to the data - if (!Ember.isEmpty(userFields)) { - attrs.userFields = {}; - userFields.forEach( - f => (attrs.userFields[f.get("field.id")] = f.get("value")) + if (new Date() - this._challengeDate > 1000 * this._challengeExpiry) { + this.fetchConfirmationValue().then(() => + this.performAccountCreation() ); + } else { + this.performAccountCreation(); } - - this.set("formSubmitted", true); - return Discourse.User.createAccount(attrs).then( - result => { - this.set("isDeveloper", false); - if (result.success) { - // Trigger the browser's password manager using the hidden static login form: - const $hidden_login_form = $("#hidden-login-form"); - $hidden_login_form - .find("input[name=username]") - .val(attrs.accountUsername); - $hidden_login_form - .find("input[name=password]") - .val(attrs.accountPassword); - $hidden_login_form - .find("input[name=redirect]") - .val(userPath("account-created")); - $hidden_login_form.submit(); - } else { - this.flash( - result.message || I18n.t("create_account.failed"), - "error" - ); - if (result.is_developer) { - this.set("isDeveloper", true); - } - if ( - result.errors && - result.errors.email && - result.errors.email.length > 0 && - result.values - ) { - this.rejectedEmails.pushObject(result.values.email); - } - if ( - result.errors && - result.errors.password && - result.errors.password.length > 0 - ) { - this.rejectedPasswords.pushObject(attrs.accountPassword); - } - this.set("formSubmitted", false); - $.removeCookie("destination_url"); - } - }, - () => { - this.set("formSubmitted", false); - $.removeCookie("destination_url"); - return this.flash(I18n.t("create_account.failed"), "error"); - } - ); } } } diff --git a/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6 b/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6 index 4ce4284c55..d286a37dab 100644 --- a/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery-sortable.js.es6 @@ -1,3 +1,6 @@ +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import DiscourseNavigation from "discourse/components/d-navigation"; // Just add query params here to have them automatically passed to topic list filters. @@ -16,23 +19,23 @@ export const queryParams = { // Basic controller options const controllerOpts = { - discoveryTopics: Ember.inject.controller("discovery/topics"), + discoveryTopics: inject("discovery/topics"), queryParams: Object.keys(queryParams) }; // Aliases for the values controllerOpts.queryParams.forEach( - p => (controllerOpts[p] = Ember.computed.alias(`discoveryTopics.${p}`)) + p => (controllerOpts[p] = alias(`discoveryTopics.${p}`)) ); -const Controller = Ember.Controller.extend(controllerOpts); +const SortableController = Controller.extend(controllerOpts); export const addDiscoveryQueryParam = function(p, opts) { queryParams[p] = opts; const cOpts = {}; - cOpts[p] = Ember.computed.alias(`discoveryTopics.${p}`); + cOpts[p] = alias(`discoveryTopics.${p}`); cOpts["queryParams"] = Object.keys(queryParams); - Controller.reopen(cOpts); + SortableController.reopen(cOpts); if (opts && opts.persisted) { DiscourseNavigation.reopen({ @@ -41,4 +44,4 @@ export const addDiscoveryQueryParam = function(p, opts) { } }; -export default Controller; +export default SortableController; diff --git a/app/assets/javascripts/discourse/controllers/discovery.js.es6 b/app/assets/javascripts/discourse/controllers/discovery.js.es6 index 858058e4b0..6345bb8aa2 100644 --- a/app/assets/javascripts/discourse/controllers/discovery.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery.js.es6 @@ -1,16 +1,19 @@ +import { alias, not } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import DiscourseURL from "discourse/lib/url"; -export default Ember.Controller.extend({ - discoveryTopics: Ember.inject.controller("discovery/topics"), - navigationCategory: Ember.inject.controller("navigation/category"), - application: Ember.inject.controller(), +export default Controller.extend({ + discoveryTopics: inject("discovery/topics"), + navigationCategory: inject("navigation/category"), + application: inject(), loading: false, - category: Ember.computed.alias("navigationCategory.category"), - noSubcategories: Ember.computed.alias("navigationCategory.noSubcategories"), + category: alias("navigationCategory.category"), + noSubcategories: alias("navigationCategory.noSubcategories"), - loadedAllItems: Ember.computed.not("discoveryTopics.model.canLoadMore"), + loadedAllItems: not("discoveryTopics.model.canLoadMore"), _showFooter: function() { this.set("application.showFooter", this.loadedAllItems); diff --git a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 index 2d8cc9f9ed..81542214ef 100644 --- a/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery/categories.js.es6 @@ -1,5 +1,8 @@ +import { reads } from "@ember/object/computed"; +import { inject } from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import DiscoveryController from "discourse/controllers/discovery"; +import { dasherize } from "@ember/string"; const subcategoryStyleComponentNames = { rows: "categories_only", @@ -9,12 +12,12 @@ const subcategoryStyleComponentNames = { }; export default DiscoveryController.extend({ - discovery: Ember.inject.controller(), + discovery: inject(), // this makes sure the composer isn't scoping to a specific category category: null, - canEdit: Ember.computed.reads("currentUser.staff"), + canEdit: reads("currentUser.staff"), @computed("model.categories.[].featuredTopics.length") latestTopicOnly() { @@ -42,7 +45,7 @@ export default DiscoveryController.extend({ parentCategory && style === "categories_and_latest_topics" ? "categories_only" : style; - return Ember.String.dasherize(componentName); + return dasherize(componentName); }, actions: { refresh() { diff --git a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 index c6443bd37e..447e2ead37 100644 --- a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 @@ -1,3 +1,5 @@ +import { alias, not, gt, empty, notEmpty, equal } from "@ember/object/computed"; +import { inject } from "@ember/controller"; import DiscoveryController from "discourse/controllers/discovery"; import { queryParams } from "discourse/controllers/discovery-sortable"; import BulkTopicSelection from "discourse/mixins/bulk-topic-selection"; @@ -8,16 +10,14 @@ import TopicList from "discourse/models/topic-list"; import computed from "ember-addons/ember-computed-decorators"; const controllerOpts = { - discovery: Ember.inject.controller(), - discoveryTopics: Ember.inject.controller("discovery/topics"), + discovery: inject(), + discoveryTopics: inject("discovery/topics"), period: null, - canStar: Ember.computed.alias("currentUser.id"), - showTopicPostBadges: Ember.computed.not("discoveryTopics.new"), - redirectedReason: Ember.computed.alias( - "currentUser.redirected_to_top.reason" - ), + canStar: alias("currentUser.id"), + showTopicPostBadges: not("discoveryTopics.new"), + redirectedReason: alias("currentUser.redirected_to_top.reason"), order: "default", ascending: false, @@ -117,16 +117,16 @@ const controllerOpts = { ); }, - hasTopics: Ember.computed.gt("model.topics.length", 0), - allLoaded: Ember.computed.empty("model.more_topics_url"), + hasTopics: gt("model.topics.length", 0), + allLoaded: empty("model.more_topics_url"), latest: endWith("model.filter", "latest"), new: endWith("model.filter", "new"), - top: Ember.computed.notEmpty("period"), - yearly: Ember.computed.equal("period", "yearly"), - quarterly: Ember.computed.equal("period", "quarterly"), - monthly: Ember.computed.equal("period", "monthly"), - weekly: Ember.computed.equal("period", "weekly"), - daily: Ember.computed.equal("period", "daily"), + top: notEmpty("period"), + yearly: equal("period", "yearly"), + quarterly: equal("period", "quarterly"), + monthly: equal("period", "monthly"), + weekly: equal("period", "weekly"), + daily: equal("period", "daily"), @computed("allLoaded", "model.topics.length") footerMessage(allLoaded, topicsLength) { diff --git a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 index 381292baaa..87c1378ffe 100644 --- a/app/assets/javascripts/discourse/controllers/edit-category.js.es6 +++ b/app/assets/javascripts/discourse/controllers/edit-category.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import DiscourseURL from "discourse/lib/url"; import { extractError } from "discourse/lib/ajax-error"; @@ -7,7 +9,7 @@ import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { selectedTab: null, saving: false, deleting: false, @@ -30,7 +32,7 @@ export default Ember.Controller.extend(ModalFunctionality, { @observes("model.description") changeSize() { - if (!Ember.isEmpty(this.get("model.description"))) { + if (!isEmpty(this.get("model.description"))) { this.set("modal.modalClass", "edit-category-modal full"); } else { this.set("modal.modalClass", "edit-category-modal small"); diff --git a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 index d90ca5cbd4..7dc26c632c 100644 --- a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js.es6 @@ -1,7 +1,10 @@ +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import TopicTimer from "discourse/models/topic-timer"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { setProperties } from "@ember/object"; export const CLOSE_STATUS_TYPE = "close"; export const OPEN_STATUS_TYPE = "open"; @@ -10,7 +13,7 @@ export const DELETE_STATUS_TYPE = "delete"; export const REMINDER_TYPE = "reminder"; export const BUMP_TYPE = "bump"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, isPublic: "true", @@ -76,7 +79,7 @@ export default Ember.Controller.extend(ModalFunctionality, { if (time) { this.send("closeModal"); - Ember.setProperties(this.topicTimer, { + setProperties(this.topicTimer, { execute_at: result.execute_at, duration: result.duration, category_id: result.category_id @@ -86,7 +89,7 @@ export default Ember.Controller.extend(ModalFunctionality, { } else { const topicTimer = this.isPublic === "true" ? "topic_timer" : "private_topic_timer"; - this.set(`model.${topicTimer}`, Ember.Object.create({})); + this.set(`model.${topicTimer}`, EmberObject.create({})); this.setProperties({ selection: null diff --git a/app/assets/javascripts/discourse/controllers/email-login.js.es6 b/app/assets/javascripts/discourse/controllers/email-login.js.es6 index d062144afe..78ab74f239 100644 --- a/app/assets/javascripts/discourse/controllers/email-login.js.es6 +++ b/app/assets/javascripts/discourse/controllers/email-login.js.es6 @@ -1,3 +1,4 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import { ajax } from "discourse/lib/ajax"; @@ -5,7 +6,7 @@ import DiscourseURL from "discourse/lib/url"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { getWebauthnCredential } from "discourse/lib/webauthn"; -export default Ember.Controller.extend({ +export default Controller.extend({ lockImageUrl: Discourse.getURL("/images/lock.svg"), @computed("model") diff --git a/app/assets/javascripts/discourse/controllers/exception.js.es6 b/app/assets/javascripts/discourse/controllers/exception.js.es6 index 6b341b155a..7967f2d24a 100644 --- a/app/assets/javascripts/discourse/controllers/exception.js.es6 +++ b/app/assets/javascripts/discourse/controllers/exception.js.es6 @@ -1,3 +1,6 @@ +import { equal, gte, none, alias } from "@ember/object/computed"; +import { schedule } from "@ember/runloop"; +import Controller from "@ember/controller"; import { on, default as computed @@ -26,7 +29,7 @@ const ButtonBackBright = { }; // The controller for the nice error page -export default Ember.Controller.extend({ +export default Controller.extend({ thrown: null, lastTransition: null, @@ -41,10 +44,10 @@ export default Ember.Controller.extend({ return false; }, - isNotFound: Ember.computed.equal("thrown.status", 404), - isForbidden: Ember.computed.equal("thrown.status", 403), - isServer: Ember.computed.gte("thrown.status", 500), - isUnknown: Ember.computed.none("isNetwork", "isServer"), + isNotFound: equal("thrown.status", 404), + isForbidden: equal("thrown.status", 403), + isServer: gte("thrown.status", 500), + isUnknown: none("isNetwork", "isServer"), // TODO // make ajax requests to /srv/status with exponential backoff @@ -73,7 +76,7 @@ export default Ember.Controller.extend({ } }, - requestUrl: Ember.computed.alias("thrown.requestedUrl"), + requestUrl: alias("thrown.requestedUrl"), @computed("networkFixed", "isNetwork", "isServer", "isUnknown") desc() { @@ -112,7 +115,7 @@ export default Ember.Controller.extend({ tryLoading() { this.set("loading", true); - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { this.lastTransition.retry(); this.set("loading", false); }); diff --git a/app/assets/javascripts/discourse/controllers/explain-reviewable.js.es6 b/app/assets/javascripts/discourse/controllers/explain-reviewable.js.es6 index 49e57228a6..268958e105 100644 --- a/app/assets/javascripts/discourse/controllers/explain-reviewable.js.es6 +++ b/app/assets/javascripts/discourse/controllers/explain-reviewable.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: null, reviewableExplanation: null, diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 index 9709b21c48..48ca403722 100644 --- a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 @@ -1,11 +1,13 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { categoryLinkHTML } from "discourse/helpers/category-link"; import computed from "ember-addons/ember-computed-decorators"; import InputValidation from "discourse/models/input-validation"; -export default Ember.Controller.extend(ModalFunctionality, { - topicController: Ember.inject.controller("topic"), +export default Controller.extend(ModalFunctionality, { + topicController: inject("topic"), loading: true, pinnedInCategoryCount: 0, diff --git a/app/assets/javascripts/discourse/controllers/flag.js.es6 b/app/assets/javascripts/discourse/controllers/flag.js.es6 index bcfbb5e325..8f3c49ebc5 100644 --- a/app/assets/javascripts/discourse/controllers/flag.js.es6 +++ b/app/assets/javascripts/discourse/controllers/flag.js.es6 @@ -1,3 +1,6 @@ +import { not } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import ActionSummary from "discourse/models/action-summary"; import { MAX_MESSAGE_LENGTH } from "discourse/models/post-action-type"; @@ -5,7 +8,7 @@ import computed from "ember-addons/ember-computed-decorators"; import optionalService from "discourse/lib/optional-service"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { adminTools: optionalService(), userDetails: null, selected: null, @@ -57,7 +60,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return flagsAvailable; } else { // flagging topic - let lookup = Ember.Object.create(); + let lookup = EmberObject.create(); let model = this.model; model.get("actions_summary").forEach(a => { a.flagTopic = model; @@ -97,7 +100,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return true; }, - submitDisabled: Ember.computed.not("submitEnabled"), + submitDisabled: not("submitEnabled"), // Staff accounts can "take action" @computed("flagTopic", "selected.is_custom_flag") @@ -154,6 +157,13 @@ export default Ember.Controller.extend(ModalFunctionality, { params = $.extend(params, opts); } + this.appEvents.trigger( + this.flagTopic ? "topic:flag-created" : "post:flag-created", + this.model, + postAction, + params + ); + this.send("hideModal"); postAction diff --git a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 index 288ffa8ba8..ae5d53679d 100644 --- a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 @@ -1,16 +1,18 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { escapeExpression } from "discourse/lib/utilities"; import { extractError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { offerHelp: null, helpSeen: false, @computed("accountEmailOrUsername", "disabled") submitDisabled(accountEmailOrUsername, disabled) { - return Ember.isEmpty((accountEmailOrUsername || "").trim()) || disabled; + return isEmpty((accountEmailOrUsername || "").trim()) || disabled; }, onShow() { diff --git a/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 b/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 index c7175a47fd..0b37bead27 100644 --- a/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 +++ b/app/assets/javascripts/discourse/controllers/full-page-search.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import { or } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { translateResults, @@ -12,8 +16,8 @@ import { import Category from "discourse/models/category"; import { escapeExpression } from "discourse/lib/utilities"; import { setTransient } from "discourse/lib/page-tracker"; -import { iconHTML } from "discourse-common/lib/icon-library"; import Composer from "discourse/models/composer"; +import { scrollTop } from "discourse/mixins/scroll-top"; const SortOrders = [ { name: I18n.t("search.relevance"), id: 0 }, @@ -24,9 +28,9 @@ const SortOrders = [ ]; const PAGE_LIMIT = 10; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), - composer: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), + composer: inject(), bulkSelectEnabled: null, loading: false, @@ -50,7 +54,7 @@ export default Ember.Controller.extend({ @computed("q") hasAutofocus(q) { - return Ember.isEmpty(q); + return isEmpty(q); }, @computed("q") @@ -194,17 +198,12 @@ export default Ember.Controller.extend({ return this.currentUser && userCanCreateTopic; }, - @computed("expanded") - searchAdvancedIcon(expanded) { - return iconHTML(expanded ? "caret-down" : "caret-right"); - }, - @computed("page") isLastPage(page) { return page === PAGE_LIMIT; }, - searchButtonDisabled: Ember.computed.or("searching", "loading"), + searchButtonDisabled: or("searching", "loading"), _search() { if (this.searching) { @@ -224,6 +223,7 @@ export default Ember.Controller.extend({ this.set("bulkSelectEnabled", false); this.selected.clear(); this.set("searching", true); + scrollTop(); } else { this.set("loading", true); } @@ -285,7 +285,7 @@ export default Ember.Controller.extend({ } this.composer.open({ action: Composer.CREATE_TOPIC, - draftKey: Composer.CREATE_TOPIC, + draftKey: Composer.NEW_TOPIC_KEY, topicCategory }); }, diff --git a/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 b/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 index 13757e678e..287b6a6994 100644 --- a/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 +++ b/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 @@ -1,86 +1,85 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { extractError } from "discourse/lib/ajax-error"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import GrantBadgeController from "discourse/mixins/grant-badge-controller"; import Badge from "discourse/models/badge"; import UserBadge from "discourse/models/user-badge"; +import { all } from "rsvp"; -export default Ember.Controller.extend( - ModalFunctionality, - GrantBadgeController, - { - topicController: Ember.inject.controller("topic"), - loading: true, - saving: false, - selectedBadgeId: null, +export default Controller.extend(ModalFunctionality, GrantBadgeController, { + topicController: inject("topic"), + loading: true, + saving: false, + selectedBadgeId: null, - init() { - this._super(...arguments); + init() { + this._super(...arguments); - this.allBadges = []; - this.userBadges = []; - }, + this.allBadges = []; + this.userBadges = []; + }, - @computed("topicController.selectedPosts") - post() { - return this.get("topicController.selectedPosts")[0]; - }, + @computed("topicController.selectedPosts") + post() { + return this.get("topicController.selectedPosts")[0]; + }, - @computed("post") - badgeReason(post) { - const url = post.get("url"); - const protocolAndHost = - window.location.protocol + "//" + window.location.host; + @computed("post") + badgeReason(post) { + const url = post.get("url"); + const protocolAndHost = + window.location.protocol + "//" + window.location.host; - return url.indexOf("/") === 0 ? protocolAndHost + url : url; - }, + return url.indexOf("/") === 0 ? protocolAndHost + url : url; + }, - @computed("saving", "selectedBadgeGrantable") - buttonDisabled(saving, selectedBadgeGrantable) { - return saving || !selectedBadgeGrantable; - }, + @computed("saving", "selectedBadgeGrantable") + buttonDisabled(saving, selectedBadgeGrantable) { + return saving || !selectedBadgeGrantable; + }, - onShow() { - this.set("loading", true); + onShow() { + this.set("loading", true); - Ember.RSVP.all([ - Badge.findAll(), - UserBadge.findByUsername(this.get("post.username")) - ]).then(([allBadges, userBadges]) => { - this.setProperties({ - allBadges: allBadges, - userBadges: userBadges, - loading: false - }); + all([ + Badge.findAll(), + UserBadge.findByUsername(this.get("post.username")) + ]).then(([allBadges, userBadges]) => { + this.setProperties({ + allBadges: allBadges, + userBadges: userBadges, + loading: false }); - }, + }); + }, - actions: { - grantBadge() { - this.set("saving", true); + actions: { + grantBadge() { + this.set("saving", true); - this.grantBadge( - this.selectedBadgeId, - this.get("post.username"), - this.badgeReason + this.grantBadge( + this.selectedBadgeId, + this.get("post.username"), + this.badgeReason + ) + .then( + newBadge => { + this.set("selectedBadgeId", null); + this.flash( + I18n.t("badges.successfully_granted", { + username: this.get("post.username"), + badge: newBadge.get("badge.name") + }), + "success" + ); + }, + error => { + this.flash(extractError(error), "error"); + } ) - .then( - newBadge => { - this.set("selectedBadgeId", null); - this.flash( - I18n.t("badges.successfully_granted", { - username: this.get("post.username"), - badge: newBadge.get("badge.name") - }), - "success" - ); - }, - error => { - this.flash(extractError(error), "error"); - } - ) - .finally(() => this.set("saving", false)); - } + .finally(() => this.set("saving", false)); } } -); +}); diff --git a/app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 b/app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 index 3e4454ce0e..ed648a3dec 100644 --- a/app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-activity-posts.js.es6 @@ -1,10 +1,12 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { observes } from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; -export default Ember.Controller.extend({ - group: Ember.inject.controller(), - groupActivity: Ember.inject.controller(), - application: Ember.inject.controller(), +export default Controller.extend({ + group: inject(), + groupActivity: inject(), + application: inject(), canLoadMore: true, loading: false, emptyText: fmt("type", "groups.empty.%@"), diff --git a/app/assets/javascripts/discourse/controllers/group-activity-topics.js.es6 b/app/assets/javascripts/discourse/controllers/group-activity-topics.js.es6 index 2a559a196c..6d922b754e 100644 --- a/app/assets/javascripts/discourse/controllers/group-activity-topics.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-activity-topics.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Controller.extend({ +import Controller from "@ember/controller"; +export default Controller.extend({ actions: { loadMore() { this.model.loadMore(); diff --git a/app/assets/javascripts/discourse/controllers/group-activity.js.es6 b/app/assets/javascripts/discourse/controllers/group-activity.js.es6 index 26fa94835a..5c48daee43 100644 --- a/app/assets/javascripts/discourse/controllers/group-activity.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-activity.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Controller.extend({ - router: Ember.inject.service(), +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; +export default Controller.extend({ + router: service(), queryParams: ["category_id"] }); diff --git a/app/assets/javascripts/discourse/controllers/group-add-members.js.es6 b/app/assets/javascripts/discourse/controllers/group-add-members.js.es6 index 6e478fe3d8..53c1327c42 100644 --- a/app/assets/javascripts/discourse/controllers/group-add-members.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-add-members.js.es6 @@ -1,8 +1,10 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { extractError } from "discourse/lib/ajax-error"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, setAsOwner: false, @@ -17,7 +19,7 @@ export default Ember.Controller.extend(ModalFunctionality, { const model = this.model; const usernames = model.get("usernames"); - if (Ember.isEmpty(usernames)) { + if (isEmpty(usernames)) { return; } let promise; diff --git a/app/assets/javascripts/discourse/controllers/group-bulk-add.js.es6 b/app/assets/javascripts/discourse/controllers/group-bulk-add.js.es6 index 716347d4c6..bef9d535f4 100644 --- a/app/assets/javascripts/discourse/controllers/group-bulk-add.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-bulk-add.js.es6 @@ -1,14 +1,16 @@ +import { isEmpty } from "@ember/utils"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { extractError } from "discourse/lib/ajax-error"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { ajax } from "discourse/lib/ajax"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, @computed("input", "loading", "result") disableAddButton(input, loading, result) { - return loading || Ember.isEmpty(input) || input.length <= 0 || result; + return loading || isEmpty(input) || input.length <= 0 || result; }, actions: { diff --git a/app/assets/javascripts/discourse/controllers/group-index.js.es6 b/app/assets/javascripts/discourse/controllers/group-index.js.es6 index 690997aa54..2cc94f9f4e 100644 --- a/app/assets/javascripts/discourse/controllers/group-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-index.js.es6 @@ -1,3 +1,6 @@ +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import Group from "discourse/models/group"; import { @@ -6,18 +9,18 @@ import { } from "ember-addons/ember-computed-decorators"; import debounce from "discourse/lib/debounce"; -export default Ember.Controller.extend({ +export default Controller.extend({ queryParams: ["order", "desc", "filter"], order: "", desc: null, loading: false, limit: null, offset: null, - isOwner: Ember.computed.alias("model.is_group_owner"), + isOwner: alias("model.is_group_owner"), showActions: false, filter: null, filterInput: null, - application: Ember.inject.controller(), + application: inject(), @observes("filterInput") _setFilter: debounce(function() { diff --git a/app/assets/javascripts/discourse/controllers/group-manage-logs.js.es6 b/app/assets/javascripts/discourse/controllers/group-manage-logs.js.es6 index 22ee01cff5..f5c3ba48f3 100644 --- a/app/assets/javascripts/discourse/controllers/group-manage-logs.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-manage-logs.js.es6 @@ -1,17 +1,20 @@ +import { inject } from "@ember/controller"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - group: Ember.inject.controller(), +export default Controller.extend({ + group: inject(), loading: false, offset: 0, - application: Ember.inject.controller(), + application: inject(), init() { this._super(...arguments); - this.set("filters", Ember.Object.create()); + this.set("filters", EmberObject.create()); }, @computed( @@ -51,7 +54,7 @@ export default Ember.Controller.extend({ reset() { this.setProperties({ offset: 0, - filters: Ember.Object.create() + filters: EmberObject.create() }); }, diff --git a/app/assets/javascripts/discourse/controllers/group-manage-profile.js.es6 b/app/assets/javascripts/discourse/controllers/group-manage-profile.js.es6 index e316e97fad..719745dfa3 100644 --- a/app/assets/javascripts/discourse/controllers/group-manage-profile.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-manage-profile.js.es6 @@ -1,3 +1,4 @@ -export default Ember.Controller.extend({ +import Controller from "@ember/controller"; +export default Controller.extend({ saving: null }); diff --git a/app/assets/javascripts/discourse/controllers/group-manage.js.es6 b/app/assets/javascripts/discourse/controllers/group-manage.js.es6 index 795627c3cb..dab05b6dbc 100644 --- a/app/assets/javascripts/discourse/controllers/group-manage.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-manage.js.es6 @@ -1,7 +1,9 @@ +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - router: Ember.inject.service(), +export default Controller.extend({ + router: service(), @computed("model.automatic") tabs(automatic) { diff --git a/app/assets/javascripts/discourse/controllers/group-messages.js.es6 b/app/assets/javascripts/discourse/controllers/group-messages.js.es6 index cda126a2e2..a422a1f33c 100644 --- a/app/assets/javascripts/discourse/controllers/group-messages.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-messages.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Controller.extend({ - router: Ember.inject.service() +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; +export default Controller.extend({ + router: service() }); diff --git a/app/assets/javascripts/discourse/controllers/group-requests.js.es6 b/app/assets/javascripts/discourse/controllers/group-requests.js.es6 index 178db75758..246fd0cf9a 100644 --- a/app/assets/javascripts/discourse/controllers/group-requests.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group-requests.js.es6 @@ -1,3 +1,5 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import Group from "discourse/models/group"; @@ -7,7 +9,7 @@ import { } from "ember-addons/ember-computed-decorators"; import debounce from "discourse/lib/debounce"; -export default Ember.Controller.extend({ +export default Controller.extend({ queryParams: ["order", "desc", "filter"], order: "", desc: null, @@ -16,7 +18,7 @@ export default Ember.Controller.extend({ offset: null, filter: null, filterInput: null, - application: Ember.inject.controller(), + application: inject(), @observes("filterInput") _setFilter: debounce(function() { diff --git a/app/assets/javascripts/discourse/controllers/group.js.es6 b/app/assets/javascripts/discourse/controllers/group.js.es6 index f6a44552aa..322e7ab12c 100644 --- a/app/assets/javascripts/discourse/controllers/group.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group.js.es6 @@ -1,6 +1,9 @@ +import EmberObject from "@ember/object"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; -const Tab = Ember.Object.extend({ +const Tab = EmberObject.extend({ init() { this._super(...arguments); let name = this.name; @@ -9,8 +12,8 @@ const Tab = Ember.Object.extend({ } }); -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), counts: null, showing: "members", destroying: null, diff --git a/app/assets/javascripts/discourse/controllers/groups-index.js.es6 b/app/assets/javascripts/discourse/controllers/groups-index.js.es6 index 1c6a824ded..a466572b26 100644 --- a/app/assets/javascripts/discourse/controllers/groups-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/groups-index.js.es6 @@ -1,11 +1,13 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), queryParams: ["order", "asc", "filter", "type"], order: null, asc: null, diff --git a/app/assets/javascripts/discourse/controllers/groups-new.js.es6 b/app/assets/javascripts/discourse/controllers/groups-new.js.es6 index 293beffd53..f93c08959d 100644 --- a/app/assets/javascripts/discourse/controllers/groups-new.js.es6 +++ b/app/assets/javascripts/discourse/controllers/groups-new.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ saving: null, actions: { diff --git a/app/assets/javascripts/discourse/controllers/history.js.es6 b/app/assets/javascripts/discourse/controllers/history.js.es6 index 53627c157f..69ea502d41 100644 --- a/app/assets/javascripts/discourse/controllers/history.js.es6 +++ b/app/assets/javascripts/discourse/controllers/history.js.es6 @@ -1,3 +1,5 @@ +import { alias, gt, not, or, equal } from "@ember/object/computed"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { categoryBadgeHTML } from "discourse/helpers/category-link"; import computed from "ember-addons/ember-computed-decorators"; @@ -20,7 +22,7 @@ function customTagArray(fieldName) { } // This controller handles displaying of history -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: true, viewMode: "side_by_side", @@ -31,12 +33,8 @@ export default Ember.Controller.extend(ModalFunctionality, { } }, - previousFeaturedLink: Ember.computed.alias( - "model.featured_link_changes.previous" - ), - currentFeaturedLink: Ember.computed.alias( - "model.featured_link_changes.current" - ), + previousFeaturedLink: alias("model.featured_link_changes.previous"), + currentFeaturedLink: alias("model.featured_link_changes.current"), previousTagChanges: customTagArray("model.tags_changes.previous"), currentTagChanges: customTagArray("model.tags_changes.current"), @@ -118,7 +116,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return prev && current > prev; }, - displayRevisions: Ember.computed.gt("model.version_count", 2), + displayRevisions: gt("model.version_count", 2), displayGoToFirst: propertyGreaterThan( "model.current_revision", "model.first_revision" @@ -132,15 +130,15 @@ export default Ember.Controller.extend(ModalFunctionality, { "model.next_revision" ), - hideGoToFirst: Ember.computed.not("displayGoToFirst"), - hideGoToPrevious: Ember.computed.not("displayGoToPrevious"), - hideGoToNext: Ember.computed.not("displayGoToNext"), - hideGoToLast: Ember.computed.not("displayGoToLast"), + hideGoToFirst: not("displayGoToFirst"), + hideGoToPrevious: not("displayGoToPrevious"), + hideGoToNext: not("displayGoToNext"), + hideGoToLast: not("displayGoToLast"), - loadFirstDisabled: Ember.computed.or("loading", "hideGoToFirst"), - loadPreviousDisabled: Ember.computed.or("loading", "hideGoToPrevious"), - loadNextDisabled: Ember.computed.or("loading", "hideGoToNext"), - loadLastDisabled: Ember.computed.or("loading", "hideGoToLast"), + loadFirstDisabled: or("loading", "hideGoToFirst"), + loadPreviousDisabled: or("loading", "hideGoToPrevious"), + loadNextDisabled: or("loading", "hideGoToNext"), + loadLastDisabled: or("loading", "hideGoToLast"), @computed("model.previous_hidden") displayShow(prevHidden) { @@ -172,10 +170,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return this.currentUser && this.currentUser.get("staff"); }, - isEitherRevisionHidden: Ember.computed.or( - "model.previous_hidden", - "model.current_hidden" - ), + isEitherRevisionHidden: or("model.previous_hidden", "model.current_hidden"), @computed("model.previous_hidden", "model.current_hidden", "displayingInline") hiddenClasses(prevHidden, currentHidden, displayingInline) { @@ -193,12 +188,9 @@ export default Ember.Controller.extend(ModalFunctionality, { } }, - displayingInline: Ember.computed.equal("viewMode", "inline"), - displayingSideBySide: Ember.computed.equal("viewMode", "side_by_side"), - displayingSideBySideMarkdown: Ember.computed.equal( - "viewMode", - "side_by_side_markdown" - ), + displayingInline: equal("viewMode", "inline"), + displayingSideBySide: equal("viewMode", "side_by_side"), + displayingSideBySideMarkdown: equal("viewMode", "side_by_side_markdown"), @computed("displayingInline") inlineClass(displayingInline) { diff --git a/app/assets/javascripts/discourse/controllers/ignore-duration-with-username.js.es6 b/app/assets/javascripts/discourse/controllers/ignore-duration-with-username.js.es6 index 6ba026a1b8..491c496df7 100644 --- a/app/assets/javascripts/discourse/controllers/ignore-duration-with-username.js.es6 +++ b/app/assets/javascripts/discourse/controllers/ignore-duration-with-username.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { popupAjaxError } from "discourse/lib/ajax-error"; import User from "discourse/models/user"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, ignoredUntil: null, ignoredUsername: null, diff --git a/app/assets/javascripts/discourse/controllers/ignore-duration.js.es6 b/app/assets/javascripts/discourse/controllers/ignore-duration.js.es6 index 574f69e373..c78b73cbb3 100644 --- a/app/assets/javascripts/discourse/controllers/ignore-duration.js.es6 +++ b/app/assets/javascripts/discourse/controllers/ignore-duration.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, ignoredUntil: null, actions: { diff --git a/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 b/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 index d4f15d95cf..b04499456b 100644 --- a/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 +++ b/app/assets/javascripts/discourse/controllers/insert-hyperlink.js.es6 @@ -1,15 +1,145 @@ +import { isEmpty } from "@ember/utils"; +import { debounce } from "@ember/runloop"; +import { cancel } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; +import { searchForTerm } from "discourse/lib/search"; -export default Ember.Controller.extend(ModalFunctionality, { - linkUrl: "", - linkText: "", +export default Controller.extend(ModalFunctionality, { + _debounced: null, + _activeSearch: null, onShow() { - Ember.run.next(() => - $(this) - .find("input.link-url") - .focus() - ); + this.setProperties({ + linkUrl: "", + linkText: "", + searchResults: [], + searchLoading: false, + selectedRow: -1 + }); + + scheduleOnce("afterRender", () => { + const element = document.querySelector(".insert-link"); + + element.addEventListener("keydown", e => this.keyDown(e)); + + element + .closest(".modal-inner-container") + .addEventListener("mousedown", e => this.mouseDown(e)); + + document.querySelector("input.link-url").focus(); + }); + }, + + keyDown(e) { + switch (e.which) { + case 40: + this.highlightRow(e, "down"); + break; + case 38: + this.highlightRow(e, "up"); + break; + case 13: + // override Enter behaviour when a row is selected + if (this.selectedRow > -1) { + const selected = document.querySelectorAll( + ".internal-link-results .search-link" + )[this.selectedRow]; + this.selectLink(selected); + e.preventDefault(); + e.stopPropagation(); + } + break; + case 27: + // Esc should cancel dropdown first + if (this.searchResults.length) { + this.set("searchResults", []); + e.preventDefault(); + e.stopPropagation(); + } + break; + } + }, + + mouseDown(e) { + if (!e.target.closest(".inputs")) { + this.set("searchResults", []); + } + }, + + highlightRow(e, direction) { + const index = + direction === "down" ? this.selectedRow + 1 : this.selectedRow - 1; + + if (index > -1 && index < this.searchResults.length) { + document + .querySelectorAll(".internal-link-results .search-link") + [index].focus(); + this.set("selectedRow", index); + } else { + this.set("selectedRow", -1); + document.querySelector("input.link-url").focus(); + } + + e.preventDefault(); + }, + + selectLink(el) { + this.setProperties({ + linkUrl: el.href, + searchResults: [], + selectedRow: -1 + }); + + if (!this.linkText && el.dataset.title) { + this.set("linkText", el.dataset.title); + } + + document.querySelector("input.link-text").focus(); + }, + + triggerSearch() { + if (this.linkUrl.length > 3 && this.linkUrl.indexOf("http") === -1) { + this.set("searchLoading", true); + this._activeSearch = searchForTerm(this.linkUrl, { + typeFilter: "topic" + }); + this._activeSearch + .then(results => { + if (results && results.topics && results.topics.length > 0) { + this.set("searchResults", results.topics); + } else { + this.set("searchResults", []); + } + }) + .finally(() => { + this.set("searchLoading", false); + this._activeSearch = null; + }); + } else { + this.abortSearch(); + } + }, + + abortSearch() { + if (this._activeSearch) { + this._activeSearch.abort(); + } + this.setProperties({ + searchResults: [], + searchLoading: false + }); + }, + + onClose() { + const element = document.querySelector(".insert-link"); + element.removeEventListener("keydown", this.keyDown); + element + .closest(".modal-inner-container") + .removeEventListener("mousedown", this.mouseDown); + + cancel(this._debounced); }, actions: { @@ -19,7 +149,7 @@ export default Ember.Controller.extend(ModalFunctionality, { origLink.indexOf("://") === -1 ? `http://${origLink}` : origLink; const sel = this._lastSel; - if (Ember.isEmpty(linkUrl)) { + if (isEmpty(linkUrl)) { return; } @@ -35,12 +165,20 @@ export default Ember.Controller.extend(ModalFunctionality, { this.toolbarEvent.selectText(sel.start + 1, origLink.length); } } - this.set("linkUrl", ""); - this.set("linkText", ""); this.send("closeModal"); }, cancel() { this.send("closeModal"); + }, + linkClick(e) { + if (!e.metaKey && !e.ctrlKey) { + e.preventDefault(); + e.stopPropagation(); + this.selectLink(e.target.closest(".search-link")); + } + }, + search() { + this._debounced = debounce(this, this.triggerSearch, 400); } } }); diff --git a/app/assets/javascripts/discourse/controllers/invites-show.js.es6 b/app/assets/javascripts/discourse/controllers/invites-show.js.es6 index 2664a95bd7..1b1c99de7d 100644 --- a/app/assets/javascripts/discourse/controllers/invites-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/invites-show.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { alias, notEmpty } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import getUrl from "discourse-common/lib/get-url"; import DiscourseURL from "discourse/lib/url"; @@ -8,16 +11,16 @@ import NameValidation from "discourse/mixins/name-validation"; import UserFieldsValidation from "discourse/mixins/user-fields-validation"; import { findAll as findLoginMethods } from "discourse/models/login-method"; -export default Ember.Controller.extend( +export default Controller.extend( PasswordValidation, UsernameValidation, NameValidation, UserFieldsValidation, { - invitedBy: Ember.computed.alias("model.invited_by"), - email: Ember.computed.alias("model.email"), - accountUsername: Ember.computed.alias("model.username"), - passwordRequired: Ember.computed.notEmpty("accountPassword"), + invitedBy: alias("model.invited_by"), + email: alias("model.email"), + accountUsername: alias("model.username"), + passwordRequired: notEmpty("accountPassword"), successMessage: null, errorMessage: null, userFields: null, @@ -66,7 +69,7 @@ export default Ember.Controller.extend( submit() { const userFields = this.userFields; let userCustomFields = {}; - if (!Ember.isEmpty(userFields)) { + if (!isEmpty(userFields)) { userFields.forEach(function(f) { userCustomFields[f.get("field.id")] = f.get("value"); }); diff --git a/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 b/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 index 385db0406f..35981f39a7 100644 --- a/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 +++ b/app/assets/javascripts/discourse/controllers/jump-to-post.js.es6 @@ -1,15 +1,16 @@ +import { alias } from "@ember/object/computed"; +import { next } from "@ember/runloop"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { model: null, postNumber: null, postDate: null, - filteredPostsCount: Ember.computed.alias( - "topic.postStream.filteredPostsCount" - ), + filteredPostsCount: alias("topic.postStream.filteredPostsCount"), onShow() { - Ember.run.next(() => $("#post-jump").focus()); + next(() => $("#post-jump").focus()); }, actions: { diff --git a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6 b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6 index 9520e6c8f8..9e1c216e13 100644 --- a/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6 +++ b/app/assets/javascripts/discourse/controllers/keyboard-shortcuts-help.js.es6 @@ -1,3 +1,4 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; const KEY = "keyboard_shortcuts_help"; @@ -46,7 +47,7 @@ function buildShortcut( return I18n.t(`${KEY}.${key}`, context); } -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { onShow() { this.set("modal.modalClass", "keyboard-shortcuts-modal"); }, diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6 index 7f0f5bdd33..19fbc21fb7 100644 --- a/app/assets/javascripts/discourse/controllers/login.js.es6 +++ b/app/assets/javascripts/discourse/controllers/login.js.es6 @@ -1,3 +1,10 @@ +import { isEmpty } from "@ember/utils"; +import { alias, or, readOnly } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import showModal from "discourse/lib/show-modal"; @@ -19,10 +26,10 @@ const AuthErrors = [ "not_allowed_from_ip_address" ]; -export default Ember.Controller.extend(ModalFunctionality, { - createAccount: Ember.inject.controller(), - forgotPassword: Ember.inject.controller(), - application: Ember.inject.controller(), +export default Controller.extend(ModalFunctionality, { + createAccount: inject(), + forgotPassword: inject(), + application: inject(), loggingIn: false, loggedIn: false, @@ -33,7 +40,7 @@ export default Ember.Controller.extend(ModalFunctionality, { canLoginLocal: setting("enable_local_logins"), canLoginLocalWithEmail: setting("enable_local_logins_via_email"), - loginRequired: Ember.computed.alias("application.loginRequired"), + loginRequired: alias("application.loginRequired"), secondFactorMethod: SECOND_FACTOR_METHODS.TOTP, resetForm() { @@ -81,14 +88,14 @@ export default Ember.Controller.extend(ModalFunctionality, { return loggingIn ? "login.logging_in" : "login.title"; }, - loginDisabled: Ember.computed.or("loggingIn", "loggedIn"), + loginDisabled: or("loggingIn", "loggedIn"), @computed("loggingIn", "application.canSignUp") showSignupLink(loggingIn, canSignUp) { return canSignUp && !loggingIn; }, - showSpinner: Ember.computed.readOnly("loggingIn"), + showSpinner: readOnly("loggingIn"), @computed("canLoginLocalWithEmail", "processingEmailLink") showLoginWithEmailLink(canLoginLocalWithEmail, processingEmailLink) { @@ -101,7 +108,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return; } - if (Ember.isEmpty(this.loginName) || Ember.isEmpty(this.loginPassword)) { + if (isEmpty(this.loginName) || isEmpty(this.loginPassword)) { this.flash(I18n.t("login.blank_username_or_password"), "error"); return; } @@ -147,7 +154,7 @@ export default Ember.Controller.extend(ModalFunctionality, { // only need to focus the 2FA input for TOTP if (!this.showSecurityKey) { - Ember.run.scheduleOnce("afterRender", () => + scheduleOnce("afterRender", () => document .getElementById("second-factor") .querySelector("input") @@ -267,7 +274,7 @@ export default Ember.Controller.extend(ModalFunctionality, { return; } - if (Ember.isEmpty(this.loginName)) { + if (isEmpty(this.loginName)) { this.flash(I18n.t("login.blank_username"), "error"); return; } @@ -319,7 +326,7 @@ export default Ember.Controller.extend(ModalFunctionality, { const loginError = (errorMsg, className, callback) => { showModal("login"); - Ember.run.next(() => { + next(() => { if (callback) callback(); this.flash(errorMsg, className || "success"); }); @@ -376,7 +383,7 @@ export default Ember.Controller.extend(ModalFunctionality, { accountEmail: options.email, accountUsername: options.username, accountName: options.name, - authOptions: Ember.Object.create(options) + authOptions: EmberObject.create(options) }); showModal("createAccount"); diff --git a/app/assets/javascripts/discourse/controllers/modal.js.es6 b/app/assets/javascripts/discourse/controllers/modal.js.es6 index 77c79b724a..cf6c4e3aa2 100644 --- a/app/assets/javascripts/discourse/controllers/modal.js.es6 +++ b/app/assets/javascripts/discourse/controllers/modal.js.es6 @@ -1 +1,2 @@ -export default Ember.Controller.extend(); +import Controller from "@ember/controller"; +export default Controller.extend(); diff --git a/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 b/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 index fa41654818..c8934801cb 100644 --- a/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 @@ -1,21 +1,26 @@ +import { isEmpty } from "@ember/utils"; +import { alias, equal } from "@ember/object/computed"; +import { next } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { movePosts, mergeTopic } from "discourse/models/topic"; import DiscourseURL from "discourse/lib/url"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { extractError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { topicName: null, saving: false, categoryId: null, tags: null, - canAddTags: Ember.computed.alias("site.can_create_tag"), - canTagMessages: Ember.computed.alias("site.can_tag_pms"), + canAddTags: alias("site.can_create_tag"), + canTagMessages: alias("site.can_tag_pms"), selectedTopicId: null, - newTopic: Ember.computed.equal("selection", "new_topic"), - existingTopic: Ember.computed.equal("selection", "existing_topic"), - newMessage: Ember.computed.equal("selection", "new_message"), - existingMessage: Ember.computed.equal("selection", "existing_message"), + newTopic: equal("selection", "new_topic"), + existingTopic: equal("selection", "existing_topic"), + newMessage: equal("selection", "new_message"), + existingMessage: equal("selection", "existing_message"), participants: null, init() { @@ -36,18 +41,14 @@ export default Ember.Controller.extend(ModalFunctionality, { ]; }, - topicController: Ember.inject.controller("topic"), - selectedPostsCount: Ember.computed.alias( - "topicController.selectedPostsCount" - ), - selectedAllPosts: Ember.computed.alias("topicController.selectedAllPosts"), - selectedPosts: Ember.computed.alias("topicController.selectedPosts"), + topicController: inject("topic"), + selectedPostsCount: alias("topicController.selectedPostsCount"), + selectedAllPosts: alias("topicController.selectedAllPosts"), + selectedPosts: alias("topicController.selectedPosts"), @computed("saving", "selectedTopicId", "topicName") buttonDisabled(saving, selectedTopicId, topicName) { - return ( - saving || (Ember.isEmpty(selectedTopicId) && Ember.isEmpty(topicName)) - ); + return saving || (isEmpty(selectedTopicId) && isEmpty(topicName)); }, @computed( @@ -90,7 +91,7 @@ export default Ember.Controller.extend(ModalFunctionality, { ); } else if (!this.canSplitTopic) { this.set("selection", "existing_topic"); - Ember.run.next(() => $("#choose-topic-title").focus()); + next(() => $("#choose-topic-title").focus()); } }, diff --git a/app/assets/javascripts/discourse/controllers/navigation/categories.js.es6 b/app/assets/javascripts/discourse/controllers/navigation/categories.js.es6 index ee6066f186..216ca0448f 100644 --- a/app/assets/javascripts/discourse/controllers/navigation/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/navigation/categories.js.es6 @@ -1,8 +1,9 @@ +import { inject } from "@ember/controller"; import NavigationDefaultController from "discourse/controllers/navigation/default"; import computed from "ember-addons/ember-computed-decorators"; export default NavigationDefaultController.extend({ - discoveryCategories: Ember.inject.controller("discovery/categories"), + discoveryCategories: inject("discovery/categories"), @computed("discoveryCategories.model", "discoveryCategories.model.draft") draft() { diff --git a/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 b/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 index a54af35e2a..1b13265576 100644 --- a/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 +++ b/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 @@ -1,8 +1,9 @@ +import { none, and } from "@ember/object/computed"; import NavigationDefaultController from "discourse/controllers/navigation/default"; export default NavigationDefaultController.extend({ - showingParentCategory: Ember.computed.none("category.parentCategory"), - showingSubcategoryList: Ember.computed.and( + showingParentCategory: none("category.parentCategory"), + showingSubcategoryList: and( "category.show_subcategory_list", "showingParentCategory" ) diff --git a/app/assets/javascripts/discourse/controllers/navigation/default.js.es6 b/app/assets/javascripts/discourse/controllers/navigation/default.js.es6 index 0ad1878622..9d4d051974 100644 --- a/app/assets/javascripts/discourse/controllers/navigation/default.js.es6 +++ b/app/assets/javascripts/discourse/controllers/navigation/default.js.es6 @@ -1,8 +1,10 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - discovery: Ember.inject.controller(), - discoveryTopics: Ember.inject.controller("discovery/topics"), +export default Controller.extend({ + discovery: inject(), + discoveryTopics: inject("discovery/topics"), @computed("discoveryTopics.model", "discoveryTopics.model.draft") draft: function() { diff --git a/app/assets/javascripts/discourse/controllers/not-activated.js.es6 b/app/assets/javascripts/discourse/controllers/not-activated.js.es6 index 71824b3e15..ba520eb6f2 100644 --- a/app/assets/javascripts/discourse/controllers/not-activated.js.es6 +++ b/app/assets/javascripts/discourse/controllers/not-activated.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { resendActivationEmail } from "discourse/lib/user-activation"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { actions: { sendActivationEmail() { resendActivationEmail(this.username).then(() => { diff --git a/app/assets/javascripts/discourse/controllers/password-reset.js.es6 b/app/assets/javascripts/discourse/controllers/password-reset.js.es6 index ae3c5949a5..b7a4545aed 100644 --- a/app/assets/javascripts/discourse/controllers/password-reset.js.es6 +++ b/app/assets/javascripts/discourse/controllers/password-reset.js.es6 @@ -1,3 +1,5 @@ +import { alias, or } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import DiscourseURL from "discourse/lib/url"; import { ajax } from "discourse/lib/ajax"; @@ -6,19 +8,22 @@ import { userPath } from "discourse/lib/url"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import { getWebauthnCredential } from "discourse/lib/webauthn"; -export default Ember.Controller.extend(PasswordValidation, { - isDeveloper: Ember.computed.alias("model.is_developer"), - admin: Ember.computed.alias("model.admin"), - secondFactorRequired: Ember.computed.alias("model.second_factor_required"), - securityKeyRequired: Ember.computed.alias("model.security_key_required"), - backupEnabled: Ember.computed.alias("model.backup_enabled"), - securityKeyOrSecondFactorRequired: Ember.computed.or( +export default Controller.extend(PasswordValidation, { + isDeveloper: alias("model.is_developer"), + admin: alias("model.admin"), + secondFactorRequired: alias("model.second_factor_required"), + securityKeyRequired: alias("model.security_key_required"), + backupEnabled: alias("model.backup_enabled"), + securityKeyOrSecondFactorRequired: or( "model.second_factor_required", "model.security_key_required" ), - secondFactorMethod: Ember.computed.alias("model.security_key_required") - ? SECOND_FACTOR_METHODS.SECURITY_KEY - : SECOND_FACTOR_METHODS.TOTP, + @computed("model.security_key_required") + secondFactorMethod(security_key_required) { + return security_key_required + ? SECOND_FACTOR_METHODS.SECURITY_KEY + : SECOND_FACTOR_METHODS.TOTP; + }, passwordRequired: true, errorMessage: null, successMessage: null, diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index cda126a2e2..a422a1f33c 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Controller.extend({ - router: Ember.inject.service() +import { inject as service } from "@ember/service"; +import Controller from "@ember/controller"; +export default Controller.extend({ + router: service() }); diff --git a/app/assets/javascripts/discourse/controllers/preferences/about.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/about.js.es6 deleted file mode 100644 index 37e7247a8a..0000000000 --- a/app/assets/javascripts/discourse/controllers/preferences/about.js.es6 +++ /dev/null @@ -1,11 +0,0 @@ -import computed from "ember-addons/ember-computed-decorators"; - -export default Ember.Controller.extend({ - saving: false, - newBio: null, - - @computed("saving") - saveButtonText(saving) { - return saving ? I18n.t("saving") : I18n.t("user.change"); - } -}); diff --git a/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 index 14fcc4b79f..e30386afdf 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { not, or, gt } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { iconHTML } from "discourse-common/lib/icon-library"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import { default as computed } from "ember-addons/ember-computed-decorators"; @@ -12,248 +15,249 @@ import { userPath } from "discourse/lib/url"; // Number of tokens shown by default. const DEFAULT_AUTH_TOKENS_COUNT = 2; -export default Ember.Controller.extend( - CanCheckEmails, - PreferencesTabController, - { - init() { - this._super(...arguments); +export default Controller.extend(CanCheckEmails, PreferencesTabController, { + init() { + this._super(...arguments); - this.saveAttrNames = ["name", "title"]; - this.set("revoking", {}); - }, + this.saveAttrNames = ["name", "title", "primary_group_id"]; + this.set("revoking", {}); + }, - canEditName: setting("enable_names"), - canSaveUser: true, + canEditName: setting("enable_names"), + canSaveUser: true, - newNameInput: null, - newTitleInput: null, + newNameInput: null, + newTitleInput: null, + newPrimaryGroupInput: null, - passwordProgress: null, + passwordProgress: null, - showAllAuthTokens: false, + showAllAuthTokens: false, - revoking: null, + revoking: null, - cannotDeleteAccount: Ember.computed.not("currentUser.can_delete_account"), - deleteDisabled: Ember.computed.or( - "model.isSaving", - "deleting", - "cannotDeleteAccount" - ), + cannotDeleteAccount: not("currentUser.can_delete_account"), + deleteDisabled: or("model.isSaving", "deleting", "cannotDeleteAccount"), - reset() { - this.set("passwordProgress", null); - }, + reset() { + this.set("passwordProgress", null); + }, - @computed() - nameInstructions() { - return I18n.t( - this.siteSettings.full_name_required - ? "user.name.instructions_required" - : "user.name.instructions" + @computed() + nameInstructions() { + return I18n.t( + this.siteSettings.full_name_required + ? "user.name.instructions_required" + : "user.name.instructions" + ); + }, + + canSelectTitle: gt("model.availableTitles.length", 0), + + @computed("model.filteredGroups") + canSelectPrimaryGroup(primaryGroupOptions) { + return ( + primaryGroupOptions.length > 0 && + this.siteSettings.user_selected_primary_groups + ); + }, + + @computed("model.is_anonymous") + canChangePassword(isAnonymous) { + if (isAnonymous) { + return false; + } else { + return ( + !this.siteSettings.enable_sso && this.siteSettings.enable_local_logins ); - }, + } + }, - canSelectTitle: Ember.computed.gt("model.availableTitles.length", 0), + @computed("model.associated_accounts") + associatedAccountsLoaded(associatedAccounts) { + return typeof associatedAccounts !== "undefined"; + }, - @computed("model.is_anonymous") - canChangePassword(isAnonymous) { - if (isAnonymous) { - return false; + @computed("model.associated_accounts.[]") + authProviders(accounts) { + const allMethods = findAll(); + + const result = allMethods.map(method => { + return { + method, + account: accounts.find(account => account.name === method.name) // Will be undefined if no account + }; + }); + + return result.filter(value => value.account || value.method.can_connect); + }, + + disableConnectButtons: propertyNotEqual("model.id", "currentUser.id"), + + @computed( + "model.second_factor_enabled", + "canCheckEmails", + "model.is_anonymous" + ) + canUpdateAssociatedAccounts( + secondFactorEnabled, + canCheckEmails, + isAnonymous + ) { + if (secondFactorEnabled || !canCheckEmails || isAnonymous) { + return false; + } + return findAll().length > 0; + }, + + @computed("showAllAuthTokens", "model.user_auth_tokens") + authTokens(showAllAuthTokens, tokens) { + tokens.sort((a, b) => { + if (a.is_active) { + return -1; + } else if (b.is_active) { + return 1; } else { - return ( - !this.siteSettings.enable_sso && this.siteSettings.enable_local_logins + return b.seen_at.localeCompare(a.seen_at); + } + }); + + return showAllAuthTokens + ? tokens + : tokens.slice(0, DEFAULT_AUTH_TOKENS_COUNT); + }, + + canShowAllAuthTokens: gt( + "model.user_auth_tokens.length", + DEFAULT_AUTH_TOKENS_COUNT + ), + + actions: { + save() { + this.set("saved", false); + + this.model.setProperties({ + name: this.newNameInput, + title: this.newTitleInput, + primary_group_id: this.newPrimaryGroupInput + }); + + return this.model + .save(this.saveAttrNames) + .then(() => this.set("saved", true)) + .catch(popupAjaxError); + }, + + changePassword() { + if (!this.passwordProgress) { + this.set( + "passwordProgress", + I18n.t("user.change_password.in_progress") ); - } - }, - - @computed("model.associated_accounts") - associatedAccountsLoaded(associatedAccounts) { - return typeof associatedAccounts !== "undefined"; - }, - - @computed("model.associated_accounts.[]") - authProviders(accounts) { - const allMethods = findAll(); - - const result = allMethods.map(method => { - return { - method, - account: accounts.find(account => account.name === method.name) // Will be undefined if no account - }; - }); - - return result.filter(value => value.account || value.method.can_connect); - }, - - disableConnectButtons: propertyNotEqual("model.id", "currentUser.id"), - - @computed( - "model.second_factor_enabled", - "canCheckEmails", - "model.is_anonymous" - ) - canUpdateAssociatedAccounts( - secondFactorEnabled, - canCheckEmails, - isAnonymous - ) { - if (secondFactorEnabled || !canCheckEmails || isAnonymous) { - return false; - } - return findAll().length > 0; - }, - - @computed("showAllAuthTokens", "model.user_auth_tokens") - authTokens(showAllAuthTokens, tokens) { - tokens.sort((a, b) => { - if (a.is_active) { - return -1; - } else if (b.is_active) { - return 1; - } else { - return b.seen_at.localeCompare(a.seen_at); - } - }); - - return showAllAuthTokens - ? tokens - : tokens.slice(0, DEFAULT_AUTH_TOKENS_COUNT); - }, - - canShowAllAuthTokens: Ember.computed.gt( - "model.user_auth_tokens.length", - DEFAULT_AUTH_TOKENS_COUNT - ), - - actions: { - save() { - this.set("saved", false); - - this.model.setProperties({ - name: this.newNameInput, - title: this.newTitleInput - }); - return this.model - .save(this.saveAttrNames) - .then(() => this.set("saved", true)) - .catch(popupAjaxError); - }, - - changePassword() { - if (!this.passwordProgress) { - this.set( - "passwordProgress", - I18n.t("user.change_password.in_progress") - ); - return this.model - .changePassword() - .then(() => { - // password changed - this.setProperties({ - changePasswordProgress: false, - passwordProgress: I18n.t("user.change_password.success") - }); - }) - .catch(() => { - // password failed to change - this.setProperties({ - changePasswordProgress: false, - passwordProgress: I18n.t("user.change_password.error") - }); - }); - } - }, - - delete() { - this.set("deleting", true); - const message = I18n.t("user.delete_account_confirm"), - model = this.model, - buttons = [ - { - label: I18n.t("cancel"), - class: "d-modal-cancel", - link: true, - callback: () => { - this.set("deleting", false); - } - }, - { - label: - iconHTML("exclamation-triangle") + - I18n.t("user.delete_account"), - class: "btn btn-danger", - callback() { - model.delete().then( - () => { - bootbox.alert( - I18n.t("user.deleted_yourself"), - () => (window.location = Discourse.getURL("/")) - ); - }, - () => { - bootbox.alert(I18n.t("user.delete_yourself_not_allowed")); - this.set("deleting", false); - } - ); - } - } - ]; - bootbox.dialog(message, buttons, { classes: "delete-account" }); - }, - - revokeAccount(account) { - this.set(`revoking.${account.name}`, true); - - this.model - .revokeAssociatedAccount(account.name) - .then(result => { - if (result.success) { - this.model.associated_accounts.removeObject(account); - } else { - bootbox.alert(result.message); - } - }) - .catch(popupAjaxError) - .finally(() => this.set(`revoking.${account.name}`, false)); - }, - - toggleShowAllAuthTokens() { - this.toggleProperty("showAllAuthTokens"); - }, - - revokeAuthToken(token) { - ajax( - userPath( - `${this.get("model.username_lower")}/preferences/revoke-auth-token` - ), - { - type: "POST", - data: token ? { token_id: token.id } : {} - } - ) + .changePassword() .then(() => { - if (!token) { - const redirect = this.siteSettings.logout_redirect; - if (Ember.isEmpty(redirect)) { - window.location = Discourse.getURL("/"); - } else { - window.location.href = redirect; - } - } + // password changed + this.setProperties({ + changePasswordProgress: false, + passwordProgress: I18n.t("user.change_password.success") + }); }) - .catch(popupAjaxError); - }, - - showToken(token) { - showModal("auth-token", { model: token }); - }, - - connectAccount(method) { - method.doLogin({ reconnect: true }); + .catch(() => { + // password failed to change + this.setProperties({ + changePasswordProgress: false, + passwordProgress: I18n.t("user.change_password.error") + }); + }); } + }, + + delete() { + this.set("deleting", true); + const message = I18n.t("user.delete_account_confirm"), + model = this.model, + buttons = [ + { + label: I18n.t("cancel"), + class: "d-modal-cancel", + link: true, + callback: () => { + this.set("deleting", false); + } + }, + { + label: + iconHTML("exclamation-triangle") + I18n.t("user.delete_account"), + class: "btn btn-danger", + callback() { + model.delete().then( + () => { + bootbox.alert( + I18n.t("user.deleted_yourself"), + () => (window.location = Discourse.getURL("/")) + ); + }, + () => { + bootbox.alert(I18n.t("user.delete_yourself_not_allowed")); + this.set("deleting", false); + } + ); + } + } + ]; + bootbox.dialog(message, buttons, { classes: "delete-account" }); + }, + + revokeAccount(account) { + this.set(`revoking.${account.name}`, true); + + this.model + .revokeAssociatedAccount(account.name) + .then(result => { + if (result.success) { + this.model.associated_accounts.removeObject(account); + } else { + bootbox.alert(result.message); + } + }) + .catch(popupAjaxError) + .finally(() => this.set(`revoking.${account.name}`, false)); + }, + + toggleShowAllAuthTokens() { + this.toggleProperty("showAllAuthTokens"); + }, + + revokeAuthToken(token) { + ajax( + userPath( + `${this.get("model.username_lower")}/preferences/revoke-auth-token` + ), + { + type: "POST", + data: token ? { token_id: token.id } : {} + } + ) + .then(() => { + if (!token) { + const redirect = this.siteSettings.logout_redirect; + if (isEmpty(redirect)) { + window.location = Discourse.getURL("/"); + } else { + window.location.href = redirect; + } + } + }) + .catch(popupAjaxError); + }, + + showToken(token) { + showModal("auth-token", { model: token }); + }, + + connectAccount(method) { + method.doLogin({ reconnect: true }); } } -); +}); diff --git a/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 index d45e3fad89..8f86974e38 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 @@ -1,8 +1,10 @@ +import { or } from "@ember/object/computed"; +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(PreferencesTabController, { +export default Controller.extend(PreferencesTabController, { init() { this._super(...arguments); @@ -34,7 +36,7 @@ export default Ember.Controller.extend(PreferencesTabController, { return this.siteSettings.remove_muted_tags_from_latest !== "never"; }, - canSave: Ember.computed.or("canSee", "currentUser.admin"), + canSave: or("canSee", "currentUser.admin"), actions: { save() { diff --git a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 index c7ad39668d..c25db36a43 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 @@ -1,18 +1,20 @@ +import { empty, or } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { propertyEqual } from "discourse/lib/computed"; import InputValidation from "discourse/models/input-validation"; import { emailValid } from "discourse/lib/utilities"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ taken: false, saving: false, error: false, success: false, newEmail: null, - newEmailEmpty: Ember.computed.empty("newEmail"), + newEmailEmpty: empty("newEmail"), - saveDisabled: Ember.computed.or( + saveDisabled: or( "saving", "newEmailEmpty", "taken", diff --git a/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 index 2db23b6f4d..a2001457e5 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 @@ -1,3 +1,5 @@ +import { equal } from "@ember/object/computed"; +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -8,12 +10,12 @@ const EMAIL_LEVELS = { NEVER: 2 }; -export default Ember.Controller.extend(PreferencesTabController, { - emailMessagesLevelAway: Ember.computed.equal( +export default Controller.extend(PreferencesTabController, { + emailMessagesLevelAway: equal( "model.user_option.email_messages_level", EMAIL_LEVELS.ONLY_WHEN_AWAY ), - emailLevelAway: Ember.computed.equal( + emailLevelAway: equal( "model.user_option.email_level", EMAIL_LEVELS.ONLY_WHEN_AWAY ), diff --git a/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6 index e5b7bf42bf..9ef7280fc2 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/interface.js.es6 @@ -1,3 +1,5 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { setDefaultHomepage } from "discourse/lib/utilities"; import { @@ -27,7 +29,7 @@ const USER_HOMES = { const TEXT_SIZES = ["smaller", "normal", "larger", "largest"]; const TITLE_COUNT_MODES = ["notifications", "contextual"]; -export default Ember.Controller.extend(PreferencesTabController, { +export default Controller.extend(PreferencesTabController, { @computed("makeThemeDefault") saveAttrNames(makeDefault) { let attrs = [ @@ -51,7 +53,7 @@ export default Ember.Controller.extend(PreferencesTabController, { return attrs; }, - preferencesController: Ember.inject.controller("preferences"), + preferencesController: inject("preferences"), @computed() isiPad() { diff --git a/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 index 77690846d5..8030885efb 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { NotificationLevels } from "discourse/lib/notification-levels"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(PreferencesTabController, { +export default Controller.extend(PreferencesTabController, { init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 index 5d1dde4b76..b4e9a46fac 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 @@ -1,9 +1,12 @@ +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { cookAsync } from "discourse/lib/text"; -export default Ember.Controller.extend(PreferencesTabController, { +export default Controller.extend(PreferencesTabController, { init() { this._super(...arguments); @@ -22,7 +25,7 @@ export default Ember.Controller.extend(PreferencesTabController, { @computed("model.user_fields.@each.value") userFields() { let siteUserFields = this.site.get("user_fields"); - if (!Ember.isEmpty(siteUserFields)) { + if (!isEmpty(siteUserFields)) { const userFields = this.get("model.user_fields"); // Staff can edit fields that are not `editable` @@ -33,7 +36,7 @@ export default Ember.Controller.extend(PreferencesTabController, { const value = userFields ? userFields[field.get("id").toString()] : null; - return Ember.Object.create({ value, field }); + return EmberObject.create({ value, field }); }); } }, @@ -51,9 +54,9 @@ export default Ember.Controller.extend(PreferencesTabController, { userFields = this.userFields; // Update the user fields - if (!Ember.isEmpty(userFields)) { + if (!isEmpty(userFields)) { const modelFields = model.get("user_fields"); - if (!Ember.isEmpty(modelFields)) { + if (!isEmpty(modelFields)) { userFields.forEach(function(uf) { modelFields[uf.get("field.id").toString()] = uf.get("value"); }); diff --git a/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6 index 34eb99d0e1..233ed03390 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/second-factor.js.es6 @@ -1,3 +1,5 @@ +import { alias, and } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import { default as DiscourseURL, userPath } from "discourse/lib/url"; @@ -6,7 +8,7 @@ import { findAll } from "discourse/models/login-method"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import showModal from "discourse/lib/show-modal"; -export default Ember.Controller.extend(CanCheckEmails, { +export default Controller.extend(CanCheckEmails, { loading: false, dirty: false, resetPasswordLoading: false, @@ -14,11 +16,11 @@ export default Ember.Controller.extend(CanCheckEmails, { password: null, errorMessage: null, newUsername: null, - backupEnabled: Ember.computed.alias("model.second_factor_backup_enabled"), + backupEnabled: alias("model.second_factor_backup_enabled"), secondFactorMethod: SECOND_FACTOR_METHODS.TOTP, totps: null, - loaded: Ember.computed.and("secondFactorImage", "secondFactorKey"), + loaded: and("secondFactorImage", "secondFactorKey"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 index e149711bd3..85d1241ad3 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 @@ -1,8 +1,9 @@ +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(PreferencesTabController, { +export default Controller.extend(PreferencesTabController, { init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 index 367f83903c..954e8c739e 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { empty, or } from "@ember/object/computed"; +import Controller from "@ember/controller"; import { default as computed, observes @@ -7,7 +10,7 @@ import DiscourseURL from "discourse/lib/url"; import { userPath } from "discourse/lib/url"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ taken: false, saving: false, errorMessage: null, @@ -15,8 +18,8 @@ export default Ember.Controller.extend({ maxLength: setting("max_username_length"), minLength: setting("min_username_length"), - newUsernameEmpty: Ember.computed.empty("newUsername"), - saveDisabled: Ember.computed.or( + newUsernameEmpty: empty("newUsername"), + saveDisabled: or( "saving", "newUsernameEmpty", "taken", @@ -35,7 +38,7 @@ export default Ember.Controller.extend({ this.set("taken", false); this.set("errorMessage", null); - if (Ember.isEmpty(this.newUsername)) return; + if (isEmpty(this.newUsername)) return; if (this.unchanged) return; Discourse.User.checkUsername( diff --git a/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 index 9f213a3090..fc675cf052 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 @@ -1,10 +1,12 @@ +import { alias, gte, or } from "@ember/object/computed"; +import Controller from "@ember/controller"; import PreferencesTabController from "discourse/mixins/preferences-tab-controller"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(PreferencesTabController, { - ignoredUsernames: Ember.computed.alias("model.ignored_usernames"), - userIsMemberOrAbove: Ember.computed.gte("model.trust_level", 2), - ignoredEnabled: Ember.computed.or("userIsMemberOrAbove", "model.staff"), +export default Controller.extend(PreferencesTabController, { + ignoredUsernames: alias("model.ignored_usernames"), + userIsMemberOrAbove: gte("model.trust_level", 2), + ignoredEnabled: or("userIsMemberOrAbove", "model.staff"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/raw-email.js.es6 b/app/assets/javascripts/discourse/controllers/raw-email.js.es6 index e671f3eef3..fbdeb103a5 100644 --- a/app/assets/javascripts/discourse/controllers/raw-email.js.es6 +++ b/app/assets/javascripts/discourse/controllers/raw-email.js.es6 @@ -1,18 +1,20 @@ +import { equal } from "@ember/object/computed"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import Post from "discourse/models/post"; import IncomingEmail from "admin/models/incoming-email"; // This controller handles displaying of raw email -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { rawEmail: "", textPart: "", htmlPart: "", tab: "raw", - showRawEmail: Ember.computed.equal("tab", "raw"), - showTextPart: Ember.computed.equal("tab", "text_part"), - showHtmlPart: Ember.computed.equal("tab", "html_part"), + showRawEmail: equal("tab", "raw"), + showTextPart: equal("tab", "text_part"), + showHtmlPart: equal("tab", "html_part"), onShow() { this.send("displayRaw"); diff --git a/app/assets/javascripts/discourse/controllers/rename-tag.js.es6 b/app/assets/javascripts/discourse/controllers/rename-tag.js.es6 index 9a7a01d1ef..b08bc2d646 100644 --- a/app/assets/javascripts/discourse/controllers/rename-tag.js.es6 +++ b/app/assets/javascripts/discourse/controllers/rename-tag.js.es6 @@ -1,9 +1,10 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import computed from "ember-addons/ember-computed-decorators"; import BufferedContent from "discourse/mixins/buffered-content"; import { extractError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend(ModalFunctionality, BufferedContent, { +export default Controller.extend(ModalFunctionality, BufferedContent, { @computed("buffered.id", "id") renameDisabled(inputTagName, currentTagName) { const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); diff --git a/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 b/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 index d893fa5b0d..06d5f30cca 100644 --- a/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 @@ -1,3 +1,6 @@ +import { sort } from "@ember/object/computed"; +import EmberObjectProxy from "@ember/object/proxy"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import ModalFunctionality from "discourse/mixins/modal-functionality"; const BufferedProxy = window.BufferedProxy; // import BufferedProxy from 'ember-buffered-proxy/proxy'; @@ -8,7 +11,7 @@ import { } from "ember-addons/ember-computed-decorators"; import Ember from "ember"; -export default Ember.Controller.extend(ModalFunctionality, Ember.Evented, { +export default Controller.extend(ModalFunctionality, Ember.Evented, { init() { this._super(...arguments); @@ -22,14 +25,11 @@ export default Ember.Controller.extend(ModalFunctionality, Ember.Evented, { @computed("site.categories") categoriesBuffered(categories) { - const bufProxy = Ember.ObjectProxy.extend(BufferedProxy); + const bufProxy = EmberObjectProxy.extend(BufferedProxy); return categories.map(c => bufProxy.create({ content: c })); }, - categoriesOrdered: Ember.computed.sort( - "categoriesBuffered", - "categoriesSorting" - ), + categoriesOrdered: sort("categoriesBuffered", "categoriesSorting"), @computed("categoriesBuffered.@each.hasBufferedChanges") showApplyAll() { diff --git a/app/assets/javascripts/discourse/controllers/request-group-membership-form.js.es6 b/app/assets/javascripts/discourse/controllers/request-group-membership-form.js.es6 index dd3a995160..0f316873ce 100644 --- a/app/assets/javascripts/discourse/controllers/request-group-membership-form.js.es6 +++ b/app/assets/javascripts/discourse/controllers/request-group-membership-form.js.es6 @@ -1,11 +1,14 @@ +import { isEmpty } from "@ember/utils"; +import { alias } from "@ember/object/computed"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { popupAjaxError } from "discourse/lib/ajax-error"; import DiscourseURL from "discourse/lib/url"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, - reason: Ember.computed.alias("model.membership_request_template"), + reason: alias("model.membership_request_template"), @computed("model.name") title(groupName) { @@ -14,7 +17,7 @@ export default Ember.Controller.extend(ModalFunctionality, { @computed("loading", "reason") disableSubmit(loading, reason) { - return loading || Ember.isEmpty(reason); + return loading || isEmpty(reason); }, actions: { diff --git a/app/assets/javascripts/discourse/controllers/review-index.js.es6 b/app/assets/javascripts/discourse/controllers/review-index.js.es6 index f65fd2129b..75ab25b4f1 100644 --- a/app/assets/javascripts/discourse/controllers/review-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/review-index.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ queryParams: [ "priority", "type", diff --git a/app/assets/javascripts/discourse/controllers/review-settings.js.es6 b/app/assets/javascripts/discourse/controllers/review-settings.js.es6 index d3ee32ccf7..8e670adb2a 100644 --- a/app/assets/javascripts/discourse/controllers/review-settings.js.es6 +++ b/app/assets/javascripts/discourse/controllers/review-settings.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ saving: false, saved: false, diff --git a/app/assets/javascripts/discourse/controllers/search-help.js.es6 b/app/assets/javascripts/discourse/controllers/search-help.js.es6 index be04358f4b..654722d2c7 100644 --- a/app/assets/javascripts/discourse/controllers/search-help.js.es6 +++ b/app/assets/javascripts/discourse/controllers/search-help.js.es6 @@ -1,7 +1,8 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { @computed showGoogleSearch() { return !Discourse.SiteSettings.login_required; diff --git a/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 index f19bb5a0f7..54f41fc405 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 @@ -1,3 +1,4 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { bufferToBase64, @@ -6,7 +7,7 @@ import { } from "discourse/lib/webauthn"; // model for this controller is user.js.es6 -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, errorMessage: null, diff --git a/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 index ac105f57b2..eab4f2943f 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, secondFactorImage: null, secondFactorKey: null, diff --git a/app/assets/javascripts/discourse/controllers/second-factor-backup-edit.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-backup-edit.js.es6 index e11f484fbc..2801056c71 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-backup-edit.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-backup-edit.js.es6 @@ -1,15 +1,16 @@ +import { alias } from "@ember/object/computed"; +import { later } from "@ember/runloop"; +import Controller from "@ember/controller"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { loading: false, errorMessage: null, successMessage: null, - backupEnabled: Ember.computed.alias("model.second_factor_backup_enabled"), - remainingCodes: Ember.computed.alias( - "model.second_factor_remaining_backup_codes" - ), + backupEnabled: alias("model.second_factor_backup_enabled"), + remainingCodes: alias("model.second_factor_remaining_backup_codes"), backupCodes: null, secondFactorMethod: SECOND_FACTOR_METHODS.TOTP, @@ -101,7 +102,7 @@ export default Ember.Controller.extend(ModalFunctionality, { }, _hideCopyMessage() { - Ember.run.later( + later( () => this.setProperties({ successMessage: null, errorMessage: null }), 2000 ); diff --git a/app/assets/javascripts/discourse/controllers/second-factor-edit-security-key.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-edit-security-key.js.es6 index 90815cfbea..8507448607 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-edit-security-key.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-edit-security-key.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { actions: { disableSecurityKey() { this.user diff --git a/app/assets/javascripts/discourse/controllers/second-factor-edit.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-edit.js.es6 index e39f0f2b65..c11b278158 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-edit.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-edit.js.es6 @@ -1,6 +1,7 @@ +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { actions: { disableSecondFactor() { this.user diff --git a/app/assets/javascripts/discourse/controllers/static.js.es6 b/app/assets/javascripts/discourse/controllers/static.js.es6 index 82fd514e16..587e14da81 100644 --- a/app/assets/javascripts/discourse/controllers/static.js.es6 +++ b/app/assets/javascripts/discourse/controllers/static.js.es6 @@ -1,11 +1,14 @@ +import { equal } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import computed from "ember-addons/ember-computed-decorators"; import { userPath } from "discourse/lib/url"; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), - showLoginButton: Ember.computed.equal("model.path", "login"), + showLoginButton: equal("model.path", "login"), @computed("model.path") bodyClass: path => `static-${path}`, diff --git a/app/assets/javascripts/discourse/controllers/tag-groups-edit.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups-edit.js.es6 new file mode 100644 index 0000000000..067a2f615b --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/tag-groups-edit.js.es6 @@ -0,0 +1,15 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; + +export default Controller.extend({ + tagGroups: inject(), + + actions: { + onDestroy() { + const tagGroups = this.tagGroups.model; + tagGroups.removeObject(this.model); + + this.transitionToRoute("tagGroups.index"); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/tag-groups-new.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups-new.js.es6 new file mode 100644 index 0000000000..e4a3a0187e --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/tag-groups-new.js.es6 @@ -0,0 +1,14 @@ +import Controller from "@ember/controller"; + +export default Controller.extend({ + tagGroups: Ember.inject.controller(), + + actions: { + onSave() { + const tagGroups = this.tagGroups.model; + tagGroups.pushObject(this.model); + + this.transitionToRoute("tagGroups.edit", this.model); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6 deleted file mode 100644 index 7b80def0b7..0000000000 --- a/app/assets/javascripts/discourse/controllers/tag-groups-show.js.es6 +++ /dev/null @@ -1,26 +0,0 @@ -export default Ember.Controller.extend({ - tagGroups: Ember.inject.controller(), - - actions: { - save() { - this.model.save(); - }, - - destroy() { - return bootbox.confirm( - I18n.t("tagging.groups.confirm_delete"), - I18n.t("no_value"), - I18n.t("yes_value"), - destroy => { - if (destroy) { - const c = this.get("tagGroups.model"); - return this.model.destroy().then(() => { - c.removeObject(this.model); - this.transitionToRoute("tagGroups"); - }); - } - } - ); - } - } -}); diff --git a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 index e4515d90b9..725f8846f1 100644 --- a/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tag-groups.js.es6 @@ -1,24 +1,9 @@ -import TagGroup from "discourse/models/tag-group"; +import Controller from "@ember/controller"; -export default Ember.Controller.extend({ +export default Controller.extend({ actions: { - selectTagGroup(tagGroup) { - if (this.selectedItem) { - this.selectedItem.set("selected", false); - } - this.set("selectedItem", tagGroup); - tagGroup.set("selected", true); - tagGroup.set("savingStatus", null); - this.transitionToRoute("tagGroups.show", tagGroup); - }, - newTagGroup() { - const newTagGroup = TagGroup.create({ - id: "new", - name: I18n.t("tagging.groups.new_name") - }); - this.model.pushObject(newTagGroup); - this.send("selectTagGroup", newTagGroup); + this.transitionToRoute("tagGroups.new"); } } }); diff --git a/app/assets/javascripts/discourse/controllers/tags-index.js.es6 b/app/assets/javascripts/discourse/controllers/tags-index.js.es6 index fa20f97f2f..c2ec12fda6 100644 --- a/app/assets/javascripts/discourse/controllers/tags-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tags-index.js.es6 @@ -1,15 +1,17 @@ +import { alias, notEmpty } from "@ember/object/computed"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import showModal from "discourse/lib/show-modal"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Ember.Controller.extend({ +export default Controller.extend({ sortedByCount: true, sortedByName: false, - canAdminTags: Ember.computed.alias("currentUser.staff"), - groupedByCategory: Ember.computed.notEmpty("model.extras.categories"), - groupedByTagGroup: Ember.computed.notEmpty("model.extras.tag_groups"), + canAdminTags: alias("currentUser.staff"), + groupedByCategory: notEmpty("model.extras.categories"), + groupedByTagGroup: notEmpty("model.extras.tag_groups"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 index 0c1c77e610..9d787fe8a4 100644 --- a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 @@ -1,3 +1,6 @@ +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { default as computed, observes @@ -48,13 +51,13 @@ if (customNavItemHref) { }); } -export default Ember.Controller.extend(BulkTopicSelection, { - application: Ember.inject.controller(), +export default Controller.extend(BulkTopicSelection, { + application: inject(), tag: null, additionalTags: null, list: null, - canAdminTag: Ember.computed.alias("currentUser.staff"), + canAdminTag: alias("currentUser.staff"), filterMode: null, navMode: "latest", loading: false, @@ -67,7 +70,7 @@ export default Ember.Controller.extend(BulkTopicSelection, { max_posts: null, q: null, - categories: Ember.computed.alias("site.categoriesList"), + categories: alias("site.categoriesList"), @computed("list", "list.draft") createTopicLabel(list, listDraft) { diff --git a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 index 5d9c287cf2..d2a809fc6e 100644 --- a/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic-bulk-actions.js.es6 @@ -1,3 +1,5 @@ +import { empty, alias } from "@ember/object/computed"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; const _buttons = []; @@ -67,11 +69,11 @@ addBulkButton("deleteTopics", "delete", { }); // Modal for performing bulk actions on topics -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { tags: null, - emptyTags: Ember.computed.empty("tags"), - categoryId: Ember.computed.alias("model.category.id"), + emptyTags: empty("tags"), + categoryId: alias("model.category.id"), onShow() { const topics = this.get("model.topics"); diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index f459e4bcec..af63f140be 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -1,3 +1,10 @@ +import { isEmpty } from "@ember/utils"; +import { or, and, not, alias } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { bufferedProperty } from "discourse/mixins/buffered-content"; import Composer from "discourse/models/composer"; import DiscourseURL from "discourse/lib/url"; @@ -18,6 +25,7 @@ import { spinnerHTML } from "discourse/helpers/loading-spinner"; import { userPath } from "discourse/lib/url"; import showModal from "discourse/lib/show-modal"; import TopicTimer from "discourse/models/topic-timer"; +import { Promise } from "rsvp"; let customPostMessageCallbacks = {}; @@ -33,14 +41,14 @@ export function registerCustomPostMessageCallback(type, callback) { customPostMessageCallbacks[type] = callback; } -export default Ember.Controller.extend(bufferedProperty("model"), { - composer: Ember.inject.controller(), - application: Ember.inject.controller(), +export default Controller.extend(bufferedProperty("model"), { + composer: inject(), + application: inject(), multiSelect: false, selectedPostIds: null, editingTopic: false, queryParams: ["filter", "username_filters"], - loadedAllPosts: Ember.computed.or( + loadedAllPosts: or( "model.postStream.loadedAllPosts", "model.postStream.loadingLastPost" ), @@ -54,7 +62,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { filter: null, quoteState: null, - canRemoveTopicFeaturedLink: Ember.computed.and( + canRemoveTopicFeaturedLink: and( "canEditTopicFeaturedLink", "buffered.featured_link" ), @@ -66,7 +74,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { @observes("model.title", "category") _titleChanged() { const title = this.get("model.title"); - if (!Ember.isEmpty(title)) { + if (!isEmpty(title)) { // force update lazily loaded titles this.send("refreshTitle"); } @@ -130,12 +138,12 @@ export default Ember.Controller.extend(bufferedProperty("model"), { return; } - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { this.send("showHistory", post, revision); }); }, - showCategoryChooser: Ember.computed.not("model.isPrivateMessage"), + showCategoryChooser: not("model.isPrivateMessage"), gotoInbox(name) { let url = userPath(this.get("currentUser.username_lower") + "/messages"); @@ -261,7 +269,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { selectText(postId, buffer) { const loadedPost = this.get("model.postStream").findLoadedPost(postId); const promise = loadedPost - ? Ember.RSVP.resolve(loadedPost) + ? Promise.resolve(loadedPost) : this.get("model.postStream").loadPost(postId); return promise.then(post => { @@ -819,7 +827,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { }, addNotice(post) { - return new Ember.RSVP.Promise(function(resolve, reject) { + return new Promise(function(resolve, reject) { const controller = showModal("add-post-notice"); controller.setProperties({ post, resolve, reject }); }); @@ -965,13 +973,13 @@ export default Ember.Controller.extend(bufferedProperty("model"), { options = { action: Composer.PRIVATE_MESSAGE, archetypeId: "private_message", - draftKey: Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY, + draftKey: post.topic.draft_key, usernames: usernames }; } else { options = { action: Composer.CREATE_TOPIC, - draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY, + draftKey: post.topic.draft_key, categoryId: this.get("model.category.id") }; } @@ -979,7 +987,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { composerController .open(options) .then(() => { - return Ember.isEmpty(quotedText) ? "" : quotedText; + return isEmpty(quotedText) ? "" : quotedText; }) .then(q => { const postUrl = `${location.protocol}//${location.host}${post.get( @@ -1056,7 +1064,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { statusType, null ) - .then(() => this.set(`model.${topicTimer}`, Ember.Object.create({}))) + .then(() => this.set(`model.${topicTimer}`, EmberObject.create({}))) .catch(error => popupAjaxError(error)); } }, @@ -1142,12 +1150,12 @@ export default Ember.Controller.extend(bufferedProperty("model"), { } }, - hasError: Ember.computed.or("model.errorHtml", "model.errorMessage"), - noErrorYet: Ember.computed.not("hasError"), + hasError: or("model.errorHtml", "model.errorMessage"), + noErrorYet: not("hasError"), - categories: Ember.computed.alias("site.categoriesList"), + categories: alias("site.categoriesList"), - selectedPostsCount: Ember.computed.alias("selectedPostIds.length"), + selectedPostsCount: alias("selectedPostIds.length"), @computed( "selectedPostIds", @@ -1196,7 +1204,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { return isMegaTopic ? false : !selectedAllPosts; }, - canDeselectAll: Ember.computed.alias("selectedAllPosts"), + canDeselectAll: alias("selectedAllPosts"), @computed( "currentUser.staff", @@ -1423,7 +1431,7 @@ export default Ember.Controller.extend(bufferedProperty("model"), { // automatically unpin topics when the user reaches the bottom const max = _.max(postNumbers); if (topic.get("pinned") && max >= topic.get("highest_post_number")) { - Ember.run.next(() => topic.clearPin()); + next(() => topic.clearPin()); } } } diff --git a/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 b/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 index 73397bb07a..87c73494a0 100644 --- a/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 @@ -1,3 +1,5 @@ +import { equal } from "@ember/object/computed"; +import Controller from "@ember/controller"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import { default as computed, @@ -17,12 +19,12 @@ function uploadTranslate(key) { return `upload_selector.${key}`; } -export default Ember.Controller.extend(ModalFunctionality, { +export default Controller.extend(ModalFunctionality, { showMore: false, imageUrl: null, imageLink: null, - local: Ember.computed.equal("selection", "local"), - remote: Ember.computed.equal("selection", "remote"), + local: equal("selection", "local"), + remote: equal("selection", "remote"), selection: "local", @computed() diff --git a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 index d8e6f29dca..596125d221 100644 --- a/app/assets/javascripts/discourse/controllers/user-activity.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-activity.js.es6 @@ -1,12 +1,16 @@ +import { alias } from "@ember/object/computed"; +import { inject as service } from "@ember/service"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { exportUserArchive } from "discourse/lib/export-csv"; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), - router: Ember.inject.service(), - user: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), + router: service(), + user: inject(), userActionType: null, - canDownloadPosts: Ember.computed.alias("user.viewingSelf"), + canDownloadPosts: alias("user.viewingSelf"), _showFooter: function() { var showFooter; diff --git a/app/assets/javascripts/discourse/controllers/user-badges.js.es6 b/app/assets/javascripts/discourse/controllers/user-badges.js.es6 index 9046c373bd..01df9566af 100644 --- a/app/assets/javascripts/discourse/controllers/user-badges.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-badges.js.es6 @@ -1,7 +1,10 @@ -export default Ember.Controller.extend({ - user: Ember.inject.controller(), - username: Ember.computed.alias("user.model.username_lower"), - sortedBadges: Ember.computed.sort("model", "badgeSortOrder"), +import { alias, sort } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; +export default Controller.extend({ + user: inject(), + username: alias("user.model.username_lower"), + sortedBadges: sort("model", "badgeSortOrder"), init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/controllers/user-card.js.es6 b/app/assets/javascripts/discourse/controllers/user-card.js.es6 index 0f26ea5e59..d0fa3abf1c 100644 --- a/app/assets/javascripts/discourse/controllers/user-card.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-card.js.es6 @@ -1,12 +1,15 @@ +import { inject as service } from "@ember/service"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { default as DiscourseURL, userPath, groupPath } from "discourse/lib/url"; -export default Ember.Controller.extend({ - topic: Ember.inject.controller(), - router: Ember.inject.service(), +export default Controller.extend({ + topic: inject(), + router: service(), actions: { togglePosts(user) { diff --git a/app/assets/javascripts/discourse/controllers/user-invited-show.js.es6 b/app/assets/javascripts/discourse/controllers/user-invited-show.js.es6 index 23bbd45295..8a8c102b0e 100644 --- a/app/assets/javascripts/discourse/controllers/user-invited-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-invited-show.js.es6 @@ -1,3 +1,5 @@ +import { equal, reads, gte } from "@ember/object/computed"; +import Controller from "@ember/controller"; import Invite from "discourse/models/invite"; import debounce from "discourse/lib/debounce"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -6,7 +8,7 @@ import { observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ +export default Controller.extend({ user: null, model: null, filter: null, @@ -31,7 +33,7 @@ export default Ember.Controller.extend({ ); }, 250), - inviteRedeemed: Ember.computed.equal("filter", "redeemed"), + inviteRedeemed: equal("filter", "redeemed"), @computed("filter") showBulkActionButtons(filter) { @@ -42,11 +44,11 @@ export default Ember.Controller.extend({ ); }, - canInviteToForum: Ember.computed.reads("currentUser.can_invite_to_forum"), + canInviteToForum: reads("currentUser.can_invite_to_forum"), - canBulkInvite: Ember.computed.reads("currentUser.admin"), + canBulkInvite: reads("currentUser.admin"), - showSearch: Ember.computed.gte("totalInvites", 10), + showSearch: gte("totalInvites", 10), @computed("invitesCount.total", "invitesCount.pending") pendingLabel(invitesCountTotal, invitesCountPending) { diff --git a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 index bb94ee6f50..ea5507cc5c 100644 --- a/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-notifications.js.es6 @@ -1,11 +1,13 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import { ajax } from "discourse/lib/ajax"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), @observes("model.canLoadMore") _showFooter() { diff --git a/app/assets/javascripts/discourse/controllers/user-posts.js.es6 b/app/assets/javascripts/discourse/controllers/user-posts.js.es6 index 25c730d97a..fe001ad1c1 100644 --- a/app/assets/javascripts/discourse/controllers/user-posts.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-posts.js.es6 @@ -1,5 +1,7 @@ -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; +export default Controller.extend({ + application: inject(), _showFooter: function() { this.set("application.showFooter", !this.get("model.canLoadMore")); diff --git a/app/assets/javascripts/discourse/controllers/user-private-messages-tags.js.es6 b/app/assets/javascripts/discourse/controllers/user-private-messages-tags.js.es6 index 1be6e948c4..d1c311f893 100644 --- a/app/assets/javascripts/discourse/controllers/user-private-messages-tags.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-private-messages-tags.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Controller.extend({ +import Controller from "@ember/controller"; +export default Controller.extend({ sortProperties: ["count:desc", "id"], tagsForUser: null, sortedByCount: true, diff --git a/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 index c5e1bd9452..c6252978c9 100644 --- a/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 @@ -1,25 +1,26 @@ +import { alias, equal, and } from "@ember/object/computed"; +import { inject as service } from "@ember/service"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import Topic from "discourse/models/topic"; -export default Ember.Controller.extend({ - router: Ember.inject.service(), - userTopicsList: Ember.inject.controller("user-topics-list"), - user: Ember.inject.controller(), +export default Controller.extend({ + router: service(), + userTopicsList: inject("user-topics-list"), + user: inject(), pmView: false, - viewingSelf: Ember.computed.alias("user.viewingSelf"), - isGroup: Ember.computed.equal("pmView", "groups"), - currentPath: Ember.computed.alias("router._router.currentPath"), - selected: Ember.computed.alias("userTopicsList.selected"), - bulkSelectEnabled: Ember.computed.alias("userTopicsList.bulkSelectEnabled"), + viewingSelf: alias("user.viewingSelf"), + isGroup: equal("pmView", "groups"), + currentPath: alias("router._router.currentPath"), + selected: alias("userTopicsList.selected"), + bulkSelectEnabled: alias("userTopicsList.bulkSelectEnabled"), showToggleBulkSelect: true, - pmTaggingEnabled: Ember.computed.alias("site.can_tag_pms"), + pmTaggingEnabled: alias("site.can_tag_pms"), tagId: null, - showNewPM: Ember.computed.and( - "user.viewingSelf", - "currentUser.can_send_private_messages" - ), + showNewPM: and("user.viewingSelf", "currentUser.can_send_private_messages"), @computed("selected.[]", "bulkSelectEnabled") hasSelection(selected, bulkSelectEnabled) { diff --git a/app/assets/javascripts/discourse/controllers/user-summary.js.es6 b/app/assets/javascripts/discourse/controllers/user-summary.js.es6 index 2e88396cb7..7383cfa336 100644 --- a/app/assets/javascripts/discourse/controllers/user-summary.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-summary.js.es6 @@ -1,12 +1,15 @@ +import { alias } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; import { durationTiny } from "discourse/lib/formatter"; // should be kept in sync with 'UserSummary::MAX_BADGES' const MAX_BADGES = 6; -export default Ember.Controller.extend({ - userController: Ember.inject.controller("user"), - user: Ember.computed.alias("userController.model"), +export default Controller.extend({ + userController: inject("user"), + user: alias("userController.model"), @computed("model.badges.length") moreBadges(badgesLength) { diff --git a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 index a4d822a565..5539500165 100644 --- a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 @@ -1,8 +1,10 @@ +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import computed from "ember-addons/ember-computed-decorators"; // Lists of topics on a user's page. -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), hideCategory: false, showPosters: false, @@ -16,6 +18,10 @@ export default Ember.Controller.extend({ this.newIncoming = []; }, + saveScrollPosition: function() { + this.session.set("topicListScrollPosition", $(window).scrollTop()); + }, + _showFooter: function() { this.set("application.showFooter", !this.get("model.canLoadMore")); }.observes("model.canLoadMore"), diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6 index e59b0edfdc..e24bf67a68 100644 --- a/app/assets/javascripts/discourse/controllers/user.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user.js.es6 @@ -1,14 +1,21 @@ +import { isEmpty } from "@ember/utils"; +import { alias, or, gt, not, and } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { inject as service } from "@ember/service"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import CanCheckEmails from "discourse/mixins/can-check-emails"; import computed from "ember-addons/ember-computed-decorators"; import User from "discourse/models/user"; import optionalService from "discourse/lib/optional-service"; import { prioritizeNameInUx } from "discourse/lib/settings"; +import { set } from "@ember/object"; -export default Ember.Controller.extend(CanCheckEmails, { +export default Controller.extend(CanCheckEmails, { indexStream: false, - router: Ember.inject.service(), - userNotifications: Ember.inject.controller("user-notifications"), - currentPath: Ember.computed.alias("router._router.currentPath"), + router: service(), + userNotifications: inject("user-notifications"), + currentPath: alias("router._router.currentPath"), adminTools: optionalService(), @computed("model.username") @@ -24,7 +31,7 @@ export default Ember.Controller.extend(CanCheckEmails, { @computed("model.profileBackgroundUrl") hasProfileBackgroundUrl(background) { - return !Ember.isEmpty(background.toString()); + return !isEmpty(background.toString()); }, @computed("model.profile_hidden", "indexStream", "viewingSelf", "forceExpand") @@ -34,17 +41,14 @@ export default Ember.Controller.extend(CanCheckEmails, { } return (!indexStream || viewingSelf) && !forceExpand; }, - canMuteOrIgnoreUser: Ember.computed.or( - "model.can_ignore_user", - "model.can_mute_user" - ), - hasGivenFlags: Ember.computed.gt("model.number_of_flags_given", 0), - hasFlaggedPosts: Ember.computed.gt("model.number_of_flagged_posts", 0), - hasDeletedPosts: Ember.computed.gt("model.number_of_deleted_posts", 0), - hasBeenSuspended: Ember.computed.gt("model.number_of_suspensions", 0), - hasReceivedWarnings: Ember.computed.gt("model.warnings_received_count", 0), + canMuteOrIgnoreUser: or("model.can_ignore_user", "model.can_mute_user"), + hasGivenFlags: gt("model.number_of_flags_given", 0), + hasFlaggedPosts: gt("model.number_of_flagged_posts", 0), + hasDeletedPosts: gt("model.number_of_deleted_posts", 0), + hasBeenSuspended: gt("model.number_of_suspensions", 0), + hasReceivedWarnings: gt("model.warnings_received_count", 0), - showStaffCounters: Ember.computed.or( + showStaffCounters: or( "hasGivenFlags", "hasFlaggedPosts", "hasDeletedPosts", @@ -57,7 +61,7 @@ export default Ember.Controller.extend(CanCheckEmails, { return !suspended || isStaff; }, - linkWebsite: Ember.computed.not("model.isBasic"), + linkWebsite: not("model.isBasic"), @computed("model.trust_level") removeNoFollow(trustLevel) { @@ -101,27 +105,22 @@ export default Ember.Controller.extend(CanCheckEmails, { return User.currentProp("can_invite_to_forum"); }, - canDeleteUser: Ember.computed.and( - "model.can_be_deleted", - "model.can_delete_all_posts" - ), + canDeleteUser: and("model.can_be_deleted", "model.can_delete_all_posts"), @computed("model.user_fields.@each.value") publicUserFields() { const siteUserFields = this.site.get("user_fields"); - if (!Ember.isEmpty(siteUserFields)) { + if (!isEmpty(siteUserFields)) { const userFields = this.get("model.user_fields"); return siteUserFields .filterBy("show_on_profile", true) .sortBy("position") .map(field => { - Ember.set(field, "dasherized_name", field.get("name").dasherize()); + set(field, "dasherized_name", field.get("name").dasherize()); const value = userFields ? userFields[field.get("id").toString()] : null; - return Ember.isEmpty(value) - ? null - : Ember.Object.create({ value, field }); + return isEmpty(value) ? null : EmberObject.create({ value, field }); }) .compact(); } diff --git a/app/assets/javascripts/discourse/controllers/users.js.es6 b/app/assets/javascripts/discourse/controllers/users.js.es6 index 2fa9a8de59..36e3236ffd 100644 --- a/app/assets/javascripts/discourse/controllers/users.js.es6 +++ b/app/assets/javascripts/discourse/controllers/users.js.es6 @@ -1,7 +1,10 @@ +import { equal } from "@ember/object/computed"; +import { inject } from "@ember/controller"; +import Controller from "@ember/controller"; import debounce from "discourse/lib/debounce"; -export default Ember.Controller.extend({ - application: Ember.inject.controller(), +export default Controller.extend({ + application: inject(), queryParams: ["period", "order", "asc", "name", "group", "exclude_usernames"], period: "weekly", order: "likes_received", @@ -10,7 +13,7 @@ export default Ember.Controller.extend({ group: null, exclude_usernames: null, - showTimeRead: Ember.computed.equal("period", "all"), + showTimeRead: equal("period", "all"), _setName: debounce(function() { this.set("name", this.nameInput); diff --git a/app/assets/javascripts/discourse/helpers/bound-avatar-template.js.es6 b/app/assets/javascripts/discourse/helpers/bound-avatar-template.js.es6 index 30cb9aa3bd..b08e483b2e 100644 --- a/app/assets/javascripts/discourse/helpers/bound-avatar-template.js.es6 +++ b/app/assets/javascripts/discourse/helpers/bound-avatar-template.js.es6 @@ -1,8 +1,9 @@ +import { isEmpty } from "@ember/utils"; import { htmlHelper } from "discourse-common/lib/helpers"; import { avatarImg } from "discourse/lib/utilities"; export default htmlHelper((avatarTemplate, size) => { - if (Ember.isEmpty(avatarTemplate)) { + if (isEmpty(avatarTemplate)) { return "
"; } else { return avatarImg({ size, avatarTemplate }); diff --git a/app/assets/javascripts/discourse/helpers/bound-avatar.js.es6 b/app/assets/javascripts/discourse/helpers/bound-avatar.js.es6 index 077e823220..6504dc1c08 100644 --- a/app/assets/javascripts/discourse/helpers/bound-avatar.js.es6 +++ b/app/assets/javascripts/discourse/helpers/bound-avatar.js.es6 @@ -1,12 +1,14 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; import { htmlHelper } from "discourse-common/lib/helpers"; import { avatarImg } from "discourse/lib/utilities"; import { addExtraUserClasses } from "discourse/helpers/user-avatar"; export default htmlHelper((user, size) => { - if (Ember.isEmpty(user)) { + if (isEmpty(user)) { return "
"; } - const avatarTemplate = Ember.get(user, "avatar_template"); + const avatarTemplate = get(user, "avatar_template"); return avatarImg(addExtraUserClasses(user, { size, avatarTemplate })); }); diff --git a/app/assets/javascripts/discourse/helpers/category-link.js.es6 b/app/assets/javascripts/discourse/helpers/category-link.js.es6 index 7f02dae280..c76382c8df 100644 --- a/app/assets/javascripts/discourse/helpers/category-link.js.es6 +++ b/app/assets/javascripts/discourse/helpers/category-link.js.es6 @@ -1,10 +1,9 @@ +import { get } from "@ember/object"; import { registerUnbound } from "discourse-common/lib/helpers"; import { isRTL } from "discourse/lib/text-direction"; import { iconHTML } from "discourse-common/lib/icon-library"; -var get = Ember.get, - escapeExpression = Handlebars.Utils.escapeExpression; - +let escapeExpression = Handlebars.Utils.escapeExpression; let _renderer = defaultCategoryLinkRenderer; export function replaceCategoryLinkRenderer(fn) { @@ -32,7 +31,7 @@ export function categoryBadgeHTML(category, opts) { if ( !category || (!opts.allowUncategorized && - Ember.get(category, "id") === + get(category, "id") === Discourse.Site.currentProp("uncategorized_category_id") && Discourse.SiteSettings.suppress_uncategorized_badge) ) diff --git a/app/assets/javascripts/discourse/helpers/dash-if-empty.js.es6 b/app/assets/javascripts/discourse/helpers/dash-if-empty.js.es6 index 18370df0d2..96d594e650 100644 --- a/app/assets/javascripts/discourse/helpers/dash-if-empty.js.es6 +++ b/app/assets/javascripts/discourse/helpers/dash-if-empty.js.es6 @@ -1,3 +1,4 @@ +import { isEmpty } from "@ember/utils"; import { htmlHelper } from "discourse-common/lib/helpers"; -export default htmlHelper(str => (Ember.isEmpty(str) ? "—" : str)); +export default htmlHelper(str => (isEmpty(str) ? "—" : str)); diff --git a/app/assets/javascripts/discourse/helpers/dasherize.js.es6 b/app/assets/javascripts/discourse/helpers/dasherize.js.es6 index b824006169..ce9aaed3af 100644 --- a/app/assets/javascripts/discourse/helpers/dasherize.js.es6 +++ b/app/assets/javascripts/discourse/helpers/dasherize.js.es6 @@ -1,5 +1,7 @@ +import Helper from "@ember/component/helper"; + function dasherize([value]) { return (value || "").replace(".", "-").dasherize(); } -export default Ember.Helper.helper(dasherize); +export default Helper.helper(dasherize); diff --git a/app/assets/javascripts/discourse/helpers/editable-value.js.es6 b/app/assets/javascripts/discourse/helpers/editable-value.js.es6 index 799815590a..ae67cedf5e 100644 --- a/app/assets/javascripts/discourse/helpers/editable-value.js.es6 +++ b/app/assets/javascripts/discourse/helpers/editable-value.js.es6 @@ -1,10 +1,13 @@ +import { get } from "@ember/object"; +import Helper from "@ember/component/helper"; + export function formatCurrency([reviewable, fieldId]) { // The field `category_id` corresponds to `category` if (fieldId === "category_id") { fieldId = "category.id"; } - let value = Ember.get(reviewable, fieldId); + let value = get(reviewable, fieldId); // If it's an array, say tags, make a copy so we aren't mutating the original if (Array.isArray(value)) { @@ -14,4 +17,4 @@ export function formatCurrency([reviewable, fieldId]) { return value; } -export default Ember.Helper.helper(formatCurrency); +export default Helper.helper(formatCurrency); diff --git a/app/assets/javascripts/discourse/helpers/icon-or-image.js.es6 b/app/assets/javascripts/discourse/helpers/icon-or-image.js.es6 index 0751b6f0e2..f038d40eb4 100644 --- a/app/assets/javascripts/discourse/helpers/icon-or-image.js.es6 +++ b/app/assets/javascripts/discourse/helpers/icon-or-image.js.es6 @@ -1,12 +1,13 @@ +import { isEmpty } from "@ember/utils"; import { htmlHelper } from "discourse-common/lib/helpers"; import { iconHTML, convertIconClass } from "discourse-common/lib/icon-library"; export default htmlHelper(function({ icon, image }) { - if (!Ember.isEmpty(image)) { + if (!isEmpty(image)) { return ``; } - if (Ember.isEmpty(icon)) { + if (isEmpty(icon)) { return ""; } diff --git a/app/assets/javascripts/discourse/helpers/user-avatar.js.es6 b/app/assets/javascripts/discourse/helpers/user-avatar.js.es6 index ff09e4e2fc..b46a49d6ff 100644 --- a/app/assets/javascripts/discourse/helpers/user-avatar.js.es6 +++ b/app/assets/javascripts/discourse/helpers/user-avatar.js.es6 @@ -1,3 +1,4 @@ +import { get } from "@ember/object"; import { registerUnbound } from "discourse-common/lib/helpers"; import { avatarImg, formatUsername } from "discourse/lib/utilities"; @@ -30,9 +31,9 @@ function renderAvatar(user, options) { options = options || {}; if (user) { - const name = Ember.get(user, options.namePath || "name"); - const username = Ember.get(user, options.usernamePath || "username"); - const avatarTemplate = Ember.get( + const name = get(user, options.namePath || "name"); + const username = get(user, options.usernamePath || "username"); + const avatarTemplate = get( user, options.avatarTemplatePath || "avatar_template" ); @@ -46,11 +47,11 @@ function renderAvatar(user, options) { let title = options.title; if (!title && !options.ignoreTitle) { // first try to get a title - title = Ember.get(user, "title"); + title = get(user, "title"); // if there was no title provided if (!title) { // try to retrieve a description - const description = Ember.get(user, "description"); + const description = get(user, "description"); // if a description has been provided if (description && description.length > 0) { // preprend the username before the description @@ -61,7 +62,7 @@ function renderAvatar(user, options) { return avatarImg({ size: options.imageSize, - extraClasses: Ember.get(user, "extras") || options.extraClasses, + extraClasses: get(user, "extras") || options.extraClasses, title: title || displayName, avatarTemplate: avatarTemplate }); diff --git a/app/assets/javascripts/discourse/initializers/asset-version.js.es6 b/app/assets/javascripts/discourse/initializers/asset-version.js.es6 index 21faedd650..f685d1b091 100644 --- a/app/assets/javascripts/discourse/initializers/asset-version.js.es6 +++ b/app/assets/javascripts/discourse/initializers/asset-version.js.es6 @@ -1,3 +1,4 @@ +import { later } from "@ember/runloop"; // Subscribe to "asset-version" change events via the Message Bus export default { name: "asset-version", @@ -16,7 +17,7 @@ export default { if (!timeoutIsSet && Discourse.get("requiresRefresh")) { // Since we can do this transparently for people browsing the forum // hold back the message 24 hours. - Ember.run.later(() => { + later(() => { bootbox.confirm(I18n.t("assets_changed_confirm"), function(result) { if (result) { document.location.reload(); diff --git a/app/assets/javascripts/discourse/initializers/auth-complete.js.es6 b/app/assets/javascripts/discourse/initializers/auth-complete.js.es6 index 83e0183ff3..31101d9010 100644 --- a/app/assets/javascripts/discourse/initializers/auth-complete.js.es6 +++ b/app/assets/javascripts/discourse/initializers/auth-complete.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; export default { name: "auth-complete", after: "inject-objects", @@ -13,7 +14,7 @@ export default { if (lastAuthResult) { const router = container.lookup("router:main"); router.one("didTransition", () => { - Ember.run.next(() => + next(() => Discourse.authenticationComplete(JSON.parse(lastAuthResult)) ); }); diff --git a/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6 b/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6 index ae3c15e420..3e1505a5dd 100644 --- a/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6 +++ b/app/assets/javascripts/discourse/initializers/auto-load-modules.js.es6 @@ -1,4 +1,6 @@ import { registerHelpers } from "discourse-common/lib/helpers"; +import RawHandlebars from "discourse-common/lib/raw-handlebars"; +import { registerRawHelpers } from "discourse-common/lib/raw-handlebars-helpers"; export function autoLoadModules(container, registry) { Object.keys(requirejs.entries).forEach(entry => { @@ -10,6 +12,7 @@ export function autoLoadModules(container, registry) { } }); registerHelpers(registry); + registerRawHelpers(RawHandlebars, Handlebars); } export default { diff --git a/app/assets/javascripts/discourse/initializers/banner.js.es6 b/app/assets/javascripts/discourse/initializers/banner.js.es6 index 46e3899b30..ccec6a95b4 100644 --- a/app/assets/javascripts/discourse/initializers/banner.js.es6 +++ b/app/assets/javascripts/discourse/initializers/banner.js.es6 @@ -1,3 +1,4 @@ +import EmberObject from "@ember/object"; import PreloadStore from "preload-store"; export default { @@ -5,7 +6,7 @@ export default { after: "message-bus", initialize(container) { - const banner = Ember.Object.create(PreloadStore.get("banner") || {}), + const banner = EmberObject.create(PreloadStore.get("banner") || {}), site = container.lookup("site:main"); site.set("banner", banner); @@ -16,7 +17,7 @@ export default { } messageBus.subscribe("/site/banner", function(ban) { - site.set("banner", Ember.Object.create(ban || {})); + site.set("banner", EmberObject.create(ban || {})); }); } }; diff --git a/app/assets/javascripts/discourse/initializers/localization.js.es6 b/app/assets/javascripts/discourse/initializers/localization.js.es6 index fc9eee1536..cbe50e53d5 100644 --- a/app/assets/javascripts/discourse/initializers/localization.js.es6 +++ b/app/assets/javascripts/discourse/initializers/localization.js.es6 @@ -1,5 +1,3 @@ -import PreloadStore from "preload-store"; - export default { name: "localization", after: "inject-objects", @@ -21,20 +19,9 @@ export default { } // Merge any overrides into our object - const overrides = PreloadStore.get("translationOverrides") || {}; + const overrides = I18n._overrides || {}; Object.keys(overrides).forEach(k => { const v = overrides[k]; - - // Special case: Message format keys are functions - if (/_MF$/.test(k)) { - k = k.replace(/^[a-z_]*js\./, ""); - I18n._compiledMFs[k] = new Function( - "transKey", - `return (${v})(transKey);` - ); - return; - } - k = k.replace("admin_js", "js"); const segs = k.split("."); @@ -52,6 +39,14 @@ export default { } }); + const mfOverrides = I18n._mfOverrides || {}; + Object.keys(mfOverrides).forEach(k => { + const v = mfOverrides[k]; + + k = k.replace(/^[a-z_]*js\./, ""); + I18n._compiledMFs[k] = v; + }); + bootbox.addLocale(I18n.currentLocale(), { OK: I18n.t("composer.modal_ok"), CANCEL: I18n.t("composer.modal_cancel"), diff --git a/app/assets/javascripts/discourse/initializers/mobile.js.es6 b/app/assets/javascripts/discourse/initializers/mobile.js.es6 index a536398e94..b0708fca85 100644 --- a/app/assets/javascripts/discourse/initializers/mobile.js.es6 +++ b/app/assets/javascripts/discourse/initializers/mobile.js.es6 @@ -1,3 +1,4 @@ +import { later } from "@ember/runloop"; import Mobile from "discourse/lib/mobile"; import { setResolverOption } from "discourse-common/resolver"; import { isAppWebview, postRNWebviewMessage } from "discourse/lib/utilities"; @@ -17,7 +18,7 @@ export default { setResolverOption("mobileView", Mobile.mobileView); if (isAppWebview()) { - Ember.run.later(() => { + later(() => { postRNWebviewMessage( "headerBg", $(".d-header").css("background-color") diff --git a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 index d3c251bb88..c79a94ceaf 100644 --- a/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/initializers/subscribe-user-notifications.js.es6 @@ -1,3 +1,4 @@ +import EmberObject from "@ember/object"; // Subscribes to user events on the message bus import { init as initDesktopNotifications, @@ -10,6 +11,7 @@ import { unsubscribe as unsubscribePushNotifications, isPushNotificationsEnabled } from "discourse/lib/push-notifications"; +import { set } from "@ember/object"; export default { name: "subscribe-user-notifications", @@ -82,7 +84,7 @@ export default { } oldNotifications.insertAt( insertPosition, - Ember.Object.create(lastNotification) + EmberObject.create(lastNotification) ); } @@ -119,7 +121,7 @@ export default { }); bus.subscribe("/client_settings", data => - Ember.set(siteSettings, data.name, data.value) + set(siteSettings, data.name, data.value) ); bus.subscribe("/refresh_client", data => Discourse.set("assetVersion", data) diff --git a/app/assets/javascripts/discourse/lib/ajax.js.es6 b/app/assets/javascripts/discourse/lib/ajax.js.es6 index cafa6e6f70..40fd85d686 100644 --- a/app/assets/javascripts/discourse/lib/ajax.js.es6 +++ b/app/assets/javascripts/discourse/lib/ajax.js.es6 @@ -1,5 +1,7 @@ +import { run } from "@ember/runloop"; import pageVisible from "discourse/lib/page-visible"; import logout from "discourse/lib/logout"; +import { Promise } from "rsvp"; let _trackView = false; let _transientHeader = null; @@ -96,7 +98,7 @@ export function ajax() { handleRedirect(data); handleLogoff(xhr); - Ember.run(() => { + run(() => { Discourse.Site.currentProp( "isReadOnly", !!xhr.getResponseHeader("Discourse-Readonly") @@ -107,7 +109,7 @@ export function ajax() { data = { result: data, xhr: xhr }; } - Ember.run(null, resolve, data); + run(null, resolve, data); }; args.error = (xhr, textStatus, errorThrown) => { @@ -128,7 +130,7 @@ export function ajax() { xhr.jqTextStatus = textStatus; xhr.requestedUrl = url; - Ember.run(null, reject, { + run(null, reject, { jqXHR: xhr, textStatus: textStatus, errorThrown: errorThrown @@ -162,13 +164,13 @@ export function ajax() { url !== Discourse.getURL("/clicks/track") && !Discourse.Session.currentProp("csrfToken") ) { - promise = new Ember.RSVP.Promise((resolve, reject) => { + promise = new Promise((resolve, reject) => { ajaxObj = updateCsrfToken().then(() => { performAjax(resolve, reject); }); }); } else { - promise = new Ember.RSVP.Promise(performAjax); + promise = new Promise(performAjax); } promise.abort = () => { diff --git a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 index 18fc9a98e2..0bcb3331c8 100644 --- a/app/assets/javascripts/discourse/lib/autocomplete.js.es6 +++ b/app/assets/javascripts/discourse/lib/autocomplete.js.es6 @@ -1,3 +1,5 @@ +import { cancel } from "@ember/runloop"; +import { later } from "@ember/runloop"; /** This is a jQuery plugin to support autocompleting values in our text fields. @@ -43,7 +45,7 @@ export default function(options) { if (this.length === 0) return; if (options === "destroy" || options.updateData) { - Ember.run.cancel(inputTimeout); + cancel(inputTimeout); $(this) .off("keyup.autocomplete") @@ -402,7 +404,7 @@ export default function(options) { $(this).on("click.autocomplete", () => closeAutocomplete()); $(this).on("paste.autocomplete", () => { - Ember.run.later(() => me.trigger("keydown"), 50); + later(() => me.trigger("keydown"), 50); }); function checkTriggerRule(opts) { @@ -455,8 +457,8 @@ export default function(options) { if (options.allowAny) { // saves us wiring up a change event as well - Ember.run.cancel(inputTimeout); - inputTimeout = Ember.run.later(function() { + cancel(inputTimeout); + inputTimeout = later(function() { if (inputSelectedItems.length === 0) { inputSelectedItems.push(""); } diff --git a/app/assets/javascripts/discourse/lib/cached-topic-list.js.es6 b/app/assets/javascripts/discourse/lib/cached-topic-list.js.es6 new file mode 100644 index 0000000000..78cd2c0c51 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/cached-topic-list.js.es6 @@ -0,0 +1,12 @@ +export function findOrResetCachedTopicList(session, filter) { + const lastTopicList = session.get("topicList"); + if (lastTopicList && lastTopicList.filter === filter) { + return lastTopicList; + } else { + session.setProperties({ + topicList: null, + topicListScrollPosition: null + }); + return false; + } +} diff --git a/app/assets/javascripts/discourse/lib/category-tag-search.js.es6 b/app/assets/javascripts/discourse/lib/category-tag-search.js.es6 index 164839fabf..0b46e05b73 100644 --- a/app/assets/javascripts/discourse/lib/category-tag-search.js.es6 +++ b/app/assets/javascripts/discourse/lib/category-tag-search.js.es6 @@ -3,6 +3,7 @@ import { CANCELLED_STATUS } from "discourse/lib/autocomplete"; import Category from "discourse/models/category"; import { TAG_HASHTAG_POSTFIX } from "discourse/lib/tag-hashtags"; import { SEPARATOR } from "discourse/lib/category-hashtags"; +import { Promise } from "rsvp"; var cache = {}; var cacheTime; @@ -15,7 +16,7 @@ function updateCache(term, results) { } function searchTags(term, categories, limit) { - return new Ember.RSVP.Promise(resolve => { + return new Promise(resolve => { const clearPromise = setTimeout(() => { resolve(CANCELLED_STATUS); }, 5000); diff --git a/app/assets/javascripts/discourse/lib/clean-dom.js.es6 b/app/assets/javascripts/discourse/lib/clean-dom.js.es6 index 8d83f4d7f8..82cdb2d537 100644 --- a/app/assets/javascripts/discourse/lib/clean-dom.js.es6 +++ b/app/assets/javascripts/discourse/lib/clean-dom.js.es6 @@ -1,3 +1,4 @@ +import { scheduleOnce } from "@ember/runloop"; function _clean() { if (window.MiniProfiler) { window.MiniProfiler.pageTransition(); @@ -35,5 +36,5 @@ function _clean() { } export function cleanDOM() { - Ember.run.scheduleOnce("afterRender", _clean); + scheduleOnce("afterRender", _clean); } diff --git a/app/assets/javascripts/discourse/lib/click-track.js.es6 b/app/assets/javascripts/discourse/lib/click-track.js.es6 index 42a65623a6..12abc76152 100644 --- a/app/assets/javascripts/discourse/lib/click-track.js.es6 +++ b/app/assets/javascripts/discourse/lib/click-track.js.es6 @@ -1,7 +1,9 @@ +import { later } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; import DiscourseURL from "discourse/lib/url"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import { selectedText } from "discourse/lib/utilities"; +import { Promise } from "rsvp"; export function isValidLink($link) { // Do not track: @@ -95,7 +97,7 @@ export default { } } - let trackPromise = Ember.RSVP.resolve(); + let trackPromise = Promise.resolve(); if (tracking) { if (!Ember.testing && navigator.sendBeacon) { const data = new FormData(); @@ -134,7 +136,7 @@ export default { $link.attr("href", null); $link.data("auto-route", true); - Ember.run.later(() => { + later(() => { $link.removeClass("no-href"); $link.attr("href", $link.data("href")); $link.data("href", null); diff --git a/app/assets/javascripts/discourse/lib/debounce.js.es6 b/app/assets/javascripts/discourse/lib/debounce.js.es6 index 6ab2eb1e58..f41b71f0d8 100644 --- a/app/assets/javascripts/discourse/lib/debounce.js.es6 +++ b/app/assets/javascripts/discourse/lib/debounce.js.es6 @@ -1,3 +1,4 @@ +import { debounce } from "@ember/runloop"; /** Debounce a Javascript function. This means if it's called many times in a time limit it should only be executed once (at the end of the limit counted from the last call made). @@ -13,6 +14,6 @@ export default function(func, wait) { self = this; args = arguments; - Ember.run.debounce(null, later, wait); + debounce(null, later, wait); }; } diff --git a/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6 b/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6 index 41b86bc30e..52c0449285 100644 --- a/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6 +++ b/app/assets/javascripts/discourse/lib/desktop-notifications.js.es6 @@ -1,6 +1,8 @@ +import { later } from "@ember/runloop"; import DiscourseURL from "discourse/lib/url"; import KeyValueStore from "discourse/lib/key-value-store"; import { formatUsername } from "discourse/lib/utilities"; +import { Promise } from "rsvp"; let primaryTab = false; let liveEnabled = false; @@ -79,7 +81,7 @@ function confirmNotification() { const clickEventHandler = () => notification.close(); notification.addEventListener("click", clickEventHandler); - Ember.run.later(() => { + later(() => { notification.close(); notification.removeEventListener("click", clickEventHandler); }, 10 * 1000); @@ -177,7 +179,7 @@ function onNotification(data) { } notification.addEventListener("click", clickEventHandler); - Ember.run.later(() => { + later(() => { notification.close(); notification.removeEventListener("click", clickEventHandler); }, 10 * 1000); @@ -188,11 +190,11 @@ function onNotification(data) { // Wraps Notification.requestPermission in a Promise function requestPermission() { if (havePermission === true) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } else if (havePermission === false) { - return Ember.RSVP.reject(); + return Promise.reject(); } else { - return new Ember.RSVP.Promise(function(resolve, reject) { + return new Promise(function(resolve, reject) { Notification.requestPermission(function(status) { if (status === "granted") { resolve(); diff --git a/app/assets/javascripts/discourse/lib/discourse-location.js.es6 b/app/assets/javascripts/discourse/lib/discourse-location.js.es6 index 3843831588..b1238d8d39 100644 --- a/app/assets/javascripts/discourse/lib/discourse-location.js.es6 +++ b/app/assets/javascripts/discourse/lib/discourse-location.js.es6 @@ -1,3 +1,4 @@ +import EmberObject from "@ember/object"; import { defaultHomepage } from "discourse/lib/utilities"; let popstateFired = false; const supportsHistoryState = window.history && "state" in window.history; @@ -9,9 +10,9 @@ const popstateCallbacks = []; @class DiscourseLocation @namespace Discourse - @extends Ember.Object + @extends @ember/object */ -const DiscourseLocation = Ember.Object.extend({ +const DiscourseLocation = EmberObject.extend({ init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 index e051f479ff..991644737a 100644 --- a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 +++ b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 @@ -1,3 +1,5 @@ +import { run } from "@ember/runloop"; +import { later } from "@ember/runloop"; import DiscourseURL from "discourse/lib/url"; import Composer from "discourse/models/composer"; import { minimumOffset } from "discourse/lib/offset-calculator"; @@ -140,7 +142,7 @@ export default { quoteReply() { this.sendToSelectedPost("replyToPost"); // lazy but should work for now - Ember.run.later(() => $(".d-editor .quote").click(), 500); + later(() => $(".d-editor .quote").click(), 500); return false; }, @@ -210,7 +212,7 @@ export default { }, showPageSearch(event) { - Ember.run(() => { + run(() => { this.appEvents.trigger("header:keyboard-trigger", { type: "page-search", event @@ -219,7 +221,7 @@ export default { }, printTopic(event) { - Ember.run(() => { + run(() => { if ($(".container.posts").length) { event.preventDefault(); // We need to stop printing the current page in Firefox this.container.lookup("controller:topic").print(); @@ -241,7 +243,7 @@ export default { this.container.lookup("controller:composer").open({ action: Composer.CREATE_TOPIC, - draftKey: Composer.CREATE_TOPIC + draftKey: Composer.NEW_TOPIC_KEY }); }, diff --git a/app/assets/javascripts/discourse/lib/link-category-hashtags.js.es6 b/app/assets/javascripts/discourse/lib/link-category-hashtags.js.es6 index d43b0f4a83..7179f234f1 100644 --- a/app/assets/javascripts/discourse/lib/link-category-hashtags.js.es6 +++ b/app/assets/javascripts/discourse/lib/link-category-hashtags.js.es6 @@ -1,3 +1,4 @@ +import { schedule } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; import { replaceSpan } from "discourse/lib/category-hashtags"; @@ -7,7 +8,7 @@ const testedKey = "tested"; const testedClass = `hashtag-${testedKey}`; function updateFound($hashtags, categorySlugs) { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $hashtags.each((index, hashtag) => { const categorySlug = categorySlugs[index]; const link = validCategoryHashtags[categorySlug]; diff --git a/app/assets/javascripts/discourse/lib/link-mentions.js.es6 b/app/assets/javascripts/discourse/lib/link-mentions.js.es6 index 07f37388e4..68d0b8b5d6 100644 --- a/app/assets/javascripts/discourse/lib/link-mentions.js.es6 +++ b/app/assets/javascripts/discourse/lib/link-mentions.js.es6 @@ -1,3 +1,4 @@ +import { scheduleOnce } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; import { userPath } from "discourse/lib/url"; import { formatUsername } from "discourse/lib/utilities"; @@ -39,7 +40,7 @@ const checked = {}; const cannotSee = []; function updateFound($mentions, usernames) { - Ember.run.scheduleOnce("afterRender", function() { + scheduleOnce("afterRender", function() { $mentions.each((i, e) => { const $e = $(e); const username = usernames[i]; diff --git a/app/assets/javascripts/discourse/lib/link-tag-hashtag.js.es6 b/app/assets/javascripts/discourse/lib/link-tag-hashtag.js.es6 index a0b2c95c46..5aa3f6d612 100644 --- a/app/assets/javascripts/discourse/lib/link-tag-hashtag.js.es6 +++ b/app/assets/javascripts/discourse/lib/link-tag-hashtag.js.es6 @@ -1,3 +1,4 @@ +import { schedule } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; import { replaceSpan } from "discourse/lib/category-hashtags"; import { TAG_HASHTAG_POSTFIX } from "discourse/lib/tag-hashtags"; @@ -7,7 +8,7 @@ const checkedTagHashtags = []; const testedClass = "tag-hashtag-tested"; function updateFound($hashtags, tagValues) { - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { $hashtags.each((index, hashtag) => { const tagValue = tagValues[index]; const link = validTagHashtags[tagValue]; diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 34b3f2897b..1efec2ea78 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -1,4 +1,7 @@ +import { run } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; +import { Promise } from "rsvp"; + const _loaded = {}; const _loading = {}; @@ -22,7 +25,7 @@ function loadWithTag(path, cb) { ) { s = s.onload = s.onreadystatechange = null; if (!abort) { - Ember.run(null, cb); + run(null, cb); } } }; @@ -37,7 +40,7 @@ export function loadCSS(url) { export default function loadScript(url, opts) { // TODO: Remove this once plugins have been updated not to use it: if (url === "defer/html-sanitizer-bundle") { - return Ember.RSVP.Promise.resolve(); + return Promise.resolve(); } opts = opts || {}; @@ -54,7 +57,7 @@ export default function loadScript(url, opts) { } }); - return new Ember.RSVP.Promise(function(resolve) { + return new Promise(function(resolve) { // If we already loaded this url if (_loaded[url]) { return resolve(); @@ -64,7 +67,7 @@ export default function loadScript(url, opts) { } let done; - _loading[url] = new Ember.RSVP.Promise(function(_done) { + _loading[url] = new Promise(function(_done) { done = _done; }); diff --git a/app/assets/javascripts/discourse/lib/logout.js.es6 b/app/assets/javascripts/discourse/lib/logout.js.es6 index 5e81d738e3..09986e892b 100644 --- a/app/assets/javascripts/discourse/lib/logout.js.es6 +++ b/app/assets/javascripts/discourse/lib/logout.js.es6 @@ -1,3 +1,4 @@ +import { isEmpty } from "@ember/utils"; export default function logout(siteSettings, keyValueStore) { if (!siteSettings || !keyValueStore) { const container = Discourse.__container__; @@ -8,7 +9,7 @@ export default function logout(siteSettings, keyValueStore) { keyValueStore.abandonLocal(); const redirect = siteSettings.logout_redirect; - if (Ember.isEmpty(redirect)) { + if (isEmpty(redirect)) { window.location = Discourse.getURL("/"); } else { window.location.href = redirect; diff --git a/app/assets/javascripts/discourse/lib/page-tracker.js.es6 b/app/assets/javascripts/discourse/lib/page-tracker.js.es6 index d7577ed5ae..4acbdc4ea3 100644 --- a/app/assets/javascripts/discourse/lib/page-tracker.js.es6 +++ b/app/assets/javascripts/discourse/lib/page-tracker.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; let _started = false; let cache = {}; let transitionCount = 0; @@ -31,7 +32,7 @@ export function startPageTracking(router, appEvents) { // Refreshing the title is debounced, so we need to trigger this in the // next runloop to have the correct title. - Ember.run.next(() => { + next(() => { let title = Discourse.get("_docTitle"); appEvents.trigger("page:changed", { diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index 4cf670b3de..88f2d7381d 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -43,9 +43,10 @@ import Sharing from "discourse/lib/sharing"; import { addComposerUploadHandler } from "discourse/components/composer-editor"; import { addCategorySortCriteria } from "discourse/components/edit-category-settings"; import { queryRegistry } from "discourse/widgets/widget"; +import Composer from "discourse/models/composer"; // If you add any methods to the API ensure you bump up this number -const PLUGIN_API_VERSION = "0.8.32"; +const PLUGIN_API_VERSION = "0.8.36"; class PluginApi { constructor(version, container) { @@ -424,45 +425,45 @@ class PluginApi { } /** - Called whenever the "page" changes. This allows us to set up analytics - and other tracking. + Called whenever the "page" changes. This allows us to set up analytics + and other tracking. - To get notified when the page changes, you can install a hook like so: + To get notified when the page changes, you can install a hook like so: - ```javascript - api.onPageChange((url, title) => { + ```javascript + api.onPageChange((url, title) => { console.log('the page changed to: ' + url + ' and title ' + title); }); - ``` - **/ + ``` + **/ onPageChange(fn) { this.onAppEvent("page:changed", data => fn(data.url, data.title)); } /** - Listen for a triggered `AppEvent` from Discourse. + Listen for a triggered `AppEvent` from Discourse. - ```javascript - api.onAppEvent('inserted-custom-html', () => { + ```javascript + api.onAppEvent('inserted-custom-html', () => { console.log('a custom footer was rendered'); }); - ``` - **/ + ``` + **/ onAppEvent(name, fn) { const appEvents = this._lookupContainer("service:app-events"); appEvents && appEvents.on(name, fn); } /** - Registers a function to generate custom avatar CSS classes - for a particular user. + Registers a function to generate custom avatar CSS classes + for a particular user. - Takes a function that will accept a user as a parameter - and return an array of CSS classes to apply. + Takes a function that will accept a user as a parameter + and return an array of CSS classes to apply. - ```javascript - api.customUserAvatarClasses(user => { - if (Ember.get(user, 'primary_group_name') === 'managers') { + ```javascript + api.customUserAvatarClasses(user => { + if (get(user, 'primary_group_name') === 'managers') { return ['managers']; } }); @@ -715,7 +716,7 @@ class PluginApi { /** * - * Adds a new item in the navigation bar. + * Adds a new item in the navigation bar. Returns the NavItem object created. * * Example: * @@ -728,14 +729,20 @@ class PluginApi { * An optional `customFilter` callback can be included to not display the * nav item on certain routes * + * An optional `init` callback can be included to run custom code on menu + * init + * * Example: * * addNavigationBarItem({ * name: "link-to-bugs-category", * displayName: "bugs" * href: "/c/bugs", + * init: (navItem, category) => { if (category) { navItem.set("category", category) } } * customFilter: (category, args, router) => { category && category.name !== 'bug' } - * customHref: (category, args, router) => { if (category && category.name) === 'not-a-bug') "/a-feature"; } + * customHref: (category, args, router) => { if (category && category.name) === 'not-a-bug') "/a-feature"; }, + * before: "top", + * forceActive(category, args, router) => router.currentURL === "/a/b/c/d"; * }) */ addNavigationBarItem(item) { @@ -762,7 +769,23 @@ class PluginApi { }; } - addNavItem(item); + const forceActive = item.forceActive; + if (forceActive) { + const router = this.container.lookup("service:router"); + item.forceActive = function(category, args) { + return forceActive(category, args, router); + }; + } + + const init = item.init; + if (init) { + const router = this.container.lookup("service:router"); + item.init = function(navItem, category, args) { + init(navItem, category, args, router); + }; + } + + return addNavItem(item); } } @@ -790,7 +813,7 @@ class PluginApi { * * Example: * - * modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{ + * api.modifySelectKit("topic-footer-mobile-dropdown").appendContent(() => [{ * name: "discourse", * id: 1 * }]) @@ -806,7 +829,7 @@ class PluginApi { * * Example: * - * addGTMPageChangedCallback( gtmData => gtmData.locale = I18n.currentLocale() ) + * api.addGTMPageChangedCallback( gtmData => gtmData.locale = I18n.currentLocale() ) * */ addGTMPageChangedCallback(fn) { @@ -820,7 +843,7 @@ class PluginApi { * Example: * * // read /discourse/lib/sharing.js.es6 for options - * addSharingSource(options) + * api.addSharingSource(options) * */ addSharingSource(options) { @@ -836,14 +859,43 @@ class PluginApi { * * Example: * - * addComposerUploadHandler(["mp4", "mov"], (file, editor) => { - * console.log("Handling upload for", file.name); + * api.addComposerUploadHandler(["mp4", "mov"], (file, editor) => { + * console.log("Handling upload for", file.name); * }) */ addComposerUploadHandler(extensions, method) { addComposerUploadHandler(extensions, method); } + /** + * Registers a "beforeSave" function on the composer. This allows you to + * implement custom logic that will happen before the user makes a post. + * + * Example: + * + * api.composerBeforeSave(() => { + * console.log("Before saving, do something!"); + * }) + */ + composerBeforeSave(method) { + Composer.reopen({ beforeSave: method }); + } + + /** + * Adds a field to draft serializer + * + * Example: + * + * api.serializeToDraft('key_set_in_model', 'field_name_in_payload'); + * + * to keep both of them same + * api.serializeToDraft('field_name'); + * + */ + serializeToDraft(fieldName, property) { + Composer.serializeToDraft(fieldName, property); + } + /** * Registers a criteria that can be used as default topic order on category * pages. diff --git a/app/assets/javascripts/discourse/lib/posts-with-placeholders.js.es6 b/app/assets/javascripts/discourse/lib/posts-with-placeholders.js.es6 index 03271c6d6b..d1b2092445 100644 --- a/app/assets/javascripts/discourse/lib/posts-with-placeholders.js.es6 +++ b/app/assets/javascripts/discourse/lib/posts-with-placeholders.js.es6 @@ -1,10 +1,11 @@ +import EmberObject from "@ember/object"; import { default as computed } from "ember-addons/ember-computed-decorators"; export function Placeholder(viewName) { this.viewName = viewName; } -export default Ember.Object.extend(Ember.Array, { +export default EmberObject.extend(Ember.Array, { posts: null, _appendingIds: null, diff --git a/app/assets/javascripts/discourse/lib/pwa-utils.js.es6 b/app/assets/javascripts/discourse/lib/pwa-utils.js.es6 index c1833da32b..1e2c901bd6 100644 --- a/app/assets/javascripts/discourse/lib/pwa-utils.js.es6 +++ b/app/assets/javascripts/discourse/lib/pwa-utils.js.es6 @@ -1,6 +1,8 @@ +import { Promise } from "rsvp"; + export function nativeShare(data) { const caps = Discourse.__container__.lookup("capabilities:main"); - return new Ember.RSVP.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (!(caps.isIOS || caps.isAndroid || caps.isWinphone)) { reject(); return; diff --git a/app/assets/javascripts/discourse/lib/render-topic-featured-link.js.es6 b/app/assets/javascripts/discourse/lib/render-topic-featured-link.js.es6 index 7fa722a28d..bcf13b115a 100644 --- a/app/assets/javascripts/discourse/lib/render-topic-featured-link.js.es6 +++ b/app/assets/javascripts/discourse/lib/render-topic-featured-link.js.es6 @@ -21,7 +21,7 @@ export function extractLinkMeta(topic) { target: target, href, domain: topic.get("featured_link_root_domain"), - rel: "nofollow" + rel: "nofollow ugc" }; if (_decorators.length) { diff --git a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 index 1fb5318045..afb55f7f8b 100644 --- a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 +++ b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 @@ -1,3 +1,4 @@ +import { later } from "@ember/runloop"; import debounce from "discourse/lib/debounce"; import { safariHacksDisabled, @@ -94,10 +95,7 @@ function positioningWorkaround($fixedElement) { if (!iOSWithVisualViewport()) { fixedElement.style.height = oldHeight; - Ember.run.later( - () => $(fixedElement).removeClass("no-transition"), - 500 - ); + later(() => $(fixedElement).removeClass("no-transition"), 500); } $(window).scrollTop(originalScrollTop); @@ -114,9 +112,16 @@ function positioningWorkaround($fixedElement) { // document.activeElement is also unreliable (iOS does not mark buttons as focused) // so instead, we store the last touched element and check against it + // cancel blur event if user is: + // - switching to another iOS app + // - invoking a select-kit dropdown + // - invoking mentions + // - invoking a toolbar button if ( lastTouchedElement && - ($(lastTouchedElement).hasClass("select-kit-header") || + (document.visibilityState === "hidden" || + $(lastTouchedElement).hasClass("select-kit-header") || + $(lastTouchedElement).closest(".autocomplete").length || ["span", "svg", "button"].includes( lastTouchedElement.nodeName.toLowerCase() )) diff --git a/app/assets/javascripts/discourse/lib/screen-track.js.es6 b/app/assets/javascripts/discourse/lib/screen-track.js.es6 index a36b15cb21..314e1fac0a 100644 --- a/app/assets/javascripts/discourse/lib/screen-track.js.es6 +++ b/app/assets/javascripts/discourse/lib/screen-track.js.es6 @@ -1,3 +1,4 @@ +import { bind } from "@ember/runloop"; import { ajax } from "discourse/lib/ajax"; // We use this class to track how long posts in a topic are on the screen. @@ -26,7 +27,7 @@ export default class { // Create an interval timer if we don't have one. if (!this._interval) { this._interval = setInterval(() => this.tick(), 1000); - this._boundScrolled = Ember.run.bind(this, this.scrolled); + this._boundScrolled = bind(this, this.scrolled); $(window).on("scroll.screentrack", this._boundScrolled); } diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6 index b8e7dd0546..2824268e66 100644 --- a/app/assets/javascripts/discourse/lib/search.js.es6 +++ b/app/assets/javascripts/discourse/lib/search.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { findRawTemplate } from "discourse/lib/raw-templates"; import Category from "discourse/models/category"; @@ -52,7 +54,7 @@ export function translateResults(results, opts) { const fullName = Handlebars.Utils.escapeExpression( group.full_name || group.display_name ); - const flairUrl = Ember.isEmpty(group.flair_url) + const flairUrl = isEmpty(group.flair_url) ? null : Handlebars.Utils.escapeExpression(group.flair_url); const flairColor = Handlebars.Utils.escapeExpression(group.flair_color); @@ -75,7 +77,7 @@ export function translateResults(results, opts) { results.tags = results.tags .map(function(tag) { const tagName = Handlebars.Utils.escapeExpression(tag.name); - return Ember.Object.create({ + return EmberObject.create({ id: tagName, url: Discourse.getURL("/tags/" + tagName) }); @@ -127,7 +129,7 @@ export function translateResults(results, opts) { !results.categories.length ); - return noResults ? null : Ember.Object.create(results); + return noResults ? null : EmberObject.create(results); } export function searchForTerm(term, opts) { diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index 8cf5a2b0be..968f1e399d 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,3 +1,5 @@ +import { dasherize } from "@ember/string"; + export default function(name, opts) { opts = opts || {}; const container = Discourse.__container__; @@ -13,7 +15,7 @@ export default function(name, opts) { modalController.set("name", controllerName); let controller = container.lookup("controller:" + controllerName); - const templateName = opts.templateName || Ember.String.dasherize(name); + const templateName = opts.templateName || dasherize(name); const renderArgs = { into: "modal", outlet: "modalBody" }; if (controller) { diff --git a/app/assets/javascripts/discourse/lib/static-route-builder.js.es6 b/app/assets/javascripts/discourse/lib/static-route-builder.js.es6 index efc97411c0..8baa97fb4d 100644 --- a/app/assets/javascripts/discourse/lib/static-route-builder.js.es6 +++ b/app/assets/javascripts/discourse/lib/static-route-builder.js.es6 @@ -1,3 +1,4 @@ +import DiscourseRoute from "discourse/routes/discourse"; import StaticPage from "discourse/models/static-page"; import { default as DiscourseURL, jumpToElement } from "discourse/lib/url"; @@ -8,7 +9,7 @@ const configs = { }; export default function(page) { - return Discourse.Route.extend({ + return DiscourseRoute.extend({ renderTemplate() { this.render("static"); }, diff --git a/app/assets/javascripts/discourse/lib/text.js.es6 b/app/assets/javascripts/discourse/lib/text.js.es6 index cb02036ced..2767426c09 100644 --- a/app/assets/javascripts/discourse/lib/text.js.es6 +++ b/app/assets/javascripts/discourse/lib/text.js.es6 @@ -4,6 +4,7 @@ import WhiteLister from "pretty-text/white-lister"; import { sanitize as textSanitize } from "pretty-text/sanitizer"; import loadScript from "discourse/lib/load-script"; import { formatUsername } from "discourse/lib/utilities"; +import { Promise } from "rsvp"; function getOpts(opts) { const siteSettings = Discourse.__container__.lookup("site-settings:main"), @@ -51,7 +52,7 @@ function loadMarkdownIt() { console.error(e); }); } else { - return Ember.RSVP.Promise.resolve(); + return Promise.resolve(); } } diff --git a/app/assets/javascripts/discourse/lib/throttle.js.es6 b/app/assets/javascripts/discourse/lib/throttle.js.es6 index 2e8673203b..05daa36c5a 100644 --- a/app/assets/javascripts/discourse/lib/throttle.js.es6 +++ b/app/assets/javascripts/discourse/lib/throttle.js.es6 @@ -1,3 +1,4 @@ +import { throttle } from "@ember/runloop"; /** Throttle a Javascript function. This means if it's called many times in a time limit it should only be executed one time at most during this time limit @@ -13,6 +14,6 @@ export default function(func, spacing, immediate) { self = this; args = arguments; - Ember.run.throttle(null, later, spacing, immediate); + throttle(null, later, spacing, immediate); }; } diff --git a/app/assets/javascripts/discourse/lib/transform-post.js.es6 b/app/assets/javascripts/discourse/lib/transform-post.js.es6 index 5f882d8a93..e6583cf8f6 100644 --- a/app/assets/javascripts/discourse/lib/transform-post.js.es6 +++ b/app/assets/javascripts/discourse/lib/transform-post.js.es6 @@ -1,3 +1,4 @@ +import { isEmpty } from "@ember/utils"; import { userPath } from "discourse/lib/url"; const _additionalAttributes = []; @@ -48,7 +49,7 @@ export function transformBasicPost(post) { showFlagDelete: false, canRecover: post.can_recover, canEdit: post.can_edit, - canFlag: !Ember.isEmpty(post.get("flagsAvailable")), + canFlag: !isEmpty(post.get("flagsAvailable")), canReviewTopic: false, reviewableId: post.reviewable_id, reviewableScoreCount: post.reviewable_score_count, diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index 34bb600e07..71986d4d29 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -1,3 +1,7 @@ +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; import offsetCalculator from "discourse/lib/offset-calculator"; import LockOn from "discourse/lib/lock-on"; import { defaultHomepage } from "discourse/lib/utilities"; @@ -59,13 +63,13 @@ export function groupPath(subPath) { let _jumpScheduled = false; export function jumpToElement(elementId) { - if (_jumpScheduled || Ember.isEmpty(elementId)) { + if (_jumpScheduled || isEmpty(elementId)) { return; } const selector = `#${elementId}, a[name=${elementId}]`; _jumpScheduled = true; - Ember.run.schedule("afterRender", function() { + schedule("afterRender", function() { const lockon = new LockOn(selector, { finished() { _jumpScheduled = false; @@ -77,7 +81,7 @@ export function jumpToElement(elementId) { let _transitioning = false; -const DiscourseURL = Ember.Object.extend({ +const DiscourseURL = EmberObject.extend({ isJumpScheduled() { return _transitioning || _jumpScheduled; }, @@ -89,7 +93,7 @@ const DiscourseURL = Ember.Object.extend({ _transitioning = postNumber > 1; - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { let elementId; let holder; @@ -155,7 +159,7 @@ const DiscourseURL = Ember.Object.extend({ // Always use replaceState in the next runloop to prevent weird routes changing // while URLs are loading. For example, while a topic loads it sets `currentPost` // which triggers a replaceState even though the topic hasn't fully loaded yet! - Ember.run.next(() => { + next(() => { const location = DiscourseURL.get("router.location"); if (location && location.replaceURL) { location.replaceURL(path); @@ -188,7 +192,7 @@ const DiscourseURL = Ember.Object.extend({ routeTo(path, opts) { opts = opts || {}; - if (Ember.isEmpty(path)) { + if (isEmpty(path)) { return; } @@ -249,7 +253,7 @@ const DiscourseURL = Ember.Object.extend({ path = rewritePath(path); if (typeof opts.afterRouteComplete === "function") { - Ember.run.schedule("afterRender", opts.afterRouteComplete); + schedule("afterRender", opts.afterRouteComplete); } if (this.navigatedToPost(oldPath, path, opts)) { diff --git a/app/assets/javascripts/discourse/lib/user-search.js.es6 b/app/assets/javascripts/discourse/lib/user-search.js.es6 index 1cb70232e9..63fbb2da71 100644 --- a/app/assets/javascripts/discourse/lib/user-search.js.es6 +++ b/app/assets/javascripts/discourse/lib/user-search.js.es6 @@ -2,6 +2,7 @@ import debounce from "discourse/lib/debounce"; import { CANCELLED_STATUS } from "discourse/lib/autocomplete"; import { userPath } from "discourse/lib/url"; import { emailValid } from "discourse/lib/utilities"; +import { Promise } from "rsvp"; var cache = {}, cacheKey, @@ -26,11 +27,13 @@ function performSearch( return; } - // I am not strongly against unconditionally returning - // however this allows us to return a list of probable - // users we want to mention, early on a topic - if (term === "" && !topicId && !categoryId) { - return []; + const eagerComplete = term === "" && !!(topicId || categoryId); + + if (term === "" && !eagerComplete) { + // The server returns no results in this case, so no point checking + // do not return empty list, because autocomplete will get terminated + resultsFn(CANCELLED_STATUS); + return; } // need to be able to cancel this @@ -51,6 +54,18 @@ function performSearch( oldSearch .then(function(r) { + const hasResults = !!( + (r.users && r.users.length) || + (r.groups && r.groups.length) || + (r.emails && r.emails.length) + ); + + if (eagerComplete && !hasResults) { + // we are trying to eager load, but received no results + // do not return empty list, because autocomplete will get terminated + r = CANCELLED_STATUS; + } + cache[term] = r; cacheTime = new Date(); // If there is a newer search term, return null @@ -152,7 +167,7 @@ export default function userSearch(options) { currentTerm = term; - return new Ember.RSVP.Promise(function(resolve) { + return new Promise(function(resolve) { const newCacheKey = `${topicId}-${categoryId}`; if (new Date() - cacheTime > 30000 || cacheKey !== newCacheKey) { diff --git a/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6 b/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6 deleted file mode 100644 index 449030dad2..0000000000 --- a/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6 +++ /dev/null @@ -1,39 +0,0 @@ -import Badge from "discourse/models/badge"; -import computed from "ember-addons/ember-computed-decorators"; - -export default Ember.Mixin.create({ - saving: false, - saved: false, - - @computed("filteredList") - selectableUserBadges(items) { - items = _.uniq(items, false, function(e) { - return e.get("badge.name"); - }); - items.unshiftObject( - Ember.Object.create({ - badge: Badge.create({ name: I18n.t("badges.none") }) - }) - ); - return items; - }, - - @computed("saving") - savingStatus(saving) { - return saving ? I18n.t("saving") : I18n.t("save"); - }, - - @computed("selectedUserBadgeId") - selectedUserBadge(selectedUserBadgeId) { - selectedUserBadgeId = parseInt(selectedUserBadgeId); - let selectedUserBadge = null; - this.selectableUserBadges.forEach(function(userBadge) { - if (userBadge.get("id") === selectedUserBadgeId) { - selectedUserBadge = userBadge; - } - }); - return selectedUserBadge; - }, - - disableSave: Ember.computed.alias("saving") -}); diff --git a/app/assets/javascripts/discourse/mixins/buffered-content.js.es6 b/app/assets/javascripts/discourse/mixins/buffered-content.js.es6 index 36f6de6071..08723e1486 100644 --- a/app/assets/javascripts/discourse/mixins/buffered-content.js.es6 +++ b/app/assets/javascripts/discourse/mixins/buffered-content.js.es6 @@ -1,8 +1,11 @@ +import EmberObjectProxy from "@ember/object/proxy"; +import Mixin from "@ember/object/mixin"; + /* global BufferedProxy: true */ export function bufferedProperty(property) { const mixin = { buffered: Ember.computed(property, function() { - return Ember.ObjectProxy.extend(BufferedProxy).create({ + return EmberObjectProxy.extend(BufferedProxy).create({ content: this.get(property) }); }), @@ -19,7 +22,7 @@ export function bufferedProperty(property) { // It's a good idea to null out fields when declaring objects mixin.property = null; - return Ember.Mixin.create(mixin); + return Mixin.create(mixin); } export default bufferedProperty("content"); diff --git a/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6 b/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6 index 411dfb6688..311e47661d 100644 --- a/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6 +++ b/app/assets/javascripts/discourse/mixins/bulk-topic-selection.js.es6 @@ -1,11 +1,13 @@ +import { alias } from "@ember/object/computed"; import { NotificationLevels } from "discourse/lib/notification-levels"; import { on } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ bulkSelectEnabled: false, selected: null, - canBulkSelect: Ember.computed.alias("currentUser.staff"), + canBulkSelect: alias("currentUser.staff"), @on("init") resetSelected() { diff --git a/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 b/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 index a7eb59fe7b..9e203da744 100644 --- a/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 +++ b/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 @@ -1,14 +1,13 @@ +import { and, alias, or } from "@ember/object/computed"; import { propertyEqual, setting } from "discourse/lib/computed"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ isCurrentUser: propertyEqual("model.id", "currentUser.id"), showEmailOnProfile: setting("moderators_view_emails"), - canStaffCheckEmails: Ember.computed.and( - "showEmailOnProfile", - "currentUser.staff" - ), - canAdminCheckEmails: Ember.computed.alias("currentUser.admin"), - canCheckEmails: Ember.computed.or( + canStaffCheckEmails: and("showEmailOnProfile", "currentUser.staff"), + canAdminCheckEmails: alias("currentUser.admin"), + canCheckEmails: or( "isCurrentUser", "canStaffCheckEmails", "canAdminCheckEmails" diff --git a/app/assets/javascripts/discourse/mixins/card-contents-base.js.es6 b/app/assets/javascripts/discourse/mixins/card-contents-base.js.es6 index 212278f2e0..e9c0c0df56 100644 --- a/app/assets/javascripts/discourse/mixins/card-contents-base.js.es6 +++ b/app/assets/javascripts/discourse/mixins/card-contents-base.js.es6 @@ -1,14 +1,19 @@ +import { alias, match } from "@ember/object/computed"; +import { throttle } from "@ember/runloop"; +import { next } from "@ember/runloop"; +import { schedule } from "@ember/runloop"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import afterTransition from "discourse/lib/after-transition"; import DiscourseURL from "discourse/lib/url"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ elementId: null, //click detection added for data-{elementId} triggeringLinkClass: null, //the classname where this card should appear _showCallback: null, //username, $target - load up data for when show is called, should call this._positionCard($target) when it's done. - postStream: Ember.computed.alias("topic.postStream"), - viewingTopic: Ember.computed.match("currentPath", /^topic\./), + postStream: alias("topic.postStream"), + viewingTopic: match("currentPath", /^topic\./), visible: false, username: null, @@ -142,7 +147,7 @@ export default Ember.Mixin.create({ _bindMobileScroll() { const mobileScrollEvent = this.mobileScrollEvent; const onScroll = () => { - Ember.run.throttle(this, this._close, 1000); + throttle(this, this._close, 1000); }; $(window).on(mobileScrollEvent, onScroll); @@ -171,7 +176,7 @@ export default Ember.Mixin.create({ let verticalAdjustments = 0; - Ember.run.schedule("afterRender", () => { + schedule("afterRender", () => { if (target) { if (!this.site.mobileView) { let position = target.offset(); @@ -245,7 +250,7 @@ export default Ember.Mixin.create({ // note: we DO NOT use afterRender here cause _positionCard may // run afterwards, if we allowed this to happen the usercard // may be offscreen and we may scroll all the way to it on focus - Ember.run.next(null, () => { + next(null, () => { const firstLink = this.element.querySelector("a"); firstLink && firstLink.focus(); }); diff --git a/app/assets/javascripts/discourse/mixins/cleans-up.js.es6 b/app/assets/javascripts/discourse/mixins/cleans-up.js.es6 index 09d469af1c..ffbaf7a9ee 100644 --- a/app/assets/javascripts/discourse/mixins/cleans-up.js.es6 +++ b/app/assets/javascripts/discourse/mixins/cleans-up.js.es6 @@ -1,11 +1,14 @@ +import { on } from "@ember/object/evented"; +import Mixin from "@ember/object/mixin"; + // Include this mixin if you want to be notified when the dom should be // cleaned (usually on route change.) -export default Ember.Mixin.create({ - _initializeChooser: function() { +export default Mixin.create({ + _initializeChooser: on("didInsertElement", function() { this.appEvents.on("dom:clean", this, "cleanUp"); - }.on("didInsertElement"), + }), - _clearChooser: function() { + _clearChooser: on("willDestroyElement", function() { this.appEvents.off("dom:clean", this, "cleanUp"); - }.on("willDestroyElement") + }) }); diff --git a/app/assets/javascripts/discourse/mixins/docking.js.es6 b/app/assets/javascripts/discourse/mixins/docking.js.es6 index 800898ae70..3df9f80eda 100644 --- a/app/assets/javascripts/discourse/mixins/docking.js.es6 +++ b/app/assets/javascripts/discourse/mixins/docking.js.es6 @@ -1,3 +1,6 @@ +import Mixin from "@ember/object/mixin"; +import { debounce } from "@ember/runloop"; + const helper = { offset() { const mainOffset = $("#main").offset(); @@ -6,13 +9,13 @@ const helper = { } }; -export default Ember.Mixin.create({ +export default Mixin.create({ queueDockCheck: null, init() { this._super(...arguments); this.queueDockCheck = () => { - Ember.run.debounce(this, this.safeDockCheck, 5); + debounce(this, this.safeDockCheck, 5); }; }, diff --git a/app/assets/javascripts/discourse/mixins/grant-badge-controller.js.es6 b/app/assets/javascripts/discourse/mixins/grant-badge-controller.js.es6 index cc0d82fd87..37502e3749 100644 --- a/app/assets/javascripts/discourse/mixins/grant-badge-controller.js.es6 +++ b/app/assets/javascripts/discourse/mixins/grant-badge-controller.js.es6 @@ -1,8 +1,10 @@ +import { empty } from "@ember/object/computed"; import computed from "ember-addons/ember-computed-decorators"; import UserBadge from "discourse/models/user-badge"; import { convertIconClass } from "discourse-common/lib/icon-library"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ @computed("allBadges.[]", "userBadges.[]") grantableBadges(allBadges, userBadges) { const granted = userBadges.reduce((map, badge) => { @@ -27,7 +29,7 @@ export default Ember.Mixin.create({ .sort((a, b) => a.get("name").localeCompare(b.get("name"))); }, - noGrantableBadges: Ember.computed.empty("grantableBadges"), + noGrantableBadges: empty("grantableBadges"), @computed("selectedBadgeId", "grantableBadges") selectedBadgeGrantable(selectedBadgeId, grantableBadges) { diff --git a/app/assets/javascripts/discourse/mixins/load-more.js.es6 b/app/assets/javascripts/discourse/mixins/load-more.js.es6 index caf86100ea..a7761e1399 100644 --- a/app/assets/javascripts/discourse/mixins/load-more.js.es6 +++ b/app/assets/javascripts/discourse/mixins/load-more.js.es6 @@ -1,9 +1,10 @@ import Eyeline from "discourse/lib/eyeline"; import Scrolling from "discourse/mixins/scrolling"; import { on } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; // Provides the ability to load more items for a view which is scrolled to the bottom. -export default Ember.Mixin.create(Scrolling, { +export default Mixin.create(Scrolling, { scrolled() { const eyeline = this.eyeline; return eyeline && eyeline.update(); diff --git a/app/assets/javascripts/discourse/mixins/mobile-scroll-direction.js.es6 b/app/assets/javascripts/discourse/mixins/mobile-scroll-direction.js.es6 index 0f27500a09..b2eabe0815 100644 --- a/app/assets/javascripts/discourse/mixins/mobile-scroll-direction.js.es6 +++ b/app/assets/javascripts/discourse/mixins/mobile-scroll-direction.js.es6 @@ -1,7 +1,9 @@ +import { debounce } from "@ember/runloop"; +import Mixin from "@ember/object/mixin"; // Small buffer so that very tiny scrolls don't trigger mobile header switch const MOBILE_SCROLL_TOLERANCE = 5; -export default Ember.Mixin.create({ +export default Mixin.create({ _lastScroll: null, _bottomHit: 0, @@ -42,7 +44,7 @@ export default Ember.Mixin.create({ // If the user reaches the very bottom of the topic, we only want to reset // this scroll direction after a second scrolldown. This is a nicer event // similar to what Safari and Chrome do. - Ember.run.debounce(() => { + debounce(() => { this._bottomHit = 1; }, 1000); diff --git a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 index cb4ba7717f..70b5bd010c 100644 --- a/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 +++ b/app/assets/javascripts/discourse/mixins/modal-functionality.js.es6 @@ -1,6 +1,7 @@ import showModal from "discourse/lib/show-modal"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ flash(text, messageClass) { this.appEvents.trigger("modal-body:flash", { text, messageClass }); }, diff --git a/app/assets/javascripts/discourse/mixins/name-validation.js.es6 b/app/assets/javascripts/discourse/mixins/name-validation.js.es6 index 5b505c1359..46f1b4dfae 100644 --- a/app/assets/javascripts/discourse/mixins/name-validation.js.es6 +++ b/app/assets/javascripts/discourse/mixins/name-validation.js.es6 @@ -1,7 +1,9 @@ +import { isEmpty } from "@ember/utils"; import InputValidation from "discourse/models/input-validation"; import { default as computed } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ @computed() nameInstructions() { return I18n.t( @@ -14,10 +16,7 @@ export default Ember.Mixin.create({ // Validate the name. @computed("accountName") nameValidation() { - if ( - this.siteSettings.full_name_required && - Ember.isEmpty(this.accountName) - ) { + if (this.siteSettings.full_name_required && isEmpty(this.accountName)) { return InputValidation.create({ failed: true }); } diff --git a/app/assets/javascripts/discourse/mixins/open-composer.js.es6 b/app/assets/javascripts/discourse/mixins/open-composer.js.es6 index 7d925ab652..5896a09d5d 100644 --- a/app/assets/javascripts/discourse/mixins/open-composer.js.es6 +++ b/app/assets/javascripts/discourse/mixins/open-composer.js.es6 @@ -1,7 +1,8 @@ // This mixin allows a route to open the composer import Composer from "discourse/models/composer"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ openComposer(controller) { let categoryId = controller.get("category.id"); if ( @@ -15,7 +16,7 @@ export default Ember.Mixin.create({ this.controllerFor("composer").open({ categoryId, action: Composer.CREATE_TOPIC, - draftKey: controller.get("model.draft_key") || Composer.CREATE_TOPIC, + draftKey: controller.get("model.draft_key") || Composer.NEW_TOPIC_KEY, draftSequence: controller.get("model.draft_sequence") || 0 }); }, diff --git a/app/assets/javascripts/discourse/mixins/pan-events.js.es6 b/app/assets/javascripts/discourse/mixins/pan-events.js.es6 index 1608d72fea..fb05901205 100644 --- a/app/assets/javascripts/discourse/mixins/pan-events.js.es6 +++ b/app/assets/javascripts/discourse/mixins/pan-events.js.es6 @@ -1,3 +1,4 @@ +import Mixin from "@ember/object/mixin"; /** Pan events is a mixin that allows components to detect and respond to swipe gestures It fires callbacks for panStart, panEnd, panMove with the pan state, and the original event. @@ -6,7 +7,7 @@ export const SWIPE_VELOCITY = 40; export const SWIPE_DISTANCE_THRESHOLD = 50; export const SWIPE_VELOCITY_THRESHOLD = 0.12; export const MINIMUM_SWIPE_DISTANCE = 5; -export default Ember.Mixin.create({ +export default Mixin.create({ //velocity is pixels per ms _panState: null, diff --git a/app/assets/javascripts/discourse/mixins/password-validation.js.es6 b/app/assets/javascripts/discourse/mixins/password-validation.js.es6 index 50a98e8790..3ddf9131f0 100644 --- a/app/assets/javascripts/discourse/mixins/password-validation.js.es6 +++ b/app/assets/javascripts/discourse/mixins/password-validation.js.es6 @@ -1,7 +1,9 @@ +import { isEmpty } from "@ember/utils"; import InputValidation from "discourse/models/input-validation"; import { default as computed } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ rejectedPasswords: null, init() { @@ -54,7 +56,7 @@ export default Ember.Mixin.create({ } // If blank, fail without a reason - if (Ember.isEmpty(password)) { + if (isEmpty(password)) { return InputValidation.create({ failed: true }); } @@ -66,14 +68,14 @@ export default Ember.Mixin.create({ }); } - if (!Ember.isEmpty(accountUsername) && password === accountUsername) { + if (!isEmpty(accountUsername) && password === accountUsername) { return InputValidation.create({ failed: true, reason: I18n.t("user.password.same_as_username") }); } - if (!Ember.isEmpty(accountEmail) && password === accountEmail) { + if (!isEmpty(accountEmail) && password === accountEmail) { return InputValidation.create({ failed: true, reason: I18n.t("user.password.same_as_email") diff --git a/app/assets/javascripts/discourse/mixins/preferences-tab-controller.js.es6 b/app/assets/javascripts/discourse/mixins/preferences-tab-controller.js.es6 index 080c81fe9f..7e49326f41 100644 --- a/app/assets/javascripts/discourse/mixins/preferences-tab-controller.js.es6 +++ b/app/assets/javascripts/discourse/mixins/preferences-tab-controller.js.es6 @@ -1,6 +1,7 @@ import { default as computed } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ saved: false, @computed("model.isSaving") diff --git a/app/assets/javascripts/discourse/mixins/scroll-top.js.es6 b/app/assets/javascripts/discourse/mixins/scroll-top.js.es6 index 630227b8fa..82ae1c0479 100644 --- a/app/assets/javascripts/discourse/mixins/scroll-top.js.es6 +++ b/app/assets/javascripts/discourse/mixins/scroll-top.js.es6 @@ -1,5 +1,7 @@ +import { scheduleOnce } from "@ember/runloop"; import DiscourseURL from "discourse/lib/url"; import { deprecated } from "discourse/mixins/scroll-top"; +import Mixin from "@ember/object/mixin"; const context = { _scrollTop() { @@ -14,10 +16,10 @@ function scrollTop() { if (DiscourseURL.isJumpScheduled()) { return; } - Ember.run.scheduleOnce("afterRender", context, context._scrollTop); + scheduleOnce("afterRender", context, context._scrollTop); } -export default Ember.Mixin.create({ +export default Mixin.create({ didInsertElement() { deprecated( "The `ScrollTop` mixin is deprecated. Replace it with a `{{d-section}}` component" diff --git a/app/assets/javascripts/discourse/mixins/scrolling.js.es6 b/app/assets/javascripts/discourse/mixins/scrolling.js.es6 index 690bf1168f..b690c77de4 100644 --- a/app/assets/javascripts/discourse/mixins/scrolling.js.es6 +++ b/app/assets/javascripts/discourse/mixins/scrolling.js.es6 @@ -1,4 +1,6 @@ +import { scheduleOnce } from "@ember/runloop"; import debounce from "discourse/lib/debounce"; +import Mixin from "@ember/object/mixin"; /** This object provides the DOM methods we need for our Mixin to bind to scrolling @@ -23,7 +25,7 @@ const ScrollingDOMMethods = { } }; -const Scrolling = Ember.Mixin.create({ +const Scrolling = Mixin.create({ // Begin watching for scroll events. By default they will be called at max every 100ms. // call with {debounce: N} for a diff time bindScrolling(opts) { @@ -37,7 +39,7 @@ const Scrolling = Ember.Mixin.create({ if (router.activeTransition) { return; } - return Ember.run.scheduleOnce("afterRender", this, "scrolled"); + return scheduleOnce("afterRender", this, "scrolled"); }; if (opts.debounce) { diff --git a/app/assets/javascripts/discourse/mixins/singleton.js.es6 b/app/assets/javascripts/discourse/mixins/singleton.js.es6 index 62a8265613..5c4ac8238d 100644 --- a/app/assets/javascripts/discourse/mixins/singleton.js.es6 +++ b/app/assets/javascripts/discourse/mixins/singleton.js.es6 @@ -8,7 +8,7 @@ ```javascript // Define your class and apply the Mixin - User = Ember.Object.extend({}); + User = EmberObject.extend({}); User.reopenClass(Singleton); // Retrieve the current instance: @@ -34,7 +34,7 @@ ```javascript // Define your class and apply the Mixin - Foot = Ember.Object.extend({}); + Foot = EmberObject.extend({}); Foot.reopenClass(Singleton, { createCurrent: function() { return Foot.create({toes: 5}); @@ -45,7 +45,9 @@ ``` **/ -const Singleton = Ember.Mixin.create({ +import Mixin from "@ember/object/mixin"; + +const Singleton = Mixin.create({ current() { if (!this._current) { this._current = this.createCurrent(); diff --git a/app/assets/javascripts/discourse/mixins/upload.js.es6 b/app/assets/javascripts/discourse/mixins/upload.js.es6 index d3f83ff419..a3b0d8626a 100644 --- a/app/assets/javascripts/discourse/mixins/upload.js.es6 +++ b/app/assets/javascripts/discourse/mixins/upload.js.es6 @@ -2,9 +2,12 @@ import { displayErrorForUpload, validateUploadedFiles } from "discourse/lib/utilities"; -import getUrl from "discourse-common/lib/get-url"; -export default Ember.Mixin.create({ +import getUrl from "discourse-common/lib/get-url"; +import { on } from "@ember/object/evented"; +import Mixin from "@ember/object/mixin"; + +export default Mixin.create({ uploading: false, uploadProgress: 0, @@ -33,7 +36,7 @@ export default Ember.Mixin.create({ return {}; }, - _initialize: function() { + _initialize: on("didInsertElement", function() { const $upload = $(this.element); const reset = () => this.setProperties({ uploading: false, uploadProgress: 0 }); @@ -101,9 +104,9 @@ export default Ember.Mixin.create({ } reset(); }); - }.on("didInsertElement"), + }), - _destroy: function() { + _destroy: on("willDestroyElement", function() { this.messageBus && this.messageBus.unsubscribe("/uploads/" + this.type); const $upload = $(this.element); @@ -113,5 +116,5 @@ export default Ember.Mixin.create({ /* wasn't initialized yet */ } $upload.off(); - }.on("willDestroyElement") + }) }); diff --git a/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6 b/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6 index 57a4b9cec0..ec007c993d 100644 --- a/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6 +++ b/app/assets/javascripts/discourse/mixins/user-fields-validation.js.es6 @@ -1,10 +1,13 @@ +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; import InputValidation from "discourse/models/input-validation"; import { on, default as computed } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ @on("init") _createUserFields() { if (!this.site) { @@ -14,7 +17,7 @@ export default Ember.Mixin.create({ let userFields = this.site.get("user_fields"); if (userFields) { userFields = _.sortBy(userFields, "position").map(function(f) { - return Ember.Object.create({ value: null, field: f }); + return EmberObject.create({ value: null, field: f }); }); } this.set("userFields", userFields); @@ -27,10 +30,10 @@ export default Ember.Mixin.create({ if (userFields) { userFields = userFields.filterBy("field.required"); } - if (!Ember.isEmpty(userFields)) { + if (!isEmpty(userFields)) { const anyEmpty = userFields.any(uf => { const val = uf.get("value"); - return !val || Ember.isEmpty(val); + return !val || isEmpty(val); }); if (anyEmpty) { return InputValidation.create({ failed: true }); diff --git a/app/assets/javascripts/discourse/mixins/username-validation.js.es6 b/app/assets/javascripts/discourse/mixins/username-validation.js.es6 index 892f587b85..66e86221a9 100644 --- a/app/assets/javascripts/discourse/mixins/username-validation.js.es6 +++ b/app/assets/javascripts/discourse/mixins/username-validation.js.es6 @@ -1,9 +1,11 @@ +import { isEmpty } from "@ember/utils"; import InputValidation from "discourse/models/input-validation"; import debounce from "discourse/lib/debounce"; import { setting } from "discourse/lib/computed"; import { default as computed } from "ember-addons/ember-computed-decorators"; +import Mixin from "@ember/object/mixin"; -export default Ember.Mixin.create({ +export default Mixin.create({ uniqueUsernameValidation: null, maxUsernameLength: setting("max_username_length"), @@ -14,7 +16,7 @@ export default Ember.Mixin.create({ Discourse.User.checkUsername(null, this.accountEmail).then(result => { if ( result.suggestion && - (Ember.isEmpty(this.accountUsername) || + (isEmpty(this.accountUsername) || this.accountUsername === this.get("authOptions.username")) ) { this.setProperties({ @@ -37,7 +39,7 @@ export default Ember.Mixin.create({ } // If blank, fail without a reason - if (Ember.isEmpty(accountUsername)) { + if (isEmpty(accountUsername)) { return InputValidation.create({ failed: true }); } @@ -67,7 +69,7 @@ export default Ember.Mixin.create({ shouldCheckUsernameAvailability() { return ( - !Ember.isEmpty(this.accountUsername) && + !isEmpty(this.accountUsername) && this.accountUsername.length >= this.minUsernameLength ); }, diff --git a/app/assets/javascripts/discourse/models/action-summary.js.es6 b/app/assets/javascripts/discourse/models/action-summary.js.es6 index 283a76981d..ce8259b9c0 100644 --- a/app/assets/javascripts/discourse/models/action-summary.js.es6 +++ b/app/assets/javascripts/discourse/models/action-summary.js.es6 @@ -1,9 +1,10 @@ +import { or } from "@ember/object/computed"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import { popupAjaxError } from "discourse/lib/ajax-error"; export default RestModel.extend({ - canToggle: Ember.computed.or("can_undo", "can_act"), + canToggle: or("can_undo", "can_act"), // Remove it removeAction: function() { diff --git a/app/assets/javascripts/discourse/models/archetype.js.es6 b/app/assets/javascripts/discourse/models/archetype.js.es6 index 9ba6e6744b..912a45b45c 100644 --- a/app/assets/javascripts/discourse/models/archetype.js.es6 +++ b/app/assets/javascripts/discourse/models/archetype.js.es6 @@ -1,8 +1,9 @@ +import { gt, not } from "@ember/object/computed"; import { propertyEqual } from "discourse/lib/computed"; import RestModel from "discourse/models/rest"; export default RestModel.extend({ - hasOptions: Ember.computed.gt("options.length", 0), + hasOptions: gt("options.length", 0), isDefault: propertyEqual("id", "site.default_archetype"), - notDefault: Ember.computed.not("isDefault") + notDefault: not("isDefault") }); diff --git a/app/assets/javascripts/discourse/models/badge.js.es6 b/app/assets/javascripts/discourse/models/badge.js.es6 index d70a5fbbe6..88203b5084 100644 --- a/app/assets/javascripts/discourse/models/badge.js.es6 +++ b/app/assets/javascripts/discourse/models/badge.js.es6 @@ -1,10 +1,13 @@ +import { none } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import BadgeGrouping from "discourse/models/badge-grouping"; import RestModel from "discourse/models/rest"; import computed from "ember-addons/ember-computed-decorators"; +import { Promise } from "rsvp"; const Badge = RestModel.extend({ - newBadge: Ember.computed.none("id"), + newBadge: none("id"), @computed url() { @@ -51,7 +54,7 @@ const Badge = RestModel.extend({ }, destroy() { - if (this.newBadge) return Ember.RSVP.resolve(); + if (this.newBadge) return Promise.resolve(); return ajax(`/admin/badges/${this.id}`, { type: "DELETE" @@ -66,7 +69,7 @@ Badge.reopenClass({ if ("badge_types" in json) { json.badge_types.forEach( badgeTypeJson => - (badgeTypes[badgeTypeJson.id] = Ember.Object.create(badgeTypeJson)) + (badgeTypes[badgeTypeJson.id] = EmberObject.create(badgeTypeJson)) ); } diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6 index 5b663c48a0..4248f6a8f8 100644 --- a/app/assets/javascripts/discourse/models/category.js.es6 +++ b/app/assets/javascripts/discourse/models/category.js.es6 @@ -1,10 +1,14 @@ +import { get } from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import computed from "ember-addons/ember-computed-decorators"; import { on } from "ember-addons/ember-computed-decorators"; import PermissionType from "discourse/models/permission-type"; +import { NotificationLevels } from "discourse/lib/notification-levels"; const Category = RestModel.extend({ + permissions: null, + @on("init") setupGroupsAndPermissions() { const availableGroups = this.available_groups; @@ -28,6 +32,13 @@ const Category = RestModel.extend({ } }, + @on("init") + setupRequiredTagGroups() { + if (this.required_tag_group_name) { + this.set("required_tag_groups", [this.required_tag_group_name]); + } + }, + @computed availablePermissions() { return [ @@ -42,6 +53,11 @@ const Category = RestModel.extend({ return { type: "category", id, category: this }; }, + @computed("notification_level") + isMuted(notificationLevel) { + return notificationLevel === NotificationLevels.MUTED; + }, + @computed("name") url() { return Discourse.getURL("/c/") + Category.slugFor(this); @@ -119,6 +135,10 @@ const Category = RestModel.extend({ allowed_tags: this.allowed_tags, allowed_tag_groups: this.allowed_tag_groups, allow_global_tags: this.allow_global_tags, + required_tag_group_name: this.required_tag_groups + ? this.required_tag_groups[0] + : null, + min_tags_from_required_group: this.min_tags_from_required_group, sort_order: this.sort_order, sort_ascending: this.sort_ascending, topic_featured_link_allowed: this.topic_featured_link_allowed, @@ -161,15 +181,6 @@ const Category = RestModel.extend({ this.availableGroups.addObject(permission.group_name); }, - @computed - permissions() { - return Ember.A([ - { group_name: "everyone", permission: PermissionType.create({ id: 1 }) }, - { group_name: "admins", permission: PermissionType.create({ id: 2 }) }, - { group_name: "crap", permission: PermissionType.create({ id: 3 }) } - ]); - }, - @computed("topics") latestTopic(topics) { if (topics && topics.length) { @@ -222,15 +233,15 @@ Category.reopenClass({ slugFor(category, separator = "/") { if (!category) return ""; - const parentCategory = Ember.get(category, "parentCategory"); + const parentCategory = get(category, "parentCategory"); let result = ""; if (parentCategory) { result = Category.slugFor(parentCategory) + separator; } - const id = Ember.get(category, "id"), - slug = Ember.get(category, "slug"); + const id = get(category, "id"), + slug = get(category, "slug"); return !slug || slug.trim().length === 0 ? `${result}${id}-category` @@ -250,7 +261,11 @@ Category.reopenClass({ }, findSingleBySlug(slug) { - return Category.list().find(c => Category.slugFor(c) === slug); + if (Discourse.SiteSettings.slug_generation_method !== "encoded") { + return Category.list().find(c => Category.slugFor(c) === slug); + } else { + return Category.list().find(c => Category.slugFor(c) === encodeURI(slug)); + } }, findById(id) { @@ -286,7 +301,11 @@ Category.reopenClass({ return ( item && item.get("parentCategory") === parentCategory && - Category.slugFor(item) === parentSlug + "/" + slug + ((Discourse.SiteSettings.slug_generation_method !== "encoded" && + Category.slugFor(item) === parentSlug + "/" + slug) || + (Discourse.SiteSettings.slug_generation_method === "encoded" && + Category.slugFor(item) === + encodeURI(parentSlug) + "/" + encodeURI(slug))) ); }); } diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index de9d9042bc..8e3a1af259 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -1,3 +1,9 @@ +import { isEmpty } from "@ember/utils"; +import { reads, equal, not, or, and } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import { cancel } from "@ember/runloop"; +import { later } from "@ember/runloop"; import RestModel from "discourse/models/rest"; import Topic from "discourse/models/topic"; import { throwAjaxError } from "discourse/lib/ajax-error"; @@ -11,18 +17,18 @@ import { import { escapeExpression, tinyAvatar } from "discourse/lib/utilities"; import { propertyNotEqual } from "discourse/lib/computed"; import throttle from "discourse/lib/throttle"; +import { Promise } from "rsvp"; +import { set } from "@ember/object"; // The actions the composer can take export const CREATE_TOPIC = "createTopic", CREATE_SHARED_DRAFT = "createSharedDraft", EDIT_SHARED_DRAFT = "editSharedDraft", PRIVATE_MESSAGE = "privateMessage", - NEW_PRIVATE_MESSAGE_KEY = "new_private_message", - NEW_TOPIC_KEY = "new_topic", REPLY = "reply", EDIT = "edit", - REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic", - REPLY_AS_NEW_PRIVATE_MESSAGE_KEY = "reply_as_new_private_message"; + NEW_PRIVATE_MESSAGE_KEY = "new_private_message", + NEW_TOPIC_KEY = "new_topic"; function isEdit(action) { return action === EDIT || action === EDIT_SHARED_DRAFT; @@ -57,6 +63,20 @@ const CLOSED = "closed", tags: "topic.tags", featuredLink: "topic.featured_link" }, + _draft_serializer = { + reply: "reply", + action: "action", + title: "title", + categoryId: "categoryId", + archetypeId: "archetypeId", + whisper: "whisper", + metaData: "metaData", + composerTime: "composerTime", + typingTime: "typingTime", + postId: "post.id", + usernames: "targetUsernames" + }, + _add_draft_fields = {}, FAST_REPLY_LENGTH_THRESHOLD = 10000; export const SAVE_LABELS = { @@ -84,9 +104,9 @@ const Composer = RestModel.extend({ draftSaving: false, draftSaved: false, - archetypes: Ember.computed.reads("site.archetypes"), + archetypes: reads("site.archetypes"), - sharedDraft: Ember.computed.equal("action", CREATE_SHARED_DRAFT), + sharedDraft: equal("action", CREATE_SHARED_DRAFT), @computed categoryId: { @@ -99,7 +119,7 @@ const Composer = RestModel.extend({ set(categoryId) { const oldCategoryId = this._categoryId; - if (Ember.isEmpty(categoryId)) { + if (isEmpty(categoryId)) { categoryId = null; } this._categoryId = categoryId; @@ -124,11 +144,16 @@ const Composer = RestModel.extend({ : null; }, - creatingTopic: Ember.computed.equal("action", CREATE_TOPIC), - creatingSharedDraft: Ember.computed.equal("action", CREATE_SHARED_DRAFT), - creatingPrivateMessage: Ember.computed.equal("action", PRIVATE_MESSAGE), - notCreatingPrivateMessage: Ember.computed.not("creatingPrivateMessage"), - notPrivateMessage: Ember.computed.not("privateMessage"), + creatingTopic: equal("action", CREATE_TOPIC), + creatingSharedDraft: equal("action", CREATE_SHARED_DRAFT), + creatingPrivateMessage: equal("action", PRIVATE_MESSAGE), + notCreatingPrivateMessage: not("creatingPrivateMessage"), + notPrivateMessage: not("privateMessage"), + + @computed("editingPost", "topic.details.can_edit") + disableTitleInput(editingPost, canEditTopic) { + return editingPost && !canEditTopic; + }, @computed("privateMessage", "archetype.hasOptions") showCategoryChooser(isPrivateMessage, hasOptions) { @@ -143,17 +168,17 @@ const Composer = RestModel.extend({ ); }, - topicFirstPost: Ember.computed.or("creatingTopic", "editingFirstPost"), + topicFirstPost: or("creatingTopic", "editingFirstPost"), @computed("action") editingPost: isEdit, - replyingToTopic: Ember.computed.equal("action", REPLY), + replyingToTopic: equal("action", REPLY), - viewOpen: Ember.computed.equal("composeState", OPEN), - viewDraft: Ember.computed.equal("composeState", DRAFT), - viewFullscreen: Ember.computed.equal("composeState", FULLSCREEN), - viewOpenOrFullscreen: Ember.computed.or("viewOpen", "viewFullscreen"), + viewOpen: equal("composeState", OPEN), + viewDraft: equal("composeState", DRAFT), + viewFullscreen: equal("composeState", FULLSCREEN), + viewOpenOrFullscreen: or("viewOpen", "viewFullscreen"), @observes("composeState") composeStateChanged() { @@ -198,7 +223,7 @@ const Composer = RestModel.extend({ @observes("archetype") archetypeChanged() { - return this.set("metaData", Ember.Object.create()); + return this.set("metaData", EmberObject.create()); }, // view detected user is typing @@ -211,16 +236,16 @@ const Composer = RestModel.extend({ false ), - editingFirstPost: Ember.computed.and("editingPost", "post.firstPost"), + editingFirstPost: and("editingPost", "post.firstPost"), - canEditTitle: Ember.computed.or( + canEditTitle: or( "creatingTopic", "creatingPrivateMessage", "editingFirstPost", "creatingSharedDraft" ), - canCategorize: Ember.computed.and( + canCategorize: and( "canEditTitle", "notCreatingPrivateMessage", "notPrivateMessage" @@ -398,7 +423,7 @@ const Composer = RestModel.extend({ @computed("metaData") hasMetaData(metaData) { - return metaData ? Ember.isEmpty(Ember.keys(metaData)) : false; + return metaData ? isEmpty(Ember.keys(metaData)) : false; }, replyDirty: propertyNotEqual("reply", "originalText"), @@ -588,7 +613,7 @@ const Composer = RestModel.extend({ } } - if (!Ember.isEmpty(reply)) { + if (!isEmpty(reply)) { return; } @@ -611,7 +636,7 @@ const Composer = RestModel.extend({ if (!opts) opts = {}; this.set("loading", false); - const replyBlank = Ember.isEmpty(this.reply); + const replyBlank = isEmpty(this.reply); const composer = this; if ( @@ -660,7 +685,7 @@ const Composer = RestModel.extend({ this.setProperties({ archetypeId: opts.archetypeId || this.site.default_archetype, - metaData: opts.metaData ? Ember.Object.create(opts.metaData) : null, + metaData: opts.metaData ? EmberObject.create(opts.metaData) : null, reply: opts.reply || this.reply || "" }); @@ -722,18 +747,30 @@ const Composer = RestModel.extend({ composer.appEvents.trigger("composer:reply-reloaded", composer); } + // Ensure additional draft fields are set + Object.keys(_add_draft_fields).forEach(f => { + this.set(_add_draft_fields[f], opts[f]); + }); + return false; }, - save(opts) { - if (!this.cantSubmitPost) { - // change category may result in some effect for topic featured link - if (!this.canEditTopicFeaturedLink) { - this.set("featuredLink", null); - } + // Overwrite to implement custom logic + beforeSave() { + return Promise.resolve(); + }, - return this.editingPost ? this.editPost(opts) : this.createPost(opts); - } + save(opts) { + return this.beforeSave().then(() => { + if (!this.cantSubmitPost) { + // change category may result in some effect for topic featured link + if (!this.canEditTopicFeaturedLink) { + this.set("featuredLink", null); + } + + return this.editingPost ? this.editPost(opts) : this.createPost(opts); + } + }); }, clearState() { @@ -757,34 +794,34 @@ const Composer = RestModel.extend({ editPost(opts) { const post = this.post; const oldCooked = post.cooked; - let promise = Ember.RSVP.resolve(); + let promise = Promise.resolve(); // Update the topic if we're editing the first post - if ( - this.title && - post.post_number === 1 && - this.get("topic.details.can_edit") - ) { - const topicProps = this.getProperties( - Object.keys(_edit_topic_serializer) - ); - // frontend should have featuredLink but backend needs featured_link - if (topicProps.featuredLink) { - topicProps.featured_link = topicProps.featuredLink; - delete topicProps.featuredLink; - } - + if (this.title && post.post_number === 1) { const topic = this.topic; - // If we're editing a shared draft, keep the original category - if (this.action === EDIT_SHARED_DRAFT) { - const destinationCategoryId = topicProps.categoryId; - promise = promise.then(() => - topic.updateDestinationCategory(destinationCategoryId) + if (topic.details.can_edit) { + const topicProps = this.getProperties( + Object.keys(_edit_topic_serializer) ); - topicProps.categoryId = topic.get("category.id"); + // frontend should have featuredLink but backend needs featured_link + if (topicProps.featuredLink) { + topicProps.featured_link = topicProps.featuredLink; + delete topicProps.featuredLink; + } + + // If we're editing a shared draft, keep the original category + if (this.action === EDIT_SHARED_DRAFT) { + const destinationCategoryId = topicProps.categoryId; + promise = promise.then(() => + topic.updateDestinationCategory(destinationCategoryId) + ); + topicProps.categoryId = topic.get("category.id"); + } + promise = promise.then(() => Topic.update(topic, topicProps)); + } else if (topic.details.can_edit_tags) { + promise = promise.then(() => topic.updateTags(this.tags)); } - promise = promise.then(() => Topic.update(topic, topicProps)); } const props = { @@ -823,7 +860,7 @@ const Composer = RestModel.extend({ Object.keys(serializer).forEach(f => { const val = this.get(serializer[f]); if (typeof val !== "undefined") { - Ember.set(dest, f, val); + set(dest, f, val); } }); return dest; @@ -964,7 +1001,7 @@ const Composer = RestModel.extend({ post.set("reply_count", post.reply_count - 1); } } - Ember.run.next(() => composer.set("composeState", OPEN)); + next(() => composer.set("composeState", OPEN)); }) ); }, @@ -1015,35 +1052,26 @@ const Composer = RestModel.extend({ }); if (this._clearingStatus) { - Ember.run.cancel(this._clearingStatus); + cancel(this._clearingStatus); this._clearingStatus = null; } - let data = this.getProperties( - "reply", - "action", - "title", - "categoryId", - "archetypeId", - "whisper", - "metaData", - "composerTime", - "typingTime", - "tags", - "noBump" - ); + let data = this.serialize(_draft_serializer); - data = Object.assign(data, { - usernames: this.targetUsernames, - postId: this.get("post.id") - }); - - if (data.postId && !Ember.isEmpty(this.originalText)) { + if (data.postId && !isEmpty(this.originalText)) { data.originalText = this.originalText; } - return Draft.save(this.draftKey, this.draftSequence, data) + return Draft.save( + this.draftKey, + this.draftSequence, + data, + this.messageBus.clientId + ) .then(result => { + if (result.draft_sequence) { + this.draftSequence = result.draft_sequence; + } if (result.conflict_user) { this.setProperties({ draftSaving: false, @@ -1058,10 +1086,27 @@ const Composer = RestModel.extend({ }); } }) - .catch(() => { + .catch(e => { + let draftStatus; + const xhr = e && e.jqXHR; + + if ( + xhr && + xhr.status === 409 && + xhr.responseJSON && + xhr.responseJSON.errors && + xhr.responseJSON.errors.length + ) { + const json = e.jqXHR.responseJSON; + draftStatus = json.errors[0]; + if (json.extras && json.extras.description) { + bootbox.alert(json.extras.description); + } + } + this.setProperties({ draftSaving: false, - draftStatus: I18n.t("composer.drafts_offline"), + draftStatus: draftStatus || I18n.t("composer.drafts_offline"), draftConflictUser: null }); }); @@ -1072,7 +1117,7 @@ const Composer = RestModel.extend({ const draftStatus = this.draftStatus; if (draftStatus && !this._clearingStatus) { - this._clearingStatus = Ember.run.later( + this._clearingStatus = later( this, () => { this.setProperties({ draftStatus: null, draftConflictUser: null }); @@ -1113,6 +1158,18 @@ Composer.reopenClass({ return Object.keys(_create_serializer); }, + serializeToDraft(fieldName, property) { + if (!property) { + property = fieldName; + } + _draft_serializer[fieldName] = property; + _add_draft_fields[fieldName] = property; + }, + + serializedFieldsForDraft() { + return Object.keys(_draft_serializer); + }, + // The status the compose view can have CLOSED, SAVING, @@ -1130,8 +1187,7 @@ Composer.reopenClass({ // Draft key NEW_PRIVATE_MESSAGE_KEY, - REPLY_AS_NEW_TOPIC_KEY, - REPLY_AS_NEW_PRIVATE_MESSAGE_KEY + NEW_TOPIC_KEY }); export default Composer; diff --git a/app/assets/javascripts/discourse/models/draft.js.es6 b/app/assets/javascripts/discourse/models/draft.js.es6 index abba8511f5..62fefef8c7 100644 --- a/app/assets/javascripts/discourse/models/draft.js.es6 +++ b/app/assets/javascripts/discourse/models/draft.js.es6 @@ -21,11 +21,11 @@ Draft.reopenClass({ return current; }, - save(key, sequence, data) { + save(key, sequence, data, clientId) { data = typeof data === "string" ? data : JSON.stringify(data); return ajax("/draft.json", { type: "POST", - data: { draft_key: key, sequence, data } + data: { draft_key: key, sequence, data, owner: clientId } }); } }); diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6 index 2b0081e4e0..b25746471e 100644 --- a/app/assets/javascripts/discourse/models/group.js.es6 +++ b/app/assets/javascripts/discourse/models/group.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import { notEmpty, equal } from "@ember/object/computed"; import { ajax } from "discourse/lib/ajax"; import { default as computed, @@ -9,6 +11,7 @@ import Category from "discourse/models/category"; import User from "discourse/models/user"; import Topic from "discourse/models/topic"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import EmberObject from "@ember/object"; const Group = RestModel.extend({ limit: 50, @@ -21,11 +24,11 @@ const Group = RestModel.extend({ this.set("owners", []); }, - hasOwners: Ember.computed.notEmpty("owners"), + hasOwners: notEmpty("owners"), @computed("automatic_membership_email_domains") emailDomains(value) { - return Ember.isEmpty(value) ? "" : value; + return isEmpty(value) ? "" : value; }, @computed("automatic") @@ -42,7 +45,7 @@ const Group = RestModel.extend({ }, findMembers(params) { - if (Ember.isEmpty(this.name)) { + if (isEmpty(this.name) || !this.can_see_members) { return; } @@ -135,7 +138,7 @@ const Group = RestModel.extend({ : null; }, - canEveryoneMention: Ember.computed.equal("mentionable_level", 99), + canEveryoneMention: equal("mentionable_level", 99), @computed("visibility_level") isPrivate(visibilityLevel) { @@ -216,7 +219,7 @@ const Group = RestModel.extend({ return ajax(`/groups/${this.name}/logs.json`, { data: { offset, filters } }).then(results => { - return Ember.Object.create({ + return EmberObject.create({ logs: results["logs"].map(log => GroupHistory.create(log)), all_loaded: results["all_loaded"] }); @@ -241,7 +244,7 @@ const Group = RestModel.extend({ p.user = User.create(p.user); p.topic = Topic.create(p.topic); p.category = Category.findById(p.category_id); - return Ember.Object.create(p); + return EmberObject.create(p); }); }); }, diff --git a/app/assets/javascripts/discourse/models/invite.js.es6 b/app/assets/javascripts/discourse/models/invite.js.es6 index 842a04a324..54baf013f5 100644 --- a/app/assets/javascripts/discourse/models/invite.js.es6 +++ b/app/assets/javascripts/discourse/models/invite.js.es6 @@ -1,6 +1,8 @@ +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { userPath } from "discourse/lib/url"; +import { Promise } from "rsvp"; const Invite = Discourse.Model.extend({ rescind() { @@ -31,7 +33,7 @@ Invite.reopenClass({ }, findInvitedBy(user, filter, search, offset) { - if (!user) Ember.RSVP.resolve(); + if (!user) Promise.resolve(); const data = {}; if (!Ember.isNone(filter)) data.filter = filter; @@ -42,15 +44,15 @@ Invite.reopenClass({ data }).then(result => { result.invites = result.invites.map(i => Invite.create(i)); - return Ember.Object.create(result); + return EmberObject.create(result); }); }, findInvitedCount(user) { - if (!user) Ember.RSVP.resolve(); + if (!user) Promise.resolve(); return ajax(userPath(`${user.username_lower}/invited_count.json`)).then( - result => Ember.Object.create(result.counts) + result => EmberObject.create(result.counts) ); }, diff --git a/app/assets/javascripts/discourse/models/login-method.js.es6 b/app/assets/javascripts/discourse/models/login-method.js.es6 index ce59db2450..0bfddf3951 100644 --- a/app/assets/javascripts/discourse/models/login-method.js.es6 +++ b/app/assets/javascripts/discourse/models/login-method.js.es6 @@ -1,7 +1,9 @@ +import EmberObject from "@ember/object"; import computed from "ember-addons/ember-computed-decorators"; import { updateCsrfToken } from "discourse/lib/ajax"; +import { Promise } from "rsvp"; -const LoginMethod = Ember.Object.extend({ +const LoginMethod = EmberObject.extend({ @computed title() { return this.title_override || I18n.t(`login.${this.name}.title`); @@ -20,12 +22,12 @@ const LoginMethod = Ember.Object.extend({ doLogin({ reconnect = false } = {}) { if (this.customLogin) { this.customLogin(); - return Ember.RSVP.resolve(); + return Promise.resolve(); } if (this.custom_url) { window.location = this.custom_url; - return Ember.RSVP.resolve(); + return Promise.resolve(); } let authUrl = Discourse.getURL(`/auth/${this.name}`); diff --git a/app/assets/javascripts/discourse/models/model.js.es6 b/app/assets/javascripts/discourse/models/model.js.es6 index c6a0b3ec20..5ce0eb2eaf 100644 --- a/app/assets/javascripts/discourse/models/model.js.es6 +++ b/app/assets/javascripts/discourse/models/model.js.es6 @@ -1,9 +1,11 @@ -const Model = Ember.Object.extend(); +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; +const Model = EmberObject.extend(); Model.reopenClass({ extractByKey(collection, klass) { const retval = {}; - if (Ember.isEmpty(collection)) { + if (isEmpty(collection)) { return retval; } diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6 index 85379d4bfc..5b36d3b4e4 100644 --- a/app/assets/javascripts/discourse/models/nav-item.js.es6 +++ b/app/assets/javascripts/discourse/models/nav-item.js.es6 @@ -118,6 +118,8 @@ const ExtraNavItem = NavItem.extend({ } }), + count: 0, + customFilter: null }); @@ -193,12 +195,46 @@ NavItem.reopenClass({ return item.customFilter.call(this, category, args); }); + let forceActive = false; + extraItems.forEach(item => { + if (item.init) { + item.init.call(this, item, category, args); + } + + const before = item.before; + if (before) { + let i = 0; + for (i = 0; i < items.length; i++) { + if (items[i].name === before) { + break; + } + } + items.splice(i, 0, item); + } else { + items.push(item); + } + if (!item.customHref) return; + item.set("href", item.customHref.call(this, category, args)); + + if (item.forceActive && item.forceActive.call(this, category, args)) { + item.active = true; + forceActive = true; + } else { + item.active = undefined; + } }); - return items.concat(extraItems); + if (forceActive) { + items.forEach(i => { + if (i.active === undefined) { + i.active = false; + } + }); + } + return items; } }); @@ -213,5 +249,7 @@ export function customNavItemHref(cb) { } export function addNavItem(item) { - NavItem.extraNavItems.push(ExtraNavItem.create(item)); + const navItem = ExtraNavItem.create(item); + NavItem.extraNavItems.push(navItem); + return navItem; } diff --git a/app/assets/javascripts/discourse/models/post-action-type.js.es6 b/app/assets/javascripts/discourse/models/post-action-type.js.es6 index fc83f6282a..ef8541a168 100644 --- a/app/assets/javascripts/discourse/models/post-action-type.js.es6 +++ b/app/assets/javascripts/discourse/models/post-action-type.js.es6 @@ -1,7 +1,8 @@ +import { not } from "@ember/object/computed"; import RestModel from "discourse/models/rest"; export const MAX_MESSAGE_LENGTH = 500; export default RestModel.extend({ - notCustomFlag: Ember.computed.not("is_custom_flag") + notCustomFlag: not("is_custom_flag") }); diff --git a/app/assets/javascripts/discourse/models/post-stream.js.es6 b/app/assets/javascripts/discourse/models/post-stream.js.es6 index a3b42bcaeb..6baafb909b 100644 --- a/app/assets/javascripts/discourse/models/post-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/post-stream.js.es6 @@ -1,9 +1,13 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { or, not, and } from "@ember/object/computed"; import { ajax } from "discourse/lib/ajax"; import DiscourseURL from "discourse/lib/url"; import RestModel from "discourse/models/rest"; import PostsWithPlaceholders from "discourse/lib/posts-with-placeholders"; import { default as computed } from "ember-addons/ember-computed-decorators"; import { loadTopicView } from "discourse/models/topic"; +import { Promise } from "rsvp"; export default RestModel.extend({ _identityMap: null, @@ -43,13 +47,8 @@ export default RestModel.extend({ }); }, - loading: Ember.computed.or( - "loadingAbove", - "loadingBelow", - "loadingFilter", - "stagingPost" - ), - notLoading: Ember.computed.not("loading"), + loading: or("loadingAbove", "loadingBelow", "loadingFilter", "stagingPost"), + notLoading: not("loading"), @computed("isMegaTopic", "stream.length", "topic.highest_post_number") filteredPostsCount(isMegaTopic, streamLength, topicHighestPostNumber) { @@ -66,16 +65,8 @@ export default RestModel.extend({ return hasPosts && filteredPostsCount > 0; }, - canAppendMore: Ember.computed.and( - "notLoading", - "hasPosts", - "lastPostNotLoaded" - ), - canPrependMore: Ember.computed.and( - "notLoading", - "hasPosts", - "firstPostNotLoaded" - ), + canAppendMore: and("notLoading", "hasPosts", "lastPostNotLoaded"), + canPrependMore: and("notLoading", "hasPosts", "firstPostNotLoaded"), @computed("hasLoadedData", "firstPostId", "posts.[]") firstPostPresent(hasLoadedData, firstPostId) { @@ -85,7 +76,7 @@ export default RestModel.extend({ return !!this.posts.findBy("id", firstPostId); }, - firstPostNotLoaded: Ember.computed.not("firstPostPresent"), + firstPostNotLoaded: not("firstPostPresent"), firstId: null, lastId: null, @@ -112,7 +103,7 @@ export default RestModel.extend({ return !!this.posts.findBy("id", lastPostId); }, - lastPostNotLoaded: Ember.computed.not("loadedAllPosts"), + lastPostNotLoaded: not("loadedAllPosts"), /** Returns a JS Object of current stream filter options. It should match the query @@ -126,7 +117,7 @@ export default RestModel.extend({ } const userFilters = this.userFilters; - if (!Ember.isEmpty(userFilters)) { + if (!isEmpty(userFilters)) { result.username_filters = userFilters.join(","); } @@ -265,7 +256,7 @@ export default RestModel.extend({ } else { const postWeWant = this.posts.findBy("post_number", opts.nearPost); if (postWeWant) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } } @@ -327,7 +318,7 @@ export default RestModel.extend({ }); } } - return Ember.RSVP.resolve(); + return Promise.resolve(); }, // Fill in a gap of posts after a particular post @@ -343,14 +334,14 @@ export default RestModel.extend({ this.stream.arrayContentDidChange(); }); } - return Ember.RSVP.resolve(); + return Promise.resolve(); }, // Appends the next window of posts to the stream. Call it when scrolling downwards. appendMore() { // Make sure we can append more posts if (!this.canAppendMore) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } const postsWithPlaceholders = this.postsWithPlaceholders; @@ -373,7 +364,7 @@ export default RestModel.extend({ }); } else { const postIds = this.nextWindow; - if (Ember.isEmpty(postIds)) return Ember.RSVP.resolve(); + if (isEmpty(postIds)) return Promise.resolve(); this.set("loadingBelow", true); postsWithPlaceholders.appending(postIds); @@ -393,7 +384,7 @@ export default RestModel.extend({ prependMore() { // Make sure we can append more posts if (!this.canPrependMore) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } if (this.isMegaTopic) { @@ -414,7 +405,7 @@ export default RestModel.extend({ }); } else { const postIds = this.previousWindow; - if (Ember.isEmpty(postIds)) return Ember.RSVP.resolve(); + if (isEmpty(postIds)) return Promise.resolve(); this.set("loadingAbove", true); return this.findPostsByIds(postIds.reverse()) @@ -532,7 +523,7 @@ export default RestModel.extend({ }, removePosts(posts) { - if (Ember.isEmpty(posts)) { + if (isEmpty(posts)) { return; } @@ -590,7 +581,7 @@ export default RestModel.extend({ have no filters. **/ triggerNewPostInStream(postId) { - const resolved = Ember.RSVP.Promise.resolve(); + const resolved = Promise.resolve(); if (!postId) { return resolved; @@ -690,13 +681,13 @@ export default RestModel.extend({ this.removePosts([existing]); }); } - return Ember.RSVP.Promise.resolve(); + return Promise.resolve(); }, triggerChangedPost(postId, updatedAt, opts) { opts = opts || {}; - const resolved = Ember.RSVP.Promise.resolve(); + const resolved = Promise.resolve(); if (!postId) { return resolved; } @@ -717,7 +708,7 @@ export default RestModel.extend({ }, triggerReadPost(postId, readersCount) { - const resolved = Ember.RSVP.Promise.resolve(); + const resolved = Promise.resolve(); resolved.then(() => { const post = this.findLoadedPost(postId); if (post && readersCount > post.readers_count) { @@ -893,12 +884,12 @@ export default RestModel.extend({ than you supplied if the post has already been loaded. **/ storePost(post) { - // Calling `Ember.get(undefined)` raises an error + // Calling `get(undefined)` raises an error if (!post) { return; } - const postId = Ember.get(post, "id"); + const postId = get(post, "id"); if (postId) { const existing = this._identityMap[post.get("id")]; @@ -942,7 +933,7 @@ export default RestModel.extend({ this.set("topic.suggested_topics", result.suggested_topics); } - const posts = Ember.get(result, "post_stream.posts"); + const posts = get(result, "post_stream.posts"); if (posts) { posts.forEach(p => { @@ -967,8 +958,8 @@ export default RestModel.extend({ }, loadIntoIdentityMap(postIds) { - if (Ember.isEmpty(postIds)) { - return Ember.RSVP.resolve([]); + if (isEmpty(postIds)) { + return Promise.resolve([]); } let includeSuggested = !this.get("topic.suggested_topics"); @@ -982,7 +973,7 @@ export default RestModel.extend({ this.set("topic.suggested_topics", result.suggested_topics); } - const posts = Ember.get(result, "post_stream.posts"); + const posts = get(result, "post_stream.posts"); if (posts) { posts.forEach(p => this.storePost(store.createRecord("post", p))); @@ -1039,12 +1030,12 @@ export default RestModel.extend({ excerpt(streamPosition) { if (this.isMegaTopic) { - return new Ember.RSVP.Promise(resolve => resolve("")); + return new Promise(resolve => resolve("")); } const stream = this.stream; - return new Ember.RSVP.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { let excerpt = this._excerpts && this._excerpts[stream[streamPosition]]; if (excerpt) { diff --git a/app/assets/javascripts/discourse/models/post.js.es6 b/app/assets/javascripts/discourse/models/post.js.es6 index a82cef491d..4fbfcdeea0 100644 --- a/app/assets/javascripts/discourse/models/post.js.es6 +++ b/app/assets/javascripts/discourse/models/post.js.es6 @@ -1,3 +1,7 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { equal, and, or, not } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import { popupAjaxError } from "discourse/lib/ajax-error"; @@ -9,6 +13,7 @@ import { postUrl } from "discourse/lib/utilities"; import { cookAsync } from "discourse/lib/text"; import { userPath } from "discourse/lib/url"; import Composer from "discourse/models/composer"; +import { Promise } from "rsvp"; const Post = RestModel.extend({ // TODO: Remove this once one instantiate all `Discourse.Post` models via the store. @@ -35,13 +40,13 @@ const Post = RestModel.extend({ } }, - new_user: Ember.computed.equal("trust_level", 0), - firstPost: Ember.computed.equal("post_number", 1), + new_user: equal("trust_level", 0), + firstPost: equal("post_number", 1), // Posts can show up as deleted if the topic is deleted - deletedViaTopic: Ember.computed.and("firstPost", "topic.deleted_at"), - deleted: Ember.computed.or("deleted_at", "deletedViaTopic"), - notDeleted: Ember.computed.not("deleted"), + deletedViaTopic: and("firstPost", "topic.deleted_at"), + deleted: or("deleted_at", "deletedViaTopic"), + notDeleted: not("deleted"), @computed("name", "username") showName(name, username) { @@ -91,7 +96,7 @@ const Post = RestModel.extend({ @computed("link_counts.@each.internal") internalLinks() { - if (Ember.isEmpty(this.link_counts)) return null; + if (isEmpty(this.link_counts)) return null; return this.link_counts.filterBy("internal").filterBy("title"); }, @@ -226,7 +231,7 @@ const Post = RestModel.extend({ }); } - return promise || Ember.RSVP.Promise.resolve(); + return promise || Promise.resolve(); }, /** @@ -279,7 +284,7 @@ const Post = RestModel.extend({ if (key === "reply_to_user" && value && oldValue) { skip = value.username === oldValue.username || - Ember.get(value, "username") === Ember.get(oldValue, "username"); + get(value, "username") === get(oldValue, "username"); } if (!skip) { @@ -346,7 +351,7 @@ const Post = RestModel.extend({ Post.reopenClass({ munge(json) { if (json.actions_summary) { - const lookup = Ember.Object.create(); + const lookup = EmberObject.create(); // this area should be optimized, it is creating way too many objects per post json.actions_summary = json.actions_summary.map(a => { @@ -394,7 +399,7 @@ Post.reopenClass({ loadRevision(postId, version) { return ajax(`/posts/${postId}/revisions/${version}.json`).then(result => - Ember.Object.create(result) + EmberObject.create(result) ); }, diff --git a/app/assets/javascripts/discourse/models/rest.js.es6 b/app/assets/javascripts/discourse/models/rest.js.es6 index 8b731f584f..a140dad504 100644 --- a/app/assets/javascripts/discourse/models/rest.js.es6 +++ b/app/assets/javascripts/discourse/models/rest.js.es6 @@ -1,6 +1,10 @@ -const RestModel = Ember.Object.extend({ - isNew: Ember.computed.equal("__state", "new"), - isCreated: Ember.computed.equal("__state", "created"), +import { equal } from "@ember/object/computed"; +import EmberObject from "@ember/object"; +import { Promise } from "rsvp"; + +const RestModel = EmberObject.extend({ + isNew: equal("__state", "new"), + isCreated: equal("__state", "created"), isSaving: false, beforeCreate() {}, @@ -8,7 +12,7 @@ const RestModel = Ember.Object.extend({ update(props) { if (this.isSaving) { - return Ember.RSVP.reject(); + return Promise.reject(); } props = props || this.updateProperties(); @@ -36,7 +40,7 @@ const RestModel = Ember.Object.extend({ _saveNew(props) { if (this.isSaving) { - return Ember.RSVP.reject(); + return Promise.reject(); } props = props || this.createProperties(); diff --git a/app/assets/javascripts/discourse/models/result-set.js.es6 b/app/assets/javascripts/discourse/models/result-set.js.es6 index dc9f1f9ec4..436abfd2de 100644 --- a/app/assets/javascripts/discourse/models/result-set.js.es6 +++ b/app/assets/javascripts/discourse/models/result-set.js.es6 @@ -1,4 +1,5 @@ import computed from "ember-addons/ember-computed-decorators"; +import { Promise } from "rsvp"; export default Ember.ArrayProxy.extend({ loading: false, @@ -34,7 +35,7 @@ export default Ember.ArrayProxy.extend({ .finally(() => this.set("loadingMore", false)); } - return Ember.RSVP.resolve(); + return Promise.resolve(); }, refresh() { diff --git a/app/assets/javascripts/discourse/models/reviewable-history.js.es6 b/app/assets/javascripts/discourse/models/reviewable-history.js.es6 index 0b1b14f54e..dec1f37be5 100644 --- a/app/assets/javascripts/discourse/models/reviewable-history.js.es6 +++ b/app/assets/javascripts/discourse/models/reviewable-history.js.es6 @@ -1,3 +1,4 @@ +import { equal } from "@ember/object/computed"; import RestModel from "discourse/models/rest"; export const CREATED = 0; @@ -5,5 +6,5 @@ export const TRANSITIONED_TO = 1; export const EDITED = 2; export default RestModel.extend({ - created: Ember.computed.equal("reviewable_history_type", CREATED) + created: equal("reviewable_history_type", CREATED) }); diff --git a/app/assets/javascripts/discourse/models/reviewable.js.es6 b/app/assets/javascripts/discourse/models/reviewable.js.es6 index 25fc62f63d..892822c59e 100644 --- a/app/assets/javascripts/discourse/models/reviewable.js.es6 +++ b/app/assets/javascripts/discourse/models/reviewable.js.es6 @@ -2,6 +2,7 @@ import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import computed from "ember-addons/ember-computed-decorators"; import Category from "discourse/models/category"; +import { Promise } from "rsvp"; export const PENDING = 0; export const APPROVED = 1; @@ -25,7 +26,7 @@ export default RestModel.extend({ update(updates) { // If no changes, do nothing if (Object.keys(updates).length === 0) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } let adapter = this.store.adapterFor("reviewable"); diff --git a/app/assets/javascripts/discourse/models/site.js.es6 b/app/assets/javascripts/discourse/models/site.js.es6 index 1089956d6c..07dc4d72b3 100644 --- a/app/assets/javascripts/discourse/models/site.js.es6 +++ b/app/assets/javascripts/discourse/models/site.js.es6 @@ -1,3 +1,7 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { alias, sort } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import computed from "ember-addons/ember-computed-decorators"; import Archetype from "discourse/models/archetype"; import PostActionType from "discourse/models/post-action-type"; @@ -6,7 +10,7 @@ import RestModel from "discourse/models/rest"; import PreloadStore from "preload-store"; const Site = RestModel.extend({ - isReadOnly: Ember.computed.alias("is_readonly"), + isReadOnly: alias("is_readonly"), init() { this._super(...arguments); @@ -30,14 +34,14 @@ const Site = RestModel.extend({ return postActionTypes.filterBy("is_flag", true); }, - categoriesByCount: Ember.computed.sort("categories", "topicCountDesc"), + categoriesByCount: sort("categories", "topicCountDesc"), collectUserFields(fields) { fields = fields || {}; let siteFields = this.user_fields; - if (!Ember.isEmpty(siteFields)) { + if (!isEmpty(siteFields)) { return siteFields.map(f => { let value = fields ? fields[f.id.toString()] : null; value = value || "—".htmlSafe(); @@ -107,7 +111,7 @@ const Site = RestModel.extend({ updateCategory(newCategory) { const categories = this.categories; - const categoryId = Ember.get(newCategory, "id"); + const categoryId = get(newCategory, "id"); const existingCategory = categories.findBy("id", categoryId); // Don't update null permissions @@ -179,7 +183,7 @@ Site.reopenClass(Singleton, { } if (result.post_action_types) { - result.postActionByIdLookup = Ember.Object.create(); + result.postActionByIdLookup = EmberObject.create(); result.post_action_types = result.post_action_types.map(p => { const actionType = PostActionType.create(p); result.postActionByIdLookup.set("action" + p.id, actionType); @@ -188,7 +192,7 @@ Site.reopenClass(Singleton, { } if (result.topic_flag_types) { - result.topicFlagByIdLookup = Ember.Object.create(); + result.topicFlagByIdLookup = EmberObject.create(); result.topic_flag_types = result.topic_flag_types.map(p => { const actionType = PostActionType.create(p); result.topicFlagByIdLookup.set("action" + p.id, actionType); @@ -204,9 +208,7 @@ Site.reopenClass(Singleton, { } if (result.user_fields) { - result.user_fields = result.user_fields.map(uf => - Ember.Object.create(uf) - ); + result.user_fields = result.user_fields.map(uf => EmberObject.create(uf)); } return result; diff --git a/app/assets/javascripts/discourse/models/static-page.js.es6 b/app/assets/javascripts/discourse/models/static-page.js.es6 index a8cdb2507b..57bb3cc2df 100644 --- a/app/assets/javascripts/discourse/models/static-page.js.es6 +++ b/app/assets/javascripts/discourse/models/static-page.js.es6 @@ -1,9 +1,10 @@ +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; -const StaticPage = Ember.Object.extend(); +const StaticPage = EmberObject.extend(); StaticPage.reopenClass({ find(path) { - return new Ember.RSVP.Promise(resolve => { + return new Promise(resolve => { // Models shouldn't really be doing Ajax request, but this is a huge speed boost if we // preload content. const $preloaded = $('noscript[data-path="/' + path + '"]'); diff --git a/app/assets/javascripts/discourse/models/store.js.es6 b/app/assets/javascripts/discourse/models/store.js.es6 index 96a96f502f..39a5ce1434 100644 --- a/app/assets/javascripts/discourse/models/store.js.es6 +++ b/app/assets/javascripts/discourse/models/store.js.es6 @@ -1,7 +1,10 @@ +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import ResultSet from "discourse/models/result-set"; import { getRegister } from "discourse-common/lib/get-owner"; +import { underscore } from "@ember/string"; +import { set } from "@ember/object"; let _identityMap; @@ -44,7 +47,7 @@ function findAndRemoveMap(type, id) { flushMap(); -export default Ember.Object.extend({ +export default EmberObject.extend({ _plurals: { "post-reply": "post-replies", "post-reply-history": "post_reply_histories", @@ -92,7 +95,8 @@ export default Ember.Object.extend({ if (typeof findArgs === "object") { return this._resultSet(type, result, findArgs); } else { - return this._hydrate(type, result[Ember.String.underscore(type)], result); + const apiName = this.adapterFor(type).apiNameFor(type); + return this._hydrate(type, result[underscore(apiName)], result); } }, @@ -146,8 +150,9 @@ export default Ember.Object.extend({ }, refreshResults(resultSet, type, url) { + const adapter = this.adapterFor(type); return ajax(url).then(result => { - const typeName = Ember.String.underscore(this.pluralize(type)); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); const content = result[typeName].map(obj => this._hydrate(type, obj, result) ); @@ -156,8 +161,9 @@ export default Ember.Object.extend({ }, appendResults(resultSet, type, url) { + const adapter = this.adapterFor(type); return ajax(url).then(result => { - let typeName = Ember.String.underscore(this.pluralize(type)); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); let pageTarget = result.meta || result; let totalRows = @@ -198,7 +204,7 @@ export default Ember.Object.extend({ // If the record is new, don't perform an Ajax call if (record.get("isNew")) { removeMap(type, record.get("id")); - return Ember.RSVP.Promise.resolve(true); + return Promise.resolve(true); } return this.adapterFor(type) @@ -210,7 +216,8 @@ export default Ember.Object.extend({ }, _resultSet(type, result, findArgs) { - const typeName = Ember.String.underscore(this.pluralize(type)); + const adapter = this.adapterFor(type); + const typeName = underscore(this.pluralize(adapter.apiNameFor(type))); const content = result[typeName].map(obj => this._hydrate(type, obj, result) ); @@ -312,7 +319,7 @@ export default Ember.Object.extend({ obj[subType] = hydrated; delete obj[k]; } else { - Ember.set(obj, subType, null); + set(obj, subType, null); } } } diff --git a/app/assets/javascripts/discourse/models/tag-group.js.es6 b/app/assets/javascripts/discourse/models/tag-group.js.es6 index 6d0579a1b9..e42ccee9dd 100644 --- a/app/assets/javascripts/discourse/models/tag-group.js.es6 +++ b/app/assets/javascripts/discourse/models/tag-group.js.es6 @@ -1,77 +1,18 @@ -import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import computed from "ember-addons/ember-computed-decorators"; import PermissionType from "discourse/models/permission-type"; export default RestModel.extend({ - @computed("name", "tag_names", "saving") - disableSave(name, tagNames, saving) { - return saving || Ember.isEmpty(name) || Ember.isEmpty(tagNames); - }, - - @computed("id") - disableDelete(id) { - return !parseInt(id); - }, - @computed("permissions") - permissionName: { - get(permissions) { - if (!permissions) return "public"; + permissionName(permissions) { + if (!permissions) return "public"; - if (permissions["everyone"] === PermissionType.FULL) { - return "public"; - } else if (permissions["everyone"] === PermissionType.READONLY) { - return "visible"; - } else { - return "private"; - } - }, - - set(value) { - if (value === "private") { - this.set("permissions", { staff: PermissionType.FULL }); - } else if (value === "visible") { - this.set("permissions", { - staff: PermissionType.FULL, - everyone: PermissionType.READONLY - }); - } else { - this.set("permissions", { everyone: PermissionType.FULL }); - } + if (permissions["everyone"] === PermissionType.FULL) { + return "public"; + } else if (permissions["everyone"] === PermissionType.READONLY) { + return "visible"; + } else { + return "private"; } - }, - - save() { - this.set("savingStatus", I18n.t("saving")); - this.set("saving", true); - - const isNew = this.id === "new"; - const url = isNew ? "/tag_groups" : `/tag_groups/${this.id}`; - const data = this.getProperties( - "name", - "tag_names", - "parent_tag_name", - "one_per_topic", - "permissions" - ); - - return ajax(url, { - data, - type: isNew ? "POST" : "PUT" - }) - .then(result => { - if (result.tag_group && result.tag_group.id) { - this.set("id", result.tag_group.id); - } - }) - .finally(() => { - this.set("savingStatus", I18n.t("saved")); - this.set("saving", false); - }); - }, - - destroy() { - return ajax(`/tag_groups/${this.id}`, { type: "DELETE" }); } }); diff --git a/app/assets/javascripts/discourse/models/topic-details.js.es6 b/app/assets/javascripts/discourse/models/topic-details.js.es6 index 9f486f0712..0622cacb69 100644 --- a/app/assets/javascripts/discourse/models/topic-details.js.es6 +++ b/app/assets/javascripts/discourse/models/topic-details.js.es6 @@ -1,3 +1,4 @@ +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import computed from "ember-addons/ember-computed-decorators"; @@ -23,7 +24,7 @@ const TopicDetails = RestModel.extend({ if (details.participants) { details.participants = details.participants.map(function(p) { p.topic = topic; - return Ember.Object.create(p); + return EmberObject.create(p); }); } diff --git a/app/assets/javascripts/discourse/models/topic-list.js.es6 b/app/assets/javascripts/discourse/models/topic-list.js.es6 index e12a90e77e..da01a6899d 100644 --- a/app/assets/javascripts/discourse/models/topic-list.js.es6 +++ b/app/assets/javascripts/discourse/models/topic-list.js.es6 @@ -1,7 +1,10 @@ +import { notEmpty } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import RestModel from "discourse/models/rest"; import Model from "discourse/models/model"; import { getOwner } from "discourse-common/lib/get-owner"; +import { Promise } from "rsvp"; // Whether to show the category badge in topic lists function displayCategoryInList(site, category) { @@ -22,7 +25,7 @@ function displayCategoryInList(site, category) { } const TopicList = RestModel.extend({ - canLoadMore: Ember.computed.notEmpty("more_topics_url"), + canLoadMore: notEmpty("more_topics_url"), forEachNew(topics, callback) { const topicIds = []; @@ -52,7 +55,7 @@ const TopicList = RestModel.extend({ loadMore() { if (this.loadingMore) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } let moreUrl = this.more_topics_url; @@ -95,7 +98,7 @@ const TopicList = RestModel.extend({ }); } else { // Return a promise indicating no more results - return Ember.RSVP.resolve(); + return Promise.resolve(); } }, @@ -135,7 +138,7 @@ TopicList.reopenClass({ const categories = Discourse.Category.list(), users = Model.extractByKey(result.users, Discourse.User), - groups = Model.extractByKey(result.primary_groups, Ember.Object); + groups = Model.extractByKey(result.primary_groups, EmberObject); return result.topic_list[listKey].map(t => { t.category = categories.findBy("id", t.category_id); diff --git a/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6 b/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6 index 5c726069d3..89eab6119a 100644 --- a/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6 +++ b/app/assets/javascripts/discourse/models/topic-tracking-state.js.es6 @@ -1,3 +1,5 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; import { NotificationLevels } from "discourse/lib/notification-levels"; import { default as computed, @@ -215,7 +217,7 @@ const TopicTrackingState = Discourse.Model.extend({ // If we have a cached topic list, we can update it from our tracking information. updateTopics(topics) { - if (Ember.isEmpty(topics)) { + if (isEmpty(topics)) { return; } @@ -389,8 +391,8 @@ const TopicTrackingState = Discourse.Model.extend({ ); } - let categoryId = category ? Ember.get(category, "id") : null; - let categoryName = category ? Ember.get(category, "name") : null; + let categoryId = category ? get(category, "id") : null; + let categoryName = category ? get(category, "name") : null; if (name === "new") { return this.countNew(categoryId); diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 1af3697106..f4bf6c6533 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -1,3 +1,6 @@ +import { get } from "@ember/object"; +import { not, notEmpty, equal, and, or } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { flushMap } from "discourse/models/store"; import RestModel from "discourse/models/rest"; @@ -194,8 +197,8 @@ const Topic = RestModel.extend({ }); }, - invisible: Ember.computed.not("visible"), - deleted: Ember.computed.notEmpty("deleted_at"), + invisible: not("visible"), + deleted: notEmpty("deleted_at"), @computed("id") searchContext(id) { @@ -335,8 +338,8 @@ const Topic = RestModel.extend({ return Discourse.Site.currentProp("archetypes").findBy("id", archetype); }, - isPrivateMessage: Ember.computed.equal("archetype", "private_message"), - isBanner: Ember.computed.equal("archetype", "banner"), + isPrivateMessage: equal("archetype", "private_message"), + isBanner: equal("archetype", "banner"), toggleStatus(property) { this.toggleProperty(property); @@ -371,12 +374,12 @@ const Topic = RestModel.extend({ toggleBookmark() { if (this.bookmarking) { - return Ember.RSVP.Promise.resolve(); + return Promise.resolve(); } this.set("bookmarking", true); const stream = this.postStream; - const posts = Ember.get(stream, "posts"); + const posts = get(stream, "posts"); const firstPost = posts && posts[0] && posts[0].get("post_number") === 1 && posts[0]; const bookmark = !this.bookmarked; @@ -414,7 +417,7 @@ const Topic = RestModel.extend({ ); } - return new Ember.RSVP.Promise(resolve => { + return new Promise(resolve => { if (unbookmarkedPosts.length > 1) { bootbox.confirm( I18n.t("bookmarks.confirm_clear"), @@ -495,10 +498,7 @@ const Topic = RestModel.extend({ ); }, - isPinnedUncategorized: Ember.computed.and( - "pinned", - "category.isUncategorizedCategory" - ), + isPinnedUncategorized: and("pinned", "category.isUncategorizedCategory"), clearPin() { // Clear the pin optimistically from the object @@ -537,7 +537,7 @@ const Topic = RestModel.extend({ return emojiUnescape(excerpt); }, - hasExcerpt: Ember.computed.notEmpty("excerpt"), + hasExcerpt: notEmpty("excerpt"), @computed("excerpt") excerptTruncated(excerpt) { @@ -545,7 +545,8 @@ const Topic = RestModel.extend({ }, readLastPost: propertyEqual("last_read_post_number", "highest_post_number"), - canClearPin: Ember.computed.and("pinned", "readLastPost"), + canClearPin: and("pinned", "readLastPost"), + canEditTags: or("details.can_edit", "details.can_edit_tags"), archiveMessage() { this.set("archiving", true); @@ -610,6 +611,17 @@ const Topic = RestModel.extend({ return ajax(`/t/${this.id}/reset-bump-date`, { type: "PUT" }).catch( popupAjaxError ); + }, + + updateTags(tags) { + if (!tags || tags.length === 0) { + tags = [""]; + } + + return ajax(`/t/${this.id}/tags`, { + type: "PUT", + data: { tags: tags } + }); } }); @@ -623,7 +635,7 @@ Topic.reopenClass({ createActionSummary(result) { if (result.actions_summary) { - const lookup = Ember.Object.create(); + const lookup = EmberObject.create(); result.actions_summary = result.actions_summary.map(a => { a.post = result; a.actionType = Discourse.Site.current().postActionTypeById(a.id); diff --git a/app/assets/javascripts/discourse/models/user-action.js.es6 b/app/assets/javascripts/discourse/models/user-action.js.es6 index 50600bc7fb..5ca07e7025 100644 --- a/app/assets/javascripts/discourse/models/user-action.js.es6 +++ b/app/assets/javascripts/discourse/models/user-action.js.es6 @@ -1,3 +1,4 @@ +import { or, equal, and } from "@ember/object/computed"; import RestModel from "discourse/models/rest"; import { on } from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators"; @@ -75,9 +76,9 @@ const UserAction = RestModel.extend({ return targetUsername === Discourse.User.currentProp("username"); }, - presentName: Ember.computed.or("name", "username"), - targetDisplayName: Ember.computed.or("target_name", "target_username"), - actingDisplayName: Ember.computed.or("acting_name", "acting_username"), + presentName: or("name", "username"), + targetDisplayName: or("target_name", "target_username"), + actingDisplayName: or("acting_name", "acting_username"), @computed("target_username") targetUserUrl(username) { @@ -104,22 +105,16 @@ const UserAction = RestModel.extend({ return postUrl(this.slug, this.topic_id, this.reply_to_post_number); }, - replyType: Ember.computed.equal("action_type", UserActionTypes.replies), - postType: Ember.computed.equal("action_type", UserActionTypes.posts), - topicType: Ember.computed.equal("action_type", UserActionTypes.topics), - bookmarkType: Ember.computed.equal("action_type", UserActionTypes.bookmarks), - messageSentType: Ember.computed.equal( - "action_type", - UserActionTypes.messages_sent - ), - messageReceivedType: Ember.computed.equal( - "action_type", - UserActionTypes.messages_received - ), - mentionType: Ember.computed.equal("action_type", UserActionTypes.mentions), - isPM: Ember.computed.or("messageSentType", "messageReceivedType"), - postReplyType: Ember.computed.or("postType", "replyType"), - removableBookmark: Ember.computed.and("bookmarkType", "sameUser"), + replyType: equal("action_type", UserActionTypes.replies), + postType: equal("action_type", UserActionTypes.posts), + topicType: equal("action_type", UserActionTypes.topics), + bookmarkType: equal("action_type", UserActionTypes.bookmarks), + messageSentType: equal("action_type", UserActionTypes.messages_sent), + messageReceivedType: equal("action_type", UserActionTypes.messages_received), + mentionType: equal("action_type", UserActionTypes.mentions), + isPM: or("messageSentType", "messageReceivedType"), + postReplyType: or("postType", "replyType"), + removableBookmark: and("bookmarkType", "sameUser"), addChild(action) { let groups = this.childGroups; diff --git a/app/assets/javascripts/discourse/models/user-badge.js.es6 b/app/assets/javascripts/discourse/models/user-badge.js.es6 index a8850674a4..69e88caf2e 100644 --- a/app/assets/javascripts/discourse/models/user-badge.js.es6 +++ b/app/assets/javascripts/discourse/models/user-badge.js.es6 @@ -1,6 +1,7 @@ import { ajax } from "discourse/lib/ajax"; import Badge from "discourse/models/badge"; import computed from "ember-addons/ember-computed-decorators"; +import { Promise } from "rsvp"; const UserBadge = Discourse.Model.extend({ @computed @@ -96,7 +97,7 @@ UserBadge.reopenClass({ **/ findByUsername: function(username, options) { if (!username) { - return Ember.RSVP.resolve([]); + return Promise.resolve([]); } var url = "/user-badges/" + username + ".json"; if (options && options.grouped) { diff --git a/app/assets/javascripts/discourse/models/user-drafts-stream.js.es6 b/app/assets/javascripts/discourse/models/user-drafts-stream.js.es6 index c384b49569..ee1d3cccad 100644 --- a/app/assets/javascripts/discourse/models/user-drafts-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/user-drafts-stream.js.es6 @@ -4,7 +4,7 @@ import RestModel from "discourse/models/rest"; import UserDraft from "discourse/models/user-draft"; import { emojiUnescape } from "discourse/lib/text"; import computed from "ember-addons/ember-computed-decorators"; - +import { Promise } from "rsvp"; import { NEW_TOPIC_KEY, NEW_PRIVATE_MESSAGE_KEY @@ -55,11 +55,11 @@ export default RestModel.extend({ const lastLoadedUrl = this.lastLoadedUrl; if (lastLoadedUrl === findUrl) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } if (this.loading) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } this.set("loading", true); diff --git a/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 index 7521b82dce..74cadcb455 100644 --- a/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 @@ -2,6 +2,7 @@ import { on } from "ember-addons/ember-computed-decorators"; import { ajax } from "discourse/lib/ajax"; import { url } from "discourse/lib/computed"; import UserAction from "discourse/models/user-action"; +import { Promise } from "rsvp"; export default Discourse.Model.extend({ loaded: false, @@ -24,7 +25,7 @@ export default Discourse.Model.extend({ filterBy(opts) { if (this.loaded && this.filter === opts.filter) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } this.setProperties( @@ -43,7 +44,7 @@ export default Discourse.Model.extend({ findItems() { if (this.loading || !this.canLoadMore) { - return Ember.RSVP.reject(); + return Promise.reject(); } this.set("loading", true); diff --git a/app/assets/javascripts/discourse/models/user-stream.js.es6 b/app/assets/javascripts/discourse/models/user-stream.js.es6 index 35e44cc661..1a90ebd940 100644 --- a/app/assets/javascripts/discourse/models/user-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/user-stream.js.es6 @@ -3,6 +3,7 @@ import { url } from "discourse/lib/computed"; import RestModel from "discourse/models/rest"; import UserAction from "discourse/models/user-action"; import { emojiUnescape } from "discourse/lib/text"; +import { Promise } from "rsvp"; import { default as computed, on @@ -92,11 +93,11 @@ export default RestModel.extend({ // Don't load the same stream twice. We're probably at the end. const lastLoadedUrl = this.lastLoadedUrl; if (lastLoadedUrl === findUrl) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } if (this.loading) { - return Ember.RSVP.resolve(); + return Promise.resolve(); } this.set("loading", true); diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index a16b24f80e..af2a0dd2fc 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -1,3 +1,6 @@ +import { isEmpty } from "@ember/utils"; +import { gt, equal, or } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import { url } from "discourse/lib/computed"; import RestModel from "discourse/models/rest"; @@ -20,6 +23,8 @@ import PreloadStore from "preload-store"; import { defaultHomepage } from "discourse/lib/utilities"; import { userPath } from "discourse/lib/url"; import Category from "discourse/models/category"; +import { Promise } from "rsvp"; +import { getProperties } from "@ember/object"; export const SECOND_FACTOR_METHODS = { TOTP: 1, @@ -30,9 +35,9 @@ export const SECOND_FACTOR_METHODS = { const isForever = dt => moment().diff(dt, "years") < -500; const User = RestModel.extend({ - hasPMs: Ember.computed.gt("private_messages_stats.all", 0), - hasStartedPMs: Ember.computed.gt("private_messages_stats.mine", 0), - hasUnreadPMs: Ember.computed.gt("private_messages_stats.unread", 0), + hasPMs: gt("private_messages_stats.all", 0), + hasStartedPMs: gt("private_messages_stats.mine", 0), + hasUnreadPMs: gt("private_messages_stats.unread", 0), redirected_to_top: { reason: null @@ -84,7 +89,7 @@ const User = RestModel.extend({ @computed("username", "name") displayName(username, name) { - if (Discourse.SiteSettings.enable_names && !Ember.isEmpty(name)) { + if (Discourse.SiteSettings.enable_names && !isEmpty(name)) { return name; } return username; @@ -92,10 +97,7 @@ const User = RestModel.extend({ @computed("profile_background_upload_url") profileBackgroundUrl(bgUrl) { - if ( - Ember.isEmpty(bgUrl) || - !Discourse.SiteSettings.allow_profile_backgrounds - ) { + if (isEmpty(bgUrl) || !Discourse.SiteSettings.allow_profile_backgrounds) { return "".htmlSafe(); } return ( @@ -116,7 +118,7 @@ const User = RestModel.extend({ const keys = this.user_api_keys; if (keys) { return keys.map(raw => { - let obj = Ember.Object.create(raw); + let obj = EmberObject.create(raw); obj.revoke = () => { this.revokeApiKey(obj); @@ -203,10 +205,10 @@ const User = RestModel.extend({ ); }, - isBasic: Ember.computed.equal("trust_level", 0), - isLeader: Ember.computed.equal("trust_level", 3), - isElder: Ember.computed.equal("trust_level", 4), - canManageTopic: Ember.computed.or("staff", "isElder"), + isBasic: equal("trust_level", 0), + isLeader: equal("trust_level", 3), + isElder: equal("trust_level", 4), + canManageTopic: or("staff", "isElder"), @computed("previous_visit_at") previousVisitAt(previous_visit_at) { @@ -266,7 +268,8 @@ const User = RestModel.extend({ "tracked_tags", "watched_tags", "watching_first_post_tags", - "date_of_birth" + "date_of_birth", + "primary_group_id" ]; const data = this.getProperties( @@ -349,7 +352,7 @@ const User = RestModel.extend({ }) .then(result => { this.set("bio_excerpt", result.user.bio_excerpt); - const userProps = Ember.getProperties( + const userProps = getProperties( this.user_option, "enable_quoting", "enable_defer", @@ -512,7 +515,7 @@ const User = RestModel.extend({ // The user's stat count, excluding PMs. @computed("statsExcludingPms.@each.count") statsCountNonPM() { - if (Ember.isEmpty(this.statsExcludingPms)) return 0; + if (isEmpty(this.statsExcludingPms)) return 0; let count = 0; this.statsExcludingPms.forEach(val => { if (this.inAllStream(val)) { @@ -525,7 +528,7 @@ const User = RestModel.extend({ // The user's stats, excluding PMs. @computed("stats.@each.isPM") statsExcludingPms() { - if (Ember.isEmpty(this.stats)) return []; + if (isEmpty(this.stats)) return []; return this.stats.rejectBy("isPM"); }, @@ -535,7 +538,7 @@ const User = RestModel.extend({ return PreloadStore.getAndRemove(`user_${user.get("username")}`, () => { return ajax(userPath(`${user.get("username")}.json`), { data: options }); }).then(json => { - if (!Ember.isEmpty(json.user.stats)) { + if (!isEmpty(json.user.stats)) { json.user.stats = Discourse.User.groupStats( json.user.stats.map(s => { if (s.count) s.count = parseInt(s.count, 10); @@ -544,7 +547,7 @@ const User = RestModel.extend({ ); } - if (!Ember.isEmpty(json.user.groups)) { + if (!isEmpty(json.user.groups)) { const groups = []; for (let i = 0; i < json.user.groups.length; i++) { @@ -560,7 +563,7 @@ const User = RestModel.extend({ json.user.invited_by = Discourse.User.create(json.user.invited_by); } - if (!Ember.isEmpty(json.user.featured_user_badge_ids)) { + if (!isEmpty(json.user.featured_user_badge_ids)) { const userBadgesMap = {}; UserBadge.createFromJson(json).forEach(userBadge => { userBadgesMap[userBadge.get("id")] = userBadge; @@ -581,7 +584,7 @@ const User = RestModel.extend({ findStaffInfo() { if (!Discourse.User.currentProp("staff")) { - return Ember.RSVP.resolve(null); + return Promise.resolve(null); } return ajax(userPath(`${this.username_lower}/staff-info.json`)).then( info => { @@ -670,7 +673,7 @@ const User = RestModel.extend({ data: { context: window.location.pathname } }); } else { - return Ember.RSVP.reject(I18n.t("user.delete_yourself_not_allowed")); + return Promise.reject(I18n.t("user.delete_yourself_not_allowed")); } }, diff --git a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 index a8de4fc07d..55f4fee1d9 100644 --- a/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/dynamic-route-builders.js.es6 @@ -95,6 +95,9 @@ export default { }); app["TagsShowCategoryRoute"] = TagsShowRoute.extend(); + app["TagsShowCategoryNoneRoute"] = TagsShowRoute.extend({ + noSubcategories: true + }); app["TagsShowParentCategoryRoute"] = TagsShowRoute.extend(); site.get("filters").forEach(function(filter) { @@ -104,6 +107,9 @@ export default { app[ "TagsShowCategory" + filter.capitalize() + "Route" ] = TagsShowRoute.extend({ navMode: filter }); + app[ + "TagsShowNoneCategory" + filter.capitalize() + "Route" + ] = TagsShowRoute.extend({ navMode: filter, noSubcategories: true }); app[ "TagsShowParentCategory" + filter.capitalize() + "Route" ] = TagsShowRoute.extend({ navMode: filter }); diff --git a/app/assets/javascripts/discourse/raw-views/list/post-count-or-badges.js.es6 b/app/assets/javascripts/discourse/raw-views/list/post-count-or-badges.js.es6 index 2f3dc5beb9..d7c5f0aa06 100644 --- a/app/assets/javascripts/discourse/raw-views/list/post-count-or-badges.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/list/post-count-or-badges.js.es6 @@ -1,8 +1,10 @@ +import { or, and } from "@ember/object/computed"; +import EmberObject from "@ember/object"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Object.extend({ - postCountsPresent: Ember.computed.or("topic.unread", "topic.displayNewPosts"), - showBadges: Ember.computed.and("postBadgesEnabled", "postCountsPresent"), +export default EmberObject.extend({ + postCountsPresent: or("topic.unread", "topic.displayNewPosts"), + showBadges: and("postBadgesEnabled", "postCountsPresent"), @computed newDotText() { diff --git a/app/assets/javascripts/discourse/raw-views/list/posts-count-column.js.es6 b/app/assets/javascripts/discourse/raw-views/list/posts-count-column.js.es6 index 2171251840..2c7ca4c9b9 100644 --- a/app/assets/javascripts/discourse/raw-views/list/posts-count-column.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/list/posts-count-column.js.es6 @@ -1,7 +1,8 @@ +import EmberObject from "@ember/object"; import computed from "ember-addons/ember-computed-decorators"; import { fmt } from "discourse/lib/computed"; -export default Ember.Object.extend({ +export default EmberObject.extend({ tagName: "td", @computed("topic.like_count", "topic.posts_count") diff --git a/app/assets/javascripts/discourse/raw-views/list/visited-line.js.es6 b/app/assets/javascripts/discourse/raw-views/list/visited-line.js.es6 index 3626b17cb7..b2aac57550 100644 --- a/app/assets/javascripts/discourse/raw-views/list/visited-line.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/list/visited-line.js.es6 @@ -1,6 +1,7 @@ +import EmberObject from "@ember/object"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Object.extend({ +export default EmberObject.extend({ @computed isLastVisited: function() { return this.lastVisitedTopic === this.topic; diff --git a/app/assets/javascripts/discourse/raw-views/topic-list-header-column.js.es6 b/app/assets/javascripts/discourse/raw-views/topic-list-header-column.js.es6 index 5febdd4fef..0ac85216b7 100644 --- a/app/assets/javascripts/discourse/raw-views/topic-list-header-column.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/topic-list-header-column.js.es6 @@ -1,6 +1,7 @@ +import EmberObject from "@ember/object"; import { default as computed } from "ember-addons/ember-computed-decorators"; -export default Ember.Object.extend({ +export default EmberObject.extend({ @computed localizedName() { if (this.forceName) { diff --git a/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 b/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 index ec33498520..8e7269bbca 100644 --- a/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 +++ b/app/assets/javascripts/discourse/raw-views/topic-status.js.es6 @@ -1,6 +1,7 @@ +import EmberObject from "@ember/object"; import computed from "ember-addons/ember-computed-decorators"; -export default Ember.Object.extend({ +export default EmberObject.extend({ showDefault: null, @computed("defaultIcon") diff --git a/app/assets/javascripts/discourse/routes/about.js.es6 b/app/assets/javascripts/discourse/routes/about.js.es6 index 3b19492a6b..f7d88a8421 100644 --- a/app/assets/javascripts/discourse/routes/about.js.es6 +++ b/app/assets/javascripts/discourse/routes/about.js.es6 @@ -1,5 +1,7 @@ import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return ajax("/about.json").then(result => { let activeAdmins = []; diff --git a/app/assets/javascripts/discourse/routes/account-created-edit-email.js.es6 b/app/assets/javascripts/discourse/routes/account-created-edit-email.js.es6 index 0922f7fe09..0946fe05db 100644 --- a/app/assets/javascripts/discourse/routes/account-created-edit-email.js.es6 +++ b/app/assets/javascripts/discourse/routes/account-created-edit-email.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ setupController(controller) { const accountCreated = this.controllerFor("account-created").get( "accountCreated" diff --git a/app/assets/javascripts/discourse/routes/account-created-index.js.es6 b/app/assets/javascripts/discourse/routes/account-created-index.js.es6 index 33aa658049..d3f46333a6 100644 --- a/app/assets/javascripts/discourse/routes/account-created-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/account-created-index.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ setupController(controller) { controller.set( "accountCreated", diff --git a/app/assets/javascripts/discourse/routes/account-created-resent.js.es6 b/app/assets/javascripts/discourse/routes/account-created-resent.js.es6 index deb2af1970..047906d262 100644 --- a/app/assets/javascripts/discourse/routes/account-created-resent.js.es6 +++ b/app/assets/javascripts/discourse/routes/account-created-resent.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ setupController(controller) { controller.set( "email", diff --git a/app/assets/javascripts/discourse/routes/account-created.js.es6 b/app/assets/javascripts/discourse/routes/account-created.js.es6 index ab117f5988..901f6c0ffb 100644 --- a/app/assets/javascripts/discourse/routes/account-created.js.es6 +++ b/app/assets/javascripts/discourse/routes/account-created.js.es6 @@ -1,6 +1,7 @@ +import Route from "@ember/routing/route"; import PreloadStore from "preload-store"; -export default Ember.Route.extend({ +export default Route.extend({ setupController(controller) { controller.set("accountCreated", PreloadStore.get("accountCreated")); } diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 654c683a45..1da84b4047 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -156,7 +156,6 @@ export default function() { this.route("email"); this.route("second-factor"); this.route("second-factor-backup"); - this.route("about", { path: "/about-me" }); }); this.route( @@ -200,6 +199,7 @@ export default function() { this.route("tags", { resetNamespace: true }, function() { this.route("show", { path: "/:tag_id" }); this.route("showCategory", { path: "/c/:category/:tag_id" }); + this.route("showCategoryNone", { path: "/c/:category/none/:tag_id" }); this.route("showParentCategory", { path: "/c/:parent_category/:category/:tag_id" }); @@ -211,6 +211,9 @@ export default function() { this.route("showCategory" + filter.capitalize(), { path: "/c/:category/:tag_id/l/" + filter }); + this.route("showCategoryNone" + filter.capitalize(), { + path: "/c/:category/:tag_id/l/" + filter + }); this.route("showParentCategory" + filter.capitalize(), { path: "/c/:parent_category/:category/:tag_id/l/" + filter }); @@ -224,7 +227,8 @@ export default function() { "tagGroups", { path: "/tag_groups", resetNamespace: true }, function() { - this.route("show", { path: "/:id" }); + this.route("edit", { path: "/:id" }); + this.route("new"); } ); diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 4c85a42862..cb1e5f0406 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -1,3 +1,6 @@ +import { once } from "@ember/runloop"; +import { next } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import { setting } from "discourse/lib/computed"; import logout from "discourse/lib/logout"; @@ -20,7 +23,7 @@ function unlessReadOnly(method, message) { }; } -const ApplicationRoute = Discourse.Route.extend(OpenComposer, { +const ApplicationRoute = DiscourseRoute.extend(OpenComposer, { siteTitle: setting("title"), shortSiteDescription: setting("short_site_description"), @@ -43,7 +46,8 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, { _collectTitleTokens(tokens) { tokens.push(this.siteTitle); if ( - window.location.pathname === Discourse.getURL("/") && + (window.location.pathname === Discourse.getURL("/") || + window.location.pathname === Discourse.getURL("/login")) && this.shortSiteDescription !== "" ) { tokens.push(this.shortSiteDescription); @@ -54,7 +58,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, { // Ember doesn't provider a router `willTransition` event so let's make one willTransition() { var router = getOwner(this).lookup("router:main"); - Ember.run.once(router, router.trigger, "willTransition"); + once(router, router.trigger, "willTransition"); return this._super(...arguments); }, @@ -81,7 +85,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, { action: Composer.PRIVATE_MESSAGE, usernames: recipient, archetypeId: "private_message", - draftKey: "new_private_message", + draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY, reply, title }); @@ -224,7 +228,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, { activate() { this._super(...arguments); - Ember.run.next(function() { + next(function() { // Support for callbacks once the application has activated ApplicationRoute.trigger("activate"); }); diff --git a/app/assets/javascripts/discourse/routes/associate-account.js.es6 b/app/assets/javascripts/discourse/routes/associate-account.js.es6 index d89654e078..a182e85c88 100644 --- a/app/assets/javascripts/discourse/routes/associate-account.js.es6 +++ b/app/assets/javascripts/discourse/routes/associate-account.js.es6 @@ -1,12 +1,14 @@ +import { next } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import showModal from "discourse/lib/show-modal"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ beforeModel() { const params = this.paramsFor("associate-account"); this.replaceWith(`preferences.account`, this.currentUser).then(() => - Ember.run.next(() => + next(() => ajax(`/associate/${encodeURIComponent(params.token)}.json`) .then(model => showModal("associate-account-confirm", { model })) .catch(popupAjaxError) diff --git a/app/assets/javascripts/discourse/routes/badges-index.js.es6 b/app/assets/javascripts/discourse/routes/badges-index.js.es6 index 2df72ea584..c4acb15592 100644 --- a/app/assets/javascripts/discourse/routes/badges-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/badges-index.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Badge from "discourse/models/badge"; import PreloadStore from "preload-store"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { if (PreloadStore.get("badges")) { return PreloadStore.getAndRemove("badges").then(json => diff --git a/app/assets/javascripts/discourse/routes/badges-show.js.es6 b/app/assets/javascripts/discourse/routes/badges-show.js.es6 index 3507beac99..86b8f0d4af 100644 --- a/app/assets/javascripts/discourse/routes/badges-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/badges-show.js.es6 @@ -1,8 +1,10 @@ +import DiscourseRoute from "discourse/routes/discourse"; import UserBadge from "discourse/models/user-badge"; import Badge from "discourse/models/badge"; import PreloadStore from "preload-store"; +import { hash } from "rsvp"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { username: { refreshModel: true @@ -51,7 +53,7 @@ export default Discourse.Route.extend({ userBadgesAll }; - return Ember.RSVP.hash(promises); + return hash(promises); }, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6 b/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6 index bc80113310..5bbd0108c6 100644 --- a/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-admin-user-posts-route.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { emojiUnescape } from "discourse/lib/text"; export default function(filter) { - return Discourse.Route.extend({ + return DiscourseRoute.extend({ actions: { didTransition() { this.controllerFor("user").set("indexStream", true); diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 index aadf72eb35..06259b920c 100644 --- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 @@ -1,3 +1,4 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { filterQueryParams, findTopicList @@ -7,10 +8,11 @@ import TopicList from "discourse/models/topic-list"; import PermissionType from "discourse/models/permission-type"; import CategoryList from "discourse/models/category-list"; import Category from "discourse/models/category"; +import { Promise, all } from "rsvp"; // A helper function to create a category route with parameters export default (filterArg, params) => { - return Discourse.Route.extend({ + return DiscourseRoute.extend({ queryParams, model(modelParams) { @@ -49,7 +51,7 @@ export default (filterArg, params) => { } this._setupNavigation(model.category); - return Ember.RSVP.all([ + return all([ this._createSubcategoryList(model.category), this._retrieveTopicList(model.category, transition) ]); @@ -86,7 +88,7 @@ export default (filterArg, params) => { } // If we're not loading a subcategory list just resolve - return Ember.RSVP.resolve(); + return Promise.resolve(); }, _retrieveTopicList(category, transition) { diff --git a/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 b/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 index 4ebca3108a..7331705f8f 100644 --- a/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 @@ -1,4 +1,5 @@ import UserTopicListRoute from "discourse/routes/user-topic-list"; +import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list"; // A helper to build a user topic list route export default (viewName, path, channel) => { @@ -18,10 +19,12 @@ export default (viewName, path, channel) => { }, model() { - return this.store.findFiltered("topicList", { - filter: - "topics/" + path + "/" + this.modelFor("user").get("username_lower") - }); + const filter = + "topics/" + path + "/" + this.modelFor("user").get("username_lower"); + const lastTopicList = findOrResetCachedTopicList(this.session, filter); + return lastTopicList + ? lastTopicList + : this.store.findFiltered("topicList", { filter }); }, setupController() { diff --git a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 index 72db37455b..5d0a576005 100644 --- a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 @@ -1,9 +1,11 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { queryParams } from "discourse/controllers/discovery-sortable"; import { defaultHomepage } from "discourse/lib/utilities"; // A helper to build a topic route for a filter function filterQueryParams(params, defaultParams) { - const findOpts = defaultParams || {}; + const findOpts = Object.assign({}, defaultParams || {}); + if (params) { Object.keys(queryParams).forEach(function(opt) { if (params[opt]) { @@ -16,7 +18,7 @@ function filterQueryParams(params, defaultParams) { function findTopicList(store, tracking, filter, filterParams, extras) { extras = extras || {}; - return new Ember.RSVP.Promise(function(resolve) { + return new Promise(function(resolve) { const session = Discourse.Session.current(); if (extras.cached) { @@ -70,7 +72,7 @@ function findTopicList(store, tracking, filter, filterParams, extras) { export default function(filter, extras) { extras = extras || {}; - return Discourse.Route.extend( + return DiscourseRoute.extend( { queryParams, diff --git a/app/assets/javascripts/discourse/routes/discourse.js.es6 b/app/assets/javascripts/discourse/routes/discourse.js.es6 index 51bdcbbc2b..2329168593 100644 --- a/app/assets/javascripts/discourse/routes/discourse.js.es6 +++ b/app/assets/javascripts/discourse/routes/discourse.js.es6 @@ -1,7 +1,9 @@ +import { once } from "@ember/runloop"; import Composer from "discourse/models/composer"; import { getOwner } from "discourse-common/lib/get-owner"; +import Route from "@ember/routing/route"; -const DiscourseRoute = Ember.Route.extend({ +const DiscourseRoute = Route.extend({ showFooter: false, // Set to true to refresh a model without a transition if a query param @@ -54,7 +56,7 @@ const DiscourseRoute = Ember.Route.extend({ }, refreshTitle() { - Ember.run.once(this, this._refreshTitleOnce); + once(this, this._refreshTitleOnce); }, clearTopicDraft() { diff --git a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 index 49605dd6c3..f5bafdf12b 100644 --- a/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6 @@ -1,3 +1,6 @@ +import EmberObject from "@ember/object"; +import { next } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import showModal from "discourse/lib/show-modal"; import OpenComposer from "discourse/mixins/open-composer"; import CategoryList from "discourse/models/category-list"; @@ -6,8 +9,9 @@ import TopicList from "discourse/models/topic-list"; import { ajax } from "discourse/lib/ajax"; import PreloadStore from "preload-store"; import { searchPriorities } from "discourse/components/concerns/category-search-priorities"; +import { hash } from "rsvp"; -const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { +const DiscoveryCategoriesRoute = DiscourseRoute.extend(OpenComposer, { renderTemplate() { this.render("navigation/categories", { outlet: "navigation-bar" }); this.render("discovery/categories", { outlet: "list-container" }); @@ -41,16 +45,16 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { }, _findCategoriesAndTopics(filter) { - return Ember.RSVP.hash({ + return hash({ wrappedCategoriesList: PreloadStore.getAndRemove("categories_list"), topicsList: PreloadStore.getAndRemove(`topic_list_${filter}`) - }).then(hash => { - let { wrappedCategoriesList, topicsList } = hash; + }).then(response => { + let { wrappedCategoriesList, topicsList } = response; let categoriesList = wrappedCategoriesList && wrappedCategoriesList.category_list; if (categoriesList && topicsList) { - return Ember.Object.create({ + return EmberObject.create({ categories: CategoryList.categoriesFrom( this.store, wrappedCategoriesList @@ -65,7 +69,7 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { } // Otherwise, return the ajax result return ajax(`/categories_and_${filter}`).then(result => { - return Ember.Object.create({ + return EmberObject.create({ categories: CategoryList.categoriesFrom(this.store, result), topics: TopicList.topicsFrom(this.store, result), can_create_category: result.category_list.can_create_category, @@ -132,9 +136,7 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, { }, didTransition() { - Ember.run.next(() => - this.controllerFor("application").set("showFooter", true) - ); + next(() => this.controllerFor("application").set("showFooter", true)); return true; } } diff --git a/app/assets/javascripts/discourse/routes/discovery.js.es6 b/app/assets/javascripts/discourse/routes/discovery.js.es6 index 234ef15930..68796918ef 100644 --- a/app/assets/javascripts/discourse/routes/discovery.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery.js.es6 @@ -2,10 +2,11 @@ The parent route for all discovery routes. Handles the logic for showing the loading spinners. **/ +import DiscourseRoute from "discourse/routes/discourse"; import OpenComposer from "discourse/mixins/open-composer"; import { scrollTop } from "discourse/mixins/scroll-top"; -export default Discourse.Route.extend(OpenComposer, { +export default DiscourseRoute.extend(OpenComposer, { redirect() { return this.redirectIfLoginRequired(); }, diff --git a/app/assets/javascripts/discourse/routes/email-login.js.es6 b/app/assets/javascripts/discourse/routes/email-login.js.es6 index 617de051cd..642d5ee3d6 100644 --- a/app/assets/javascripts/discourse/routes/email-login.js.es6 +++ b/app/assets/javascripts/discourse/routes/email-login.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ titleToken() { return I18n.t("login.title"); }, diff --git a/app/assets/javascripts/discourse/routes/exception.js.es6 b/app/assets/javascripts/discourse/routes/exception.js.es6 index 1b64efb9a6..d90cd0fb76 100644 --- a/app/assets/javascripts/discourse/routes/exception.js.es6 +++ b/app/assets/javascripts/discourse/routes/exception.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ serialize() { return ""; }, diff --git a/app/assets/javascripts/discourse/routes/forgot-password.js.es6 b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 index e88fbdb082..58309565b5 100644 --- a/app/assets/javascripts/discourse/routes/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; import { defaultHomepage } from "discourse/lib/utilities"; import buildStaticRoute from "discourse/routes/build-static-route"; @@ -11,7 +12,7 @@ ForgotPasswordRoute.reopen({ this.replaceWith( loginRequired ? "login" : `discovery.${defaultHomepage()}` ).then(e => { - Ember.run.next(() => e.send("showForgotPassword")); + next(() => e.send("showForgotPassword")); }); } }); diff --git a/app/assets/javascripts/discourse/routes/full-page-search.js.es6 b/app/assets/javascripts/discourse/routes/full-page-search.js.es6 index 97ec4772e7..ca7906e109 100644 --- a/app/assets/javascripts/discourse/routes/full-page-search.js.es6 +++ b/app/assets/javascripts/discourse/routes/full-page-search.js.es6 @@ -1,3 +1,4 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import { translateResults, @@ -8,7 +9,7 @@ import PreloadStore from "preload-store"; import { getTransient, setTransient } from "discourse/lib/page-tracker"; import { escapeExpression } from "discourse/lib/utilities"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ queryParams: { q: {}, expanded: false, diff --git a/app/assets/javascripts/discourse/routes/group-activity-index.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-index.js.es6 index 4ad23d5f64..de7b551a80 100644 --- a/app/assets/javascripts/discourse/routes/group-activity-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-activity-index.js.es6 @@ -1,4 +1,6 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; + +export default Route.extend({ beforeModel() { const group = this.modelFor("group"); if (group.can_see_members) { diff --git a/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 index 62aad28945..86b35b6534 100644 --- a/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-activity-posts.js.es6 @@ -1,5 +1,8 @@ +import { get } from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; + export function buildGroupPage(type) { - return Discourse.Route.extend({ + return DiscourseRoute.extend({ type, titleToken() { @@ -7,7 +10,7 @@ export function buildGroupPage(type) { }, model(params, transition) { - let categoryId = Ember.get(transition.to, "queryParams.category_id"); + let categoryId = get(transition.to, "queryParams.category_id"); return this.modelFor("group").findPosts({ type, categoryId }); }, diff --git a/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 b/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 index a36ec0e6e5..b1b77f40b7 100644 --- a/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-activity-topics.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t(`groups.topics`); }, diff --git a/app/assets/javascripts/discourse/routes/group-index.js.es6 b/app/assets/javascripts/discourse/routes/group-index.js.es6 index 2aab4410ab..a8f630df0f 100644 --- a/app/assets/javascripts/discourse/routes/group-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-index.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import showModal from "discourse/lib/show-modal"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ titleToken() { return I18n.t("groups.members.title"); }, diff --git a/app/assets/javascripts/discourse/routes/group-manage-index.js.es6 b/app/assets/javascripts/discourse/routes/group-manage-index.js.es6 index 590722bb0f..4e9cf5c71c 100644 --- a/app/assets/javascripts/discourse/routes/group-manage-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, beforeModel() { diff --git a/app/assets/javascripts/discourse/routes/group-manage-interaction.js.es6 b/app/assets/javascripts/discourse/routes/group-manage-interaction.js.es6 index e8f3be3da2..e273e2d22f 100644 --- a/app/assets/javascripts/discourse/routes/group-manage-interaction.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage-interaction.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/group-manage-logs.js.es6 b/app/assets/javascripts/discourse/routes/group-manage-logs.js.es6 index 56b092ecfe..ad49c84619 100644 --- a/app/assets/javascripts/discourse/routes/group-manage-logs.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage-logs.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("groups.manage.logs.title"); }, diff --git a/app/assets/javascripts/discourse/routes/group-manage-membership.js.es6 b/app/assets/javascripts/discourse/routes/group-manage-membership.js.es6 index 37746f3e91..1ded3e2b07 100644 --- a/app/assets/javascripts/discourse/routes/group-manage-membership.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage-membership.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/group-manage-profile.js.es6 b/app/assets/javascripts/discourse/routes/group-manage-profile.js.es6 index e0f133e0ce..b720151ff4 100644 --- a/app/assets/javascripts/discourse/routes/group-manage-profile.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage-profile.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/group-manage.js.es6 b/app/assets/javascripts/discourse/routes/group-manage.js.es6 index 54122bcbd4..70b5f053c7 100644 --- a/app/assets/javascripts/discourse/routes/group-manage.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-manage.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/group-members.js.es6 b/app/assets/javascripts/discourse/routes/group-members.js.es6 index 8ec71ae22a..872052de67 100644 --- a/app/assets/javascripts/discourse/routes/group-members.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-members.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel: function() { this.transitionTo("group.index"); } diff --git a/app/assets/javascripts/discourse/routes/group-messages-index.js.es6 b/app/assets/javascripts/discourse/routes/group-messages-index.js.es6 index 68750d154a..be802450b2 100644 --- a/app/assets/javascripts/discourse/routes/group-messages-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-messages-index.js.es6 @@ -1,4 +1,5 @@ -export default Ember.Route.extend({ +import Route from "@ember/routing/route"; +export default Route.extend({ beforeModel: function() { this.transitionTo("group.messages.inbox"); } diff --git a/app/assets/javascripts/discourse/routes/group-messages.js.es6 b/app/assets/javascripts/discourse/routes/group-messages.js.es6 index 82f26f93e2..1a605ec168 100644 --- a/app/assets/javascripts/discourse/routes/group-messages.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-messages.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("groups.messages"); }, diff --git a/app/assets/javascripts/discourse/routes/group-requests.js.es6 b/app/assets/javascripts/discourse/routes/group-requests.js.es6 index c469c9895a..b299bb01bf 100644 --- a/app/assets/javascripts/discourse/routes/group-requests.js.es6 +++ b/app/assets/javascripts/discourse/routes/group-requests.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("groups.requests.title"); }, diff --git a/app/assets/javascripts/discourse/routes/group.js.es6 b/app/assets/javascripts/discourse/routes/group.js.es6 index 9e2c7f87de..bd58f6d3a7 100644 --- a/app/assets/javascripts/discourse/routes/group.js.es6 +++ b/app/assets/javascripts/discourse/routes/group.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return [this.modelFor("group").get("name")]; }, diff --git a/app/assets/javascripts/discourse/routes/groups-index.js.es6 b/app/assets/javascripts/discourse/routes/groups-index.js.es6 index e7189d778f..a510bd93b6 100644 --- a/app/assets/javascripts/discourse/routes/groups-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/groups-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("groups.index.title"); }, diff --git a/app/assets/javascripts/discourse/routes/groups-new.js.es6 b/app/assets/javascripts/discourse/routes/groups-new.js.es6 index 8c2bbd29a7..67f76347d9 100644 --- a/app/assets/javascripts/discourse/routes/groups-new.js.es6 +++ b/app/assets/javascripts/discourse/routes/groups-new.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Group from "discourse/models/group"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ showFooter: true, titleToken() { diff --git a/app/assets/javascripts/discourse/routes/invites-show.js.es6 b/app/assets/javascripts/discourse/routes/invites-show.js.es6 index 93f4bdcc40..7ec701b842 100644 --- a/app/assets/javascripts/discourse/routes/invites-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/invites-show.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import PreloadStore from "preload-store"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ titleToken() { return I18n.t("invites.accept_title"); }, diff --git a/app/assets/javascripts/discourse/routes/login.js.es6 b/app/assets/javascripts/discourse/routes/login.js.es6 index 8465ceb6bc..c41f884f30 100644 --- a/app/assets/javascripts/discourse/routes/login.js.es6 +++ b/app/assets/javascripts/discourse/routes/login.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; import buildStaticRoute from "discourse/routes/build-static-route"; import { defaultHomepage } from "discourse/lib/utilities"; @@ -7,7 +8,7 @@ LoginRoute.reopen({ beforeModel() { if (!this.siteSettings.login_required) { this.replaceWith(`/${defaultHomepage()}`).then(e => { - Ember.run.next(() => e.send("showLogin")); + next(() => e.send("showLogin")); }); } } diff --git a/app/assets/javascripts/discourse/routes/new-message.js.es6 b/app/assets/javascripts/discourse/routes/new-message.js.es6 index 42b664fde5..c85001cbbf 100644 --- a/app/assets/javascripts/discourse/routes/new-message.js.es6 +++ b/app/assets/javascripts/discourse/routes/new-message.js.es6 @@ -1,7 +1,9 @@ +import { next } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import User from "discourse/models/user"; import Group from "discourse/models/group"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ beforeModel(transition) { const params = transition.to.queryParams; @@ -14,7 +16,7 @@ export default Discourse.Route.extend({ User.findByUsername(encodeURIComponent(params.username)) .then(user => { if (user.can_send_private_message_to_user) { - Ember.run.next(() => + next(() => e.send( "createNewMessageViaParams", user.username, @@ -34,7 +36,7 @@ export default Discourse.Route.extend({ Group.messageable(groupName) .then(result => { if (result.messageable) { - Ember.run.next(() => + next(() => e.send( "createNewMessageViaParams", groupName, diff --git a/app/assets/javascripts/discourse/routes/new-topic.js.es6 b/app/assets/javascripts/discourse/routes/new-topic.js.es6 index 266276fd06..550b4b5341 100644 --- a/app/assets/javascripts/discourse/routes/new-topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/new-topic.js.es6 @@ -1,6 +1,8 @@ +import { next } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import Category from "discourse/models/category"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ beforeModel(transition) { if (this.currentUser) { let category, categoryId; @@ -62,7 +64,7 @@ export default Discourse.Route.extend({ }, _sendTransition(event, transition, categoryId) { - Ember.run.next(() => { + next(() => { event.send( "createNewTopicViaParams", transition.to.queryParams.title, diff --git a/app/assets/javascripts/discourse/routes/password-reset.js.es6 b/app/assets/javascripts/discourse/routes/password-reset.js.es6 index a0ccc31484..393b19f96a 100644 --- a/app/assets/javascripts/discourse/routes/password-reset.js.es6 +++ b/app/assets/javascripts/discourse/routes/password-reset.js.es6 @@ -1,8 +1,9 @@ +import DiscourseRoute from "discourse/routes/discourse"; import PreloadStore from "preload-store"; import { ajax } from "discourse/lib/ajax"; import { userPath } from "discourse/lib/url"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ titleToken() { return I18n.t("login.reset_password"); }, diff --git a/app/assets/javascripts/discourse/routes/post.js.es6 b/app/assets/javascripts/discourse/routes/post.js.es6 index c63a71243c..15b8aa3d1a 100644 --- a/app/assets/javascripts/discourse/routes/post.js.es6 +++ b/app/assets/javascripts/discourse/routes/post.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ beforeModel({ params }) { return ajax(`/p/${params.post.id}`).then(t => { this.transitionTo( diff --git a/app/assets/javascripts/discourse/routes/preferences-about.js.es6 b/app/assets/javascripts/discourse/routes/preferences-about.js.es6 deleted file mode 100644 index d6e29ec781..0000000000 --- a/app/assets/javascripts/discourse/routes/preferences-about.js.es6 +++ /dev/null @@ -1,46 +0,0 @@ -import RestrictedUserRoute from "discourse/routes/restricted-user"; - -export default RestrictedUserRoute.extend({ - showFooter: true, - - model: function() { - return this.modelFor("user"); - }, - - renderTemplate: function() { - this.render({ into: "user" }); - }, - - setupController: function(controller, model) { - controller.setProperties({ model, newBio: model.get("bio_raw") }); - }, - - // A bit odd, but if we leave to /preferences we need to re-render that outlet - deactivate: function() { - this._super(...arguments); - this.render("preferences", { into: "user", controller: "preferences" }); - }, - - actions: { - changeAbout: function() { - var route = this; - var controller = route.controllerFor("preferences/about"); - - controller.setProperties({ saving: true }); - return controller - .get("model") - .save() - .then( - function() { - controller.set("saving", false); - route.transitionTo("user.index"); - }, - function() { - // model failed to save - controller.set("saving", false); - bootbox.alert(I18n.t("generic_error")); - } - ); - } - } -}); diff --git a/app/assets/javascripts/discourse/routes/preferences-account.js.es6 b/app/assets/javascripts/discourse/routes/preferences-account.js.es6 index e654ff0622..6ea1e95b95 100644 --- a/app/assets/javascripts/discourse/routes/preferences-account.js.es6 +++ b/app/assets/javascripts/discourse/routes/preferences-account.js.es6 @@ -21,7 +21,8 @@ export default RestrictedUserRoute.extend({ controller.setProperties({ model: user, newNameInput: user.get("name"), - newTitleInput: user.get("title") + newTitleInput: user.get("title"), + newPrimaryGroupInput: user.get("primary_group_id") }); }, diff --git a/app/assets/javascripts/discourse/routes/preferences-second-factor.js.es6 b/app/assets/javascripts/discourse/routes/preferences-second-factor.js.es6 index 763460bc23..cae63a6707 100644 --- a/app/assets/javascripts/discourse/routes/preferences-second-factor.js.es6 +++ b/app/assets/javascripts/discourse/routes/preferences-second-factor.js.es6 @@ -45,7 +45,7 @@ export default RestrictedUserRoute.extend({ if ( transition.targetName === "preferences.second-factor" || !user || - (settings.allow_anonymous_posting && user.is_anonymous) || + user.is_anonymous || user.second_factor_enabled || (settings.enforce_second_factor === "staff" && !user.staff) || settings.enforce_second_factor === "no" diff --git a/app/assets/javascripts/discourse/routes/review-index.js.es6 b/app/assets/javascripts/discourse/routes/review-index.js.es6 index b6ba62ab45..d5b2fad370 100644 --- a/app/assets/javascripts/discourse/routes/review-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/review-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model(params) { return this.store.findAll("reviewable", params); }, diff --git a/app/assets/javascripts/discourse/routes/review-settings.js.es6 b/app/assets/javascripts/discourse/routes/review-settings.js.es6 index 46ed6f10fa..bb5e2e5fb1 100644 --- a/app/assets/javascripts/discourse/routes/review-settings.js.es6 +++ b/app/assets/javascripts/discourse/routes/review-settings.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.store.find("reviewable-settings"); }, diff --git a/app/assets/javascripts/discourse/routes/review-show.js.es6 b/app/assets/javascripts/discourse/routes/review-show.js.es6 index afe7b30a5d..2d6d9795d4 100644 --- a/app/assets/javascripts/discourse/routes/review-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/review-show.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ setupController(controller, model) { controller.set("reviewable", model); } diff --git a/app/assets/javascripts/discourse/routes/review-topics.js.es6 b/app/assets/javascripts/discourse/routes/review-topics.js.es6 index 7c3f058fbd..262194ed00 100644 --- a/app/assets/javascripts/discourse/routes/review-topics.js.es6 +++ b/app/assets/javascripts/discourse/routes/review-topics.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { return this.store.findAll("reviewable-topic"); }, diff --git a/app/assets/javascripts/discourse/routes/review.js.es6 b/app/assets/javascripts/discourse/routes/review.js.es6 index 6343919dfc..9c28f22c54 100644 --- a/app/assets/javascripts/discourse/routes/review.js.es6 +++ b/app/assets/javascripts/discourse/routes/review.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { return I18n.t("review.title"); } diff --git a/app/assets/javascripts/discourse/routes/signup.js.es6 b/app/assets/javascripts/discourse/routes/signup.js.es6 index a2753ded2b..9a732c67d8 100644 --- a/app/assets/javascripts/discourse/routes/signup.js.es6 +++ b/app/assets/javascripts/discourse/routes/signup.js.es6 @@ -1,3 +1,4 @@ +import { next } from "@ember/runloop"; import buildStaticRoute from "discourse/routes/build-static-route"; const SignupRoute = buildStaticRoute("signup"); @@ -9,13 +10,13 @@ SignupRoute.reopen({ if (!this.siteSettings.login_required) { this.replaceWith("discovery.latest").then(e => { if (canSignUp) { - Ember.run.next(() => e.send("showCreateAccount")); + next(() => e.send("showCreateAccount")); } }); } else { this.replaceWith("login").then(e => { if (canSignUp) { - Ember.run.next(() => e.send("showCreateAccount")); + next(() => e.send("showCreateAccount")); } }); } diff --git a/app/assets/javascripts/discourse/routes/tag-groups-edit.js.es6 b/app/assets/javascripts/discourse/routes/tag-groups-edit.js.es6 new file mode 100644 index 0000000000..a923282cce --- /dev/null +++ b/app/assets/javascripts/discourse/routes/tag-groups-edit.js.es6 @@ -0,0 +1,13 @@ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ + showFooter: true, + + model(params) { + return this.store.find("tagGroup", params.id); + }, + + afterModel(tagGroup) { + tagGroup.set("savingStatus", null); + } +}); diff --git a/app/assets/javascripts/discourse/routes/tag-groups-new.js.es6 b/app/assets/javascripts/discourse/routes/tag-groups-new.js.es6 new file mode 100644 index 0000000000..64c460f512 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/tag-groups-new.js.es6 @@ -0,0 +1,17 @@ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ + showFooter: true, + + beforeModel() { + if (!this.siteSettings.tagging_enabled) { + this.transitionTo("tagGroups"); + } + }, + + model() { + return this.store.createRecord("tagGroup", { + name: I18n.t("tagging.groups.new_name") + }); + } +}); diff --git a/app/assets/javascripts/discourse/routes/tag-groups-show.js.es6 b/app/assets/javascripts/discourse/routes/tag-groups-show.js.es6 deleted file mode 100644 index 165ae49d4a..0000000000 --- a/app/assets/javascripts/discourse/routes/tag-groups-show.js.es6 +++ /dev/null @@ -1,7 +0,0 @@ -export default Discourse.Route.extend({ - showFooter: true, - - model(params) { - return this.store.find("tagGroup", params.id); - } -}); diff --git a/app/assets/javascripts/discourse/routes/tag-groups.js.es6 b/app/assets/javascripts/discourse/routes/tag-groups.js.es6 index ccc7d79b75..1010b04c03 100644 --- a/app/assets/javascripts/discourse/routes/tag-groups.js.es6 +++ b/app/assets/javascripts/discourse/routes/tag-groups.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, model() { diff --git a/app/assets/javascripts/discourse/routes/tags-index.js.es6 b/app/assets/javascripts/discourse/routes/tags-index.js.es6 index c9436e876d..99cd3a211d 100644 --- a/app/assets/javascripts/discourse/routes/tags-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/tags-index.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Tag from "discourse/models/tag"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return this.store.findAll("tag").then(result => { if (result.extras) { diff --git a/app/assets/javascripts/discourse/routes/tags-show.js.es6 b/app/assets/javascripts/discourse/routes/tags-show.js.es6 index 3a10287935..c718cc75ff 100644 --- a/app/assets/javascripts/discourse/routes/tags-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/tags-show.js.es6 @@ -1,3 +1,4 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Composer from "discourse/models/composer"; import showModal from "discourse/lib/show-modal"; import { @@ -7,7 +8,7 @@ import { import { queryParams } from "discourse/controllers/discovery-sortable"; import PermissionType from "discourse/models/permission-type"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ navMode: "latest", queryParams, @@ -84,6 +85,8 @@ export default Discourse.Route.extend({ ); if (parentCategorySlug) { filter = `tags/c/${parentCategorySlug}/${categorySlug}/${tagId}/l/${topicFilter}`; + } else if (this.noSubcategories) { + filter = `tags/c/${categorySlug}/none/${tagId}/l/${topicFilter}`; } else { filter = `tags/c/${categorySlug}/${tagId}/l/${topicFilter}`; } @@ -161,7 +164,8 @@ export default Discourse.Route.extend({ category: this.category, filterMode: this.filterMode, navMode: this.navMode, - tagNotification: this.tagNotification + tagNotification: this.tagNotification, + noSubcategories: this.noSubcategories }); }, diff --git a/app/assets/javascripts/discourse/routes/topic-by-slug-or-id.js.es6 b/app/assets/javascripts/discourse/routes/topic-by-slug-or-id.js.es6 index dd5b8e444b..74556b57fc 100644 --- a/app/assets/javascripts/discourse/routes/topic-by-slug-or-id.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic-by-slug-or-id.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { default as Topic, ID_CONSTRAINT } from "discourse/models/topic"; import DiscourseURL from "discourse/lib/url"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model(params) { if (params.slugOrId.match(ID_CONSTRAINT)) { return { url: `/t/topic/${params.slugOrId}` }; diff --git a/app/assets/javascripts/discourse/routes/topic-from-params.js.es6 b/app/assets/javascripts/discourse/routes/topic-from-params.js.es6 index c193cbe98c..08c4671236 100644 --- a/app/assets/javascripts/discourse/routes/topic-from-params.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic-from-params.js.es6 @@ -1,8 +1,11 @@ +import { isEmpty } from "@ember/utils"; +import { scheduleOnce } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import DiscourseURL from "discourse/lib/url"; import Draft from "discourse/models/draft"; // This route is used for retrieving a topic based on params -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ // Avoid default model hook model(params) { return params; @@ -56,7 +59,7 @@ export default Discourse.Route.extend({ topicController.subscribe(); // Highlight our post after the next render - Ember.run.scheduleOnce("afterRender", () => + scheduleOnce("afterRender", () => this.appEvents.trigger("post:highlight", closest) ); @@ -66,7 +69,7 @@ export default Discourse.Route.extend({ } DiscourseURL.jumpToPost(closest, opts); - if (!Ember.isEmpty(topic.draft)) { + if (!isEmpty(topic.draft)) { composerController.open({ draft: Draft.getLocal(topic.draft_key, topic.draft), draftKey: topic.draft_key, diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 4782d2dab8..a6f3eba69a 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -1,3 +1,9 @@ +import { get } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { cancel } from "@ember/runloop"; +import { scheduleOnce } from "@ember/runloop"; +import { later } from "@ember/runloop"; +import DiscourseRoute from "discourse/routes/discourse"; import DiscourseURL from "discourse/lib/url"; import { ID_CONSTRAINT } from "discourse/models/topic"; @@ -9,7 +15,7 @@ const SCROLL_DELAY = 500; import showModal from "discourse/lib/show-modal"; -const TopicRoute = Discourse.Route.extend({ +const TopicRoute = DiscourseRoute.extend({ redirect() { return this.redirectIfLoginRequired(); }, @@ -167,9 +173,9 @@ const TopicRoute = Discourse.Route.extend({ postUrl += "/" + currentPost; } - Ember.run.cancel(scheduledReplace); + cancel(scheduledReplace); lastScrollPos = parseInt($(document).scrollTop(), 10); - scheduledReplace = Ember.run.later( + scheduledReplace = later( this, "_replaceUnlessScrolling", postUrl, @@ -185,7 +191,7 @@ const TopicRoute = Discourse.Route.extend({ willTransition() { this._super(...arguments); - Ember.run.cancel(scheduledReplace); + cancel(scheduledReplace); isTransitioning = true; return true; } @@ -200,7 +206,7 @@ const TopicRoute = Discourse.Route.extend({ return; } lastScrollPos = currentPos; - scheduledReplace = Ember.run.later( + scheduledReplace = later( this, "_replaceUnlessScrolling", url, @@ -210,13 +216,13 @@ const TopicRoute = Discourse.Route.extend({ setupParams(topic, params) { const postStream = topic.get("postStream"); - postStream.set("summary", Ember.get(params, "filter") === "summary"); + postStream.set("summary", get(params, "filter") === "summary"); - const usernames = Ember.get(params, "username_filters"), + const usernames = get(params, "username_filters"), userFilters = postStream.get("userFilters"); userFilters.clear(); - if (!Ember.isEmpty(usernames) && usernames !== "undefined") { + if (!isEmpty(usernames) && usernames !== "undefined") { userFilters.addObjects(usernames.split(",")); } @@ -301,7 +307,7 @@ const TopicRoute = Discourse.Route.extend({ // We reset screen tracking every time a topic is entered this.screenTrack.start(model.get("id"), controller); - Ember.run.scheduleOnce("afterRender", () => { + scheduleOnce("afterRender", () => { this.appEvents.trigger("header:update-topic", model); }); } diff --git a/app/assets/javascripts/discourse/routes/unknown.js.es6 b/app/assets/javascripts/discourse/routes/unknown.js.es6 index 4b2b993549..3df278df6f 100644 --- a/app/assets/javascripts/discourse/routes/unknown.js.es6 +++ b/app/assets/javascripts/discourse/routes/unknown.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { return ajax("/404-body", { dataType: "html" }); } diff --git a/app/assets/javascripts/discourse/routes/user-activity-drafts.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-drafts.js.es6 index 2ca94b05e5..392b9a6255 100644 --- a/app/assets/javascripts/discourse/routes/user-activity-drafts.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-activity-drafts.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { let userDraftsStream = this.modelFor("user").get("userDraftsStream"); return userDraftsStream.load(this.site).then(() => userDraftsStream); diff --git a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 index 8d9d1e8144..1aea1056cf 100644 --- a/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-activity-stream.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import ViewingActionType from "discourse/mixins/viewing-action-type"; -export default Discourse.Route.extend(ViewingActionType, { +export default DiscourseRoute.extend(ViewingActionType, { queryParams: { acting_username: { refreshModel: true } }, diff --git a/app/assets/javascripts/discourse/routes/user-activity.js.es6 b/app/assets/javascripts/discourse/routes/user-activity.js.es6 index a827e3d998..f36beaf1d5 100644 --- a/app/assets/javascripts/discourse/routes/user-activity.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-activity.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ model() { let user = this.modelFor("user"); if (user.get("profile_hidden")) { diff --git a/app/assets/javascripts/discourse/routes/user-badges.js.es6 b/app/assets/javascripts/discourse/routes/user-badges.js.es6 index 0efe8069fc..ffe6008da9 100644 --- a/app/assets/javascripts/discourse/routes/user-badges.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-badges.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import ViewingActionType from "discourse/mixins/viewing-action-type"; import UserBadge from "discourse/models/user-badge"; -export default Discourse.Route.extend(ViewingActionType, { +export default DiscourseRoute.extend(ViewingActionType, { model() { return UserBadge.findByUsername( this.modelFor("user").get("username_lower"), diff --git a/app/assets/javascripts/discourse/routes/user-index.js.es6 b/app/assets/javascripts/discourse/routes/user-index.js.es6 index eef87b16eb..ca51d8fce9 100644 --- a/app/assets/javascripts/discourse/routes/user-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel() { const { currentUser } = this; const viewingMe = diff --git a/app/assets/javascripts/discourse/routes/user-invited-index.js.es6 b/app/assets/javascripts/discourse/routes/user-invited-index.js.es6 index bf7a358215..721f4fb8b2 100644 --- a/app/assets/javascripts/discourse/routes/user-invited-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-invited-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ beforeModel: function() { this.replaceWith("userInvited.show", "pending"); } diff --git a/app/assets/javascripts/discourse/routes/user-invited-show.js.es6 b/app/assets/javascripts/discourse/routes/user-invited-show.js.es6 index 54f367b739..3cd83f79ce 100644 --- a/app/assets/javascripts/discourse/routes/user-invited-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-invited-show.js.es6 @@ -1,7 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Invite from "discourse/models/invite"; import showModal from "discourse/lib/show-modal"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model(params) { Invite.findInvitedCount(this.modelFor("user")).then(result => this.set("invitesCount", result) diff --git a/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 index 1e998969a3..28f0041253 100644 --- a/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ controllerName: "user-notifications", renderTemplate() { this.render("user/notifications-index"); diff --git a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 index e4e65c7f9b..3feb837746 100644 --- a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import ViewingActionType from "discourse/mixins/viewing-action-type"; -export default Discourse.Route.extend(ViewingActionType, { +export default DiscourseRoute.extend(ViewingActionType, { renderTemplate() { this.render("user/notifications"); }, diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-group-archive.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-group-archive.js.es6 index 0d37dac923..0aece428d2 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-group-archive.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-group-archive.js.es6 @@ -1,4 +1,5 @@ import createPMRoute from "discourse/routes/build-private-messages-route"; +import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list"; export default createPMRoute("groups", "private-messages-groups").extend({ groupName: null, @@ -16,9 +17,11 @@ export default createPMRoute("groups", "private-messages-groups").extend({ model(params) { const username = this.modelFor("user").get("username_lower"); - return this.store.findFiltered("topicList", { - filter: `topics/private-messages-group/${username}/${params.name}/archive` - }); + const filter = `topics/private-messages-group/${username}/${params.name}/archive`; + const lastTopicList = findOrResetCachedTopicList(this.session, filter); + return lastTopicList + ? lastTopicList + : this.store.findFiltered("topicList", { filter }); }, afterModel(model) { diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 index cea1b022f4..971cb506cb 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 @@ -1,4 +1,5 @@ import createPMRoute from "discourse/routes/build-private-messages-route"; +import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list"; export default createPMRoute("groups", "private-messages-groups").extend({ groupName: null, @@ -11,9 +12,11 @@ export default createPMRoute("groups", "private-messages-groups").extend({ model(params) { const username = this.modelFor("user").get("username_lower"); - return this.store.findFiltered("topicList", { - filter: `topics/private-messages-group/${username}/${params.name}` - }); + const filter = `topics/private-messages-group/${username}/${params.name}`; + const lastTopicList = findOrResetCachedTopicList(this.session, filter); + return lastTopicList + ? lastTopicList + : this.store.findFiltered("topicList", { filter }); }, afterModel(model) { diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-tags.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-tags.js.es6 index 7007920e38..cfe2d026bb 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-tags.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-tags.js.es6 @@ -1,12 +1,14 @@ +import EmberObject from "@ember/object"; +import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ model() { const username = this.modelFor("user").get("username_lower"); return ajax(`/tags/personal_messages/${username}`) .then(result => { - return result.tags.map(tag => Ember.Object.create(tag)); + return result.tags.map(tag => EmberObject.create(tag)); }) .catch(popupAjaxError); }, diff --git a/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 index 2596727a6a..ef6854e056 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 @@ -1,6 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; import Draft from "discourse/models/draft"; +import Composer from "discourse/models/composer"; -export default Discourse.Route.extend({ +export default DiscourseRoute.extend({ renderTemplate() { this.render("user/messages"); }, @@ -17,7 +19,7 @@ export default Discourse.Route.extend({ if (data.draft) { composerController.open({ draft: data.draft, - draftKey: "new_private_message", + draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY, ignoreIfChanged: true, draftSequence: data.draft_sequence }); diff --git a/app/assets/javascripts/discourse/routes/user-summary.js.es6 b/app/assets/javascripts/discourse/routes/user-summary.js.es6 index 698d2f4edc..6827063517 100644 --- a/app/assets/javascripts/discourse/routes/user-summary.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-summary.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ showFooter: true, model() { diff --git a/app/assets/javascripts/discourse/routes/user-topic-list.js.es6 b/app/assets/javascripts/discourse/routes/user-topic-list.js.es6 index c82e0dceea..80f2c66734 100644 --- a/app/assets/javascripts/discourse/routes/user-topic-list.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-topic-list.js.es6 @@ -1,6 +1,7 @@ +import DiscourseRoute from "discourse/routes/discourse"; import ViewingActionType from "discourse/mixins/viewing-action-type"; -export default Discourse.Route.extend(ViewingActionType, { +export default DiscourseRoute.extend(ViewingActionType, { renderTemplate() { this.render("user-topics-list"); }, diff --git a/app/assets/javascripts/discourse/routes/user.js.es6 b/app/assets/javascripts/discourse/routes/user.js.es6 index 4eaaa4c910..af8d85ccf0 100644 --- a/app/assets/javascripts/discourse/routes/user.js.es6 +++ b/app/assets/javascripts/discourse/routes/user.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ titleToken() { const username = this.modelFor("user").username; if (username) { diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index 009ee9e88d..b500a985b5 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.Route.extend({ +import DiscourseRoute from "discourse/routes/discourse"; + +export default DiscourseRoute.extend({ queryParams: { period: { refreshModel: true }, order: { refreshModel: true }, diff --git a/app/assets/javascripts/discourse/services/app-events.js.es6 b/app/assets/javascripts/discourse/services/app-events.js.es6 index 5967568ef3..fa73e9d463 100644 --- a/app/assets/javascripts/discourse/services/app-events.js.es6 +++ b/app/assets/javascripts/discourse/services/app-events.js.es6 @@ -1,6 +1,7 @@ import deprecated from "discourse-common/lib/deprecated"; +import Service from "@ember/service"; -export default Ember.Service.extend(Ember.Evented, { +export default Service.extend(Ember.Evented, { _events: {}, on() { diff --git a/app/assets/javascripts/discourse/services/emoji-store.js.es6 b/app/assets/javascripts/discourse/services/emoji-store.js.es6 index 7c7a5d082a..19fbd662fc 100644 --- a/app/assets/javascripts/discourse/services/emoji-store.js.es6 +++ b/app/assets/javascripts/discourse/services/emoji-store.js.es6 @@ -1,11 +1,12 @@ import KeyValueStore from "discourse/lib/key-value-store"; +import Service from "@ember/service"; const EMOJI_USAGE = "emojiUsage"; const EMOJI_SELECTED_DIVERSITY = "emojiSelectedDiversity"; const TRACKED_EMOJIS = 15; const STORE_NAMESPACE = "discourse_emojis_"; -export default Ember.Service.extend({ +export default Service.extend({ init() { this._super(...arguments); diff --git a/app/assets/javascripts/discourse/services/logs-notice.js.es6 b/app/assets/javascripts/discourse/services/logs-notice.js.es6 index f70e021992..73961054a1 100644 --- a/app/assets/javascripts/discourse/services/logs-notice.js.es6 +++ b/app/assets/javascripts/discourse/services/logs-notice.js.es6 @@ -1,3 +1,5 @@ +import { isEmpty } from "@ember/utils"; +import EmberObject from "@ember/object"; import { default as computed, on, @@ -7,7 +9,7 @@ import { autoUpdatingRelativeAge } from "discourse/lib/formatter"; const LOGS_NOTICE_KEY = "logs-notice-text"; -const LogsNotice = Ember.Object.extend({ +const LogsNotice = EmberObject.extend({ text: "", @on("init") @@ -47,7 +49,7 @@ const LogsNotice = Ember.Object.extend({ @computed("text") isEmpty(text) { - return Ember.isEmpty(text); + return isEmpty(text); }, @computed("text") @@ -61,8 +63,8 @@ const LogsNotice = Ember.Object.extend({ }, @computed("isEmpty", "isAdmin") - hidden(isEmpty, isAdmin) { - return !isAdmin || isEmpty; + hidden(thisIsEmpty, isAdmin) { + return !isAdmin || thisIsEmpty; }, @observes("text") diff --git a/app/assets/javascripts/discourse/services/search.js.es6 b/app/assets/javascripts/discourse/services/search.js.es6 index 2a47789da4..641e35e482 100644 --- a/app/assets/javascripts/discourse/services/search.js.es6 +++ b/app/assets/javascripts/discourse/services/search.js.es6 @@ -1,9 +1,11 @@ +import { get } from "@ember/object"; +import EmberObject from "@ember/object"; import { default as computed, observes } from "ember-addons/ember-computed-decorators"; -export default Ember.Object.extend({ +export default EmberObject.extend({ searchContextEnabled: false, // checkbox to scope search searchContext: null, term: null, @@ -18,7 +20,7 @@ export default Ember.Object.extend({ contextType: { get(searchContext) { if (searchContext) { - return Ember.get(searchContext, "type"); + return get(searchContext, "type"); } }, set(value, searchContext) { diff --git a/app/assets/javascripts/discourse/services/theme-settings.js.es6 b/app/assets/javascripts/discourse/services/theme-settings.js.es6 index 1ff2300f7f..032024b56b 100644 --- a/app/assets/javascripts/discourse/services/theme-settings.js.es6 +++ b/app/assets/javascripts/discourse/services/theme-settings.js.es6 @@ -1,4 +1,7 @@ -export default Ember.Service.extend({ +import { get } from "@ember/object"; +import Service from "@ember/service"; + +export default Service.extend({ settings: null, init() { @@ -12,7 +15,7 @@ export default Ember.Service.extend({ getSetting(themeId, settingsKey) { if (this._settings[themeId]) { - return Ember.get(this._settings[themeId], settingsKey); + return get(this._settings[themeId], settingsKey); } return null; }, diff --git a/app/assets/javascripts/discourse/templates/badges/show.hbs b/app/assets/javascripts/discourse/templates/badges/show.hbs index 933bc48de8..9eeb3d7fa2 100644 --- a/app/assets/javascripts/discourse/templates/badges/show.hbs +++ b/app/assets/javascripts/discourse/templates/badges/show.hbs @@ -13,7 +13,7 @@
{{i18n 'badges.allow_title'}} {{d-button - class="btn btn-default pad-left no-text" + class="btn-default pad-left" action=(action "toggleSetUserTitle") icon="pencil-alt"}}
diff --git a/app/assets/javascripts/discourse/templates/components/badge-title.hbs b/app/assets/javascripts/discourse/templates/components/badge-title.hbs index 23b1f4e22d..5361595199 100644 --- a/app/assets/javascripts/discourse/templates/components/badge-title.hbs +++ b/app/assets/javascripts/discourse/templates/components/badge-title.hbs @@ -18,7 +18,11 @@
- + {{d-button + class="btn-primary" + action=(action "save") + disabled=saving + label=(if saving "saving" "save")}} {{#if saved}}{{i18n 'saved'}}{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs index d1d105121e..44d9dc579d 100644 --- a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs @@ -18,7 +18,10 @@ canBulkSelect=canBulkSelect selected=selected skipHeader=skipHeader - tagsForUser=tagsForUser}} + tagsForUser=tagsForUser + onScroll=onScroll + scrollOnLoad=scrollOnLoad}} + {{else}} {{#unless loadingMore}}
diff --git a/app/assets/javascripts/discourse/templates/components/categories-only.hbs b/app/assets/javascripts/discourse/templates/components/categories-only.hbs index 4f93c8a316..762752097b 100644 --- a/app/assets/javascripts/discourse/templates/components/categories-only.hbs +++ b/app/assets/javascripts/discourse/templates/components/categories-only.hbs @@ -20,12 +20,14 @@
{{#if c.subcategories}}
- {{#each c.subcategories as |s|}} - - {{category-title-before category=s}} - {{category-link s hideParent="true"}} - {{category-unread category=s}} - + {{#each c.subcategories as |subcategory|}} + {{#unless subcategory.isMuted}} + + {{category-title-before category=subcategory}} + {{category-link subcategory hideParent="true"}} + {{category-unread category=subcategory}} + + {{/unless}} {{/each}}
{{/if}} diff --git a/app/assets/javascripts/discourse/templates/components/composer-title.hbs b/app/assets/javascripts/discourse/templates/components/composer-title.hbs index 76f63dac1f..a8483595de 100644 --- a/app/assets/javascripts/discourse/templates/components/composer-title.hbs +++ b/app/assets/javascripts/discourse/templates/components/composer-title.hbs @@ -3,7 +3,7 @@ id="reply-title" maxLength=titleMaxLength placeholderKey=composer.titlePlaceholder - disabled=composer.loading + disabled=disabled autocomplete="discourse"}} {{popup-input-tip validation=validation}} diff --git a/app/assets/javascripts/discourse/templates/components/create-topic-button.hbs b/app/assets/javascripts/discourse/templates/components/create-topic-button.hbs index e99673f9cb..3a0e3ebfa9 100644 --- a/app/assets/javascripts/discourse/templates/components/create-topic-button.hbs +++ b/app/assets/javascripts/discourse/templates/components/create-topic-button.hbs @@ -1,7 +1,7 @@ {{#if canCreateTopic}} {{d-button + class="btn-default" id="create-topic" - class="btn btn-default" action=action icon="plus" disabled=disabled diff --git a/app/assets/javascripts/discourse/templates/components/d-modal.hbs b/app/assets/javascripts/discourse/templates/components/d-modal.hbs index 4e7cd0dca2..6c6106bbad 100644 --- a/app/assets/javascripts/discourse/templates/components/d-modal.hbs +++ b/app/assets/javascripts/discourse/templates/components/d-modal.hbs @@ -3,11 +3,7 @@