Ember 1.12 support

This commit is contained in:
Robin Ward 2015-08-11 17:34:02 -04:00
parent 02a968bd27
commit 22844b9e46
39 changed files with 10322 additions and 61875 deletions

View File

@ -20,5 +20,5 @@ vendor/
test/javascripts/helpers/ test/javascripts/helpers/
test/javascripts/test_helper.js test/javascripts/test_helper.js
test/javascripts/test_helper.js test/javascripts/test_helper.js
test/javascripts/fixtures
app/assets/javascripts/ember-addons/ app/assets/javascripts/ember-addons/

105
.eslintrc Normal file
View File

@ -0,0 +1,105 @@
{
"env": {
"jasmine": true,
"node": true,
"mocha": true,
"browser": true,
"builtin": true
},
ecmaVersion: 7,
"globals":
{"Ember":true,
"jQuery":true,
"$":true,
"RSVP":true,
"Discourse":true,
"Em":true,
"PreloadStore":true,
"Handlebars":true,
"I18n":true,
"bootbox":true,
"module":true,
"moduleFor":true,
"moduleForComponent":true,
"Pretender":true,
"sandbox":true,
"controllerFor":true,
"test":true,
"ok":true,
"not":true,
"expect":true,
"equal":true,
"visit":true,
"andThen":true,
"click":true,
"currentPath":true,
"currentRouteName":true,
"currentURL":true,
"fillIn":true,
"keyEvent":true,
"triggerEvent":true,
"count":true,
"exists":true,
"visible":true,
"invisible":true,
"asyncRender":true,
"selectDropdown":true,
"asyncTestDiscourse":true,
"fixture":true,
"find":true,
"sinon":true,
"moment":true,
"start":true,
"_":true,
"alert":true,
"containsInstance":true,
"deepEqual":true,
"notEqual":true,
"define":true,
"require":true,
"requirejs":true,
"hasModule":true,
"Blob":true,
"File":true},
"rules": {
"block-scoped-var": 2,
"dot-notation": 0,
"eqeqeq": [
2,
"allow-null"
],
"guard-for-in": 2,
"no-bitwise": 2,
"no-caller": 2,
"no-cond-assign": 0,
"no-debugger": 2,
"no-empty": 0,
"no-eval": 2,
"no-extend-native": 2,
"no-extra-parens": 0,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-loop-func": 2,
"no-multi-str": 2,
"no-new": 2,
"no-plusplus": 0,
"no-proto": 2,
"no-script-url": 2,
"no-sequences": 2,
"no-shadow": 2,
"no-undef": 2,
"no-unused-vars": 2,
"no-with": 2,
"semi": [
0,
"never"
],
"strict": 0,
"valid-typeof": 2,
"wrap-iife": [
2,
"inside"
]
},
"parser": "babel-eslint"
}

View File

@ -1,83 +0,0 @@
{
"predef":["Ember",
"jQuery",
"$",
"RSVP",
"Discourse",
"Em",
"PreloadStore",
"Handlebars",
"I18n",
"bootbox",
"module",
"moduleFor",
"moduleForComponent",
"Pretender",
"sandbox",
"controllerFor",
"test",
"ok",
"not",
"expect",
"equal",
"visit",
"andThen",
"click",
"currentPath",
"currentRouteName",
"currentURL",
"fillIn",
"keyEvent",
"triggerEvent",
"count",
"exists",
"visible",
"invisible",
"asyncRender",
"selectDropdown",
"asyncTestDiscourse",
"fixture",
"find",
"sinon",
"moment",
"start",
"_",
"alert",
"containsInstance",
"deepEqual",
"notEqual",
"define",
"require",
"requirejs",
"hasModule",
"Blob",
"File"],
"node" : false,
"browser" : true,
"boss" : true,
"curly": false,
"debug": false,
"devel": false,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"unused": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"quotmark": false,
"lastsemic": true,
"esnext": true
}

View File

@ -46,9 +46,9 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
aws-sdk-resources (2.0.45) aws-sdk-resources (2.0.45)
aws-sdk-core (= 2.0.45) aws-sdk-core (= 2.0.45)
babel-source (4.6.6) babel-source (5.8.19)
babel-transpiler (0.6.0) babel-transpiler (0.7.0)
babel-source (>= 4.0, < 5) babel-source (>= 4.0, < 6)
execjs (~> 2.0) execjs (~> 2.0)
barber (0.9.0) barber (0.9.0)
ember-source (>= 1.0, < 2) ember-source (>= 1.0, < 2)
@ -86,7 +86,7 @@ GEM
ember-source (>= 1.1.0) ember-source (>= 1.1.0)
jquery-rails (>= 1.0.17) jquery-rails (>= 1.0.17)
railties (>= 3.1) railties (>= 3.1)
ember-source (1.11.3.1) ember-source (1.12.1)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.7) eventmachine (1.0.7)
excon (0.45.3) excon (0.45.3)

View File

@ -2,6 +2,7 @@ import BufferedContent from 'discourse/mixins/buffered-content';
import ScrollTop from 'discourse/mixins/scroll-top'; import ScrollTop from 'discourse/mixins/scroll-top';
import SiteSetting from 'admin/models/site-setting'; import SiteSetting from 'admin/models/site-setting';
import { propertyNotEqual } from 'discourse/lib/computed'; import { propertyNotEqual } from 'discourse/lib/computed';
import computed from 'ember-addons/ember-computed-decorators';
const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list']; const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list'];
@ -20,19 +21,22 @@ export default Ember.Component.extend(BufferedContent, ScrollTop, {
} }
}.property('buffered.value'), }.property('buffered.value'),
typeClass: function() { @computed('partialType')
typeClass() {
return this.get('partialType').replace("_", "-"); return this.get('partialType').replace("_", "-");
}.property('partialType'), },
enabled: function(key, value) { @computed('buffered.value')
if (arguments.length > 1) { enabled: {
get() {
const bufferedValue = this.get('buffered.value');
if (Ember.isEmpty(bufferedValue)) { return false; }
return bufferedValue === 'true';
},
set(key, value) {
this.set('buffered.value', value ? 'true' : 'false'); this.set('buffered.value', value ? 'true' : 'false');
} }
},
const bufferedValue = this.get('buffered.value');
if (Ember.isEmpty(bufferedValue)) { return false; }
return bufferedValue === 'true';
}.property('buffered.value'),
settingName: function() { settingName: function() {
return this.get('setting.setting').replace(/\_/g, ' '); return this.get('setting.setting').replace(/\_/g, ' ');
@ -40,7 +44,7 @@ export default Ember.Component.extend(BufferedContent, ScrollTop, {
partialType: function() { partialType: function() {
let type = this.get('setting.type'); let type = this.get('setting.type');
return (CustomTypes.indexOf(type) !== -1) ? type : 'string'; return CustomTypes.indexOf(type) !== -1 ? type : 'string';
}.property('setting.type'), }.property('setting.type'),
partialName: function() { partialName: function() {

View File

@ -3,7 +3,7 @@ var DiscourseResolver = require('discourse/ember/resolver').default;
// Allow us to import Ember // Allow us to import Ember
define('ember', ['exports'], function(__exports__) { define('ember', ['exports'], function(__exports__) {
__exports__["default"] = Ember; __exports__.default = Ember;
}); });
window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, { window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
@ -16,7 +16,7 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
// if it's a non relative URL, return it. // if it's a non relative URL, return it.
if (!/^\/[^\/]/.test(url)) return url; if (!/^\/[^\/]/.test(url)) return url;
var u = (Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri); var u = Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri;
if (u[u.length-1] === '/') u = u.substring(0, u.length-1); if (u[u.length-1] === '/') u = u.substring(0, u.length-1);
if (url.indexOf(u) !== -1) return url; if (url.indexOf(u) !== -1) return url;
@ -66,7 +66,7 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
// The classes of buttons to show on a post // The classes of buttons to show on a post
postButtons: function() { postButtons: function() {
return Discourse.SiteSettings.post_menu.split("|").map(function(i) { return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
return (i.replace(/\+/, '').capitalize()); return i.replace(/\+/, '').capitalize();
}); });
}.property(), }.property(),
@ -109,12 +109,26 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
$('noscript').remove(); $('noscript').remove();
// Load any ES6 initializers Ember.keys(requirejs._eak_seen).forEach(function(key) {
if (/\/pre\-initializers\//.test(key)) {
var module = require(key, null, null, true);
if (!module) { throw new Error(key + ' must export an initializer.'); }
Discourse.initializer(module.default);
}
});
Ember.keys(requirejs._eak_seen).forEach(function(key) { Ember.keys(requirejs._eak_seen).forEach(function(key) {
if (/\/initializers\//.test(key)) { if (/\/initializers\//.test(key)) {
var module = require(key, null, null, true); var module = require(key, null, null, true);
if (!module) { throw new Error(key + ' must export an initializer.'); } if (!module) { throw new Error(key + ' must export an initializer.'); }
Discourse.initializer(module.default);
var init = module.default;
var oldInitialize = init.initialize;
init.initialize = function(app) {
oldInitialize.call(this, app.container, app);
};
Discourse.instanceInitializer(init);
} }
}); });
@ -125,17 +139,22 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
return desired && Discourse.get("currentAssetVersion") !== desired; return desired && Discourse.get("currentAssetVersion") !== desired;
}.property("currentAssetVersion", "desiredAssetVersion"), }.property("currentAssetVersion", "desiredAssetVersion"),
assetVersion: function(prop, val) {
if(val) {
if(this.get("currentAssetVersion")){
this.set("desiredAssetVersion", val);
} else {
this.set("currentAssetVersion", val);
}
}
return this.get("currentAssetVersion");
}.property()
assetVersion: Ember.computed({
get: function() {
return this.get("currentAssetVersion");
},
set: function(key, val) {
if(val) {
if (this.get("currentAssetVersion")) {
this.set("desiredAssetVersion", val);
} else {
this.set("currentAssetVersion", val);
}
}
return this.get("currentAssetVersion");
}
})
}); });
// TODO: Remove this, it is in for backwards compatibiltiy with plugins // TODO: Remove this, it is in for backwards compatibiltiy with plugins
@ -159,5 +178,3 @@ proxyDep('URL', function() { return require('discourse/lib/url').default });
proxyDep('Quote', function() { return require('discourse/lib/quote').default }); proxyDep('Quote', function() { return require('discourse/lib/quote').default });
proxyDep('debounce', function() { return require('discourse/lib/debounce').default }); proxyDep('debounce', function() { return require('discourse/lib/debounce').default });
proxyDep('View', function() { return Ember.View }, "Use `Ember.View` instead"); proxyDep('View', function() { return Ember.View }, "Use `Ember.View` instead");
proxyDep('Controller', function() { return Ember.Controller }, "Use `Ember.Controller` instead");
proxyDep('ObjectController', function() { return Ember.ObjectController }, "Use `Ember.Controller` instead");

View File

@ -1,23 +1,31 @@
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({ export default Ember.Component.extend({
classNames: ['controls'], classNames: ['controls'],
notificationsPermission: function() { @computed
notificationsPermission() {
if (this.get('isNotSupported')) return ''; if (this.get('isNotSupported')) return '';
return Notification.permission; return Notification.permission;
}.property(), },
notificationsDisabled: function(_, value) { @computed
if (arguments.length > 1) { notificationsDisabled: {
localStorage.setItem('notifications-disabled', value); set(key, value) {
if (arguments.length > 1) {
localStorage.setItem('notifications-disabled', value);
}
return localStorage.getItem('notifications-disabled');
},
get() {
return localStorage.getItem('notifications-disabled');
} }
return localStorage.getItem('notifications-disabled'); },
}.property(),
@computed
isNotSupported: function() { isNotSupported() {
return !window['Notification']; return typeof window.Notification === "undefined";
}.property(), },
isDefaultPermission: function() { isDefaultPermission: function() {
if (this.get('isNotSupported')) return false; if (this.get('isNotSupported')) return false;

View File

@ -50,7 +50,7 @@ export default Ember.Controller.extend({
// create a marker element // create a marker element
const markerElement = document.createElement("span"); const markerElement = document.createElement("span");
// containing a single invisible character // containing a single invisible character
markerElement.appendChild(document.createTextNode("\u{feff}")); markerElement.appendChild(document.createTextNode("\ufeff"));
// collapse the range at the beginning/end of the selection // collapse the range at the beginning/end of the selection
range.collapse(!Discourse.Mobile.isMobileDevice); range.collapse(!Discourse.Mobile.isMobileDevice);

View File

@ -1,20 +1,27 @@
import searchForTerm from 'discourse/lib/search-for-term'; import searchForTerm from 'discourse/lib/search-for-term';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
import computed from 'ember-addons/ember-computed-decorators';
let _dontSearch = false; let _dontSearch = false;
export default Em.Controller.extend({ export default Em.Controller.extend({
typeFilter: null, typeFilter: null,
contextType: function(key, value){ @computed('searchContext')
if(arguments.length > 1) { contextType: {
get(searchContext) {
if (searchContext) {
return Ember.get(searchContext, 'type');
}
},
set(key, value) {
// a bit hacky, consider cleaning this up, need to work through all observers though // a bit hacky, consider cleaning this up, need to work through all observers though
const context = $.extend({}, this.get('searchContext')); const context = $.extend({}, this.get('searchContext'));
context.type = value; context.type = value;
this.set('searchContext', context); this.set('searchContext', context);
return this.get('searchContext.type');
} }
return this.get('searchContext.type'); },
}.property('searchContext'),
contextChanged: function(){ contextChanged: function(){
if (this.get('searchContextEnabled')) { if (this.get('searchContextEnabled')) {

View File

@ -4,6 +4,7 @@ import { spinnerHTML } from 'discourse/helpers/loading-spinner';
import Topic from 'discourse/models/topic'; import Topic from 'discourse/models/topic';
import Quote from 'discourse/lib/quote'; import Quote from 'discourse/lib/quote';
import { setting } from 'discourse/lib/computed'; import { setting } from 'discourse/lib/computed';
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
multiSelect: false, multiSelect: false,
@ -65,35 +66,53 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
}.observes('model.postStream', 'model.postStream.loadedAllPosts'), }.observes('model.postStream', 'model.postStream.loadedAllPosts'),
show_deleted: function(key, value) { @computed('model.postStream.summary')
const postStream = this.get('model.postStream'); show_deleted: {
if (!postStream) { return; } set(key, value) {
const postStream = this.get('model.postStream');
if (!postStream) { return; }
if (arguments.length > 1) { if (arguments.length > 1) {
postStream.set('show_deleted', value); postStream.set('show_deleted', value);
}
return postStream.get('show_deleted') ? true : undefined;
},
get() {
return this.get('postStream.show_deleted') ? true : undefined;
} }
return postStream.get('show_deleted') ? true : undefined; },
}.property('model.postStream.summary'),
filter: function(key, value) { @computed('model.postStream.summary')
const postStream = this.get('model.postStream'); filter: {
if (!postStream) { return; } set(key, value) {
const postStream = this.get('model.postStream');
if (!postStream) { return; }
if (arguments.length > 1) { if (arguments.length > 1) {
postStream.set('summary', value === "summary"); postStream.set('summary', value === "summary");
}
return postStream.get('summary') ? "summary" : undefined;
},
get() {
return this.get('postStream.summary') ? "summary" : undefined;
} }
return postStream.get('summary') ? "summary" : undefined; },
}.property('model.postStream.summary'),
username_filters: function(key, value) { @computed('model.postStream.streamFilters.username_filters')
const postStream = this.get('model.postStream'); username_filters: {
if (!postStream) { return; } set(key, value) {
const postStream = this.get('model.postStream');
if (!postStream) { return; }
if (arguments.length > 1) { if (arguments.length > 1) {
postStream.set('streamFilters.username_filters', value); postStream.set('streamFilters.username_filters', value);
}
return postStream.get('streamFilters.username_filters');
},
get() {
return this.get('postStream.streamFilters.username_filters');
} }
return postStream.get('streamFilters.username_filters'); },
}.property('model.postStream.streamFilters.username_filters'),
_clearSelected: function() { _clearSelected: function() {
this.set('selectedPosts', []); this.set('selectedPosts', []);
@ -489,13 +508,13 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
canMergeTopic: function() { canMergeTopic: function() {
if (!this.get('model.details.can_move_posts')) return false; if (!this.get('model.details.can_move_posts')) return false;
return (this.get('selectedPostsCount') > 0); return this.get('selectedPostsCount') > 0;
}.property('selectedPostsCount'), }.property('selectedPostsCount'),
canSplitTopic: function() { canSplitTopic: function() {
if (!this.get('model.details.can_move_posts')) return false; if (!this.get('model.details.can_move_posts')) return false;
if (this.get('allPostsSelected')) return false; if (this.get('allPostsSelected')) return false;
return (this.get('selectedPostsCount') > 0); return this.get('selectedPostsCount') > 0;
}.property('selectedPostsCount'), }.property('selectedPostsCount'),
canChangeOwner: function() { canChangeOwner: function() {

View File

@ -2,6 +2,5 @@ import { applyFlaggedProperties } from 'discourse/controllers/header';
export default { export default {
name: 'apply-flagged-properties', name: 'apply-flagged-properties',
after: 'register-discourse-location',
initialize: applyFlaggedProperties initialize: applyFlaggedProperties
}; };

View File

@ -1,7 +1,6 @@
// Append our CSRF token to AJAX requests when necessary. // Append our CSRF token to AJAX requests when necessary.
export default { export default {
name: "csrf-token", name: "csrf-token",
after: 'inject-objects',
initialize: function(container) { initialize: function(container) {
var session = container.lookup('session:main'); var session = container.lookup('session:main');

View File

@ -2,7 +2,6 @@ import { showSelector } from "discourse/lib/emoji/emoji-toolbar";
export default { export default {
name: 'enable-emoji', name: 'enable-emoji',
after: 'inject-objects',
initialize(container) { initialize(container) {
const siteSettings = container.lookup('site-settings:main'); const siteSettings = container.lookup('site-settings:main');

View File

@ -1,50 +1,6 @@
import Session from 'discourse/models/session'; // backwards compatibility for plugins that depend on this initializer
import AppEvents from 'discourse/lib/app-events';
import Store from 'discourse/models/store';
import DiscourseURL from 'discourse/lib/url';
function inject() {
const app = arguments[0],
name = arguments[1],
singletonName = Ember.String.underscore(name).replace(/_/, '-') + ':main';
Array.prototype.slice.call(arguments, 2).forEach(function(dest) {
app.inject(dest, name, singletonName);
});
}
function injectAll(app, name) {
inject(app, name, 'controller', 'component', 'route', 'view', 'model');
}
export default { export default {
name: "inject-objects", name: "inject-objects",
initialize(container, app) { initialize: Ember.K
const appEvents = AppEvents.create();
app.register('app-events:main', appEvents, { instantiate: false });
injectAll(app, 'appEvents');
DiscourseURL.appEvents = appEvents;
app.register('store:main', Store);
inject(app, 'store', 'route', 'controller');
// Inject Discourse.Site to avoid using Discourse.Site.current()
const site = Discourse.Site.current();
app.register('site:main', site, { instantiate: false });
injectAll(app, 'site');
// Inject Discourse.SiteSettings to avoid using Discourse.SiteSettings globals
app.register('site-settings:main', Discourse.SiteSettings, { instantiate: false });
injectAll(app, 'siteSettings');
// Inject Session for transient data
app.register('session:main', Session.current(), { instantiate: false });
injectAll(app, 'session');
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
inject(app, 'currentUser', 'component', 'route', 'controller');
app.register('message-bus:main', window.MessageBus, { instantiate: false });
inject(app, 'messageBus', 'route', 'controller', 'view', 'component');
}
}; };

View File

@ -3,7 +3,6 @@ import PageTracker from 'discourse/lib/page-tracker';
export default { export default {
name: "page-tracking", name: "page-tracking",
after: 'register-discourse-location',
initialize(container) { initialize(container) {

View File

@ -1,10 +1,6 @@
import DiscourseLocation from 'discourse/lib/discourse-location'; // backwards compatibility for plugins that depend on this initializer
export default { export default {
name: "register-discourse-location", name: "register-discourse-location",
after: 'inject-objects', initialize: Ember.K
initialize: function(container, application) {
application.register('location:discourse-location', DiscourseLocation);
}
}; };

View File

@ -4,14 +4,13 @@ import DiscoverySortableController from 'discourse/controllers/discovery-sortabl
export default { export default {
name: 'dynamic-route-builders', name: 'dynamic-route-builders',
after: 'register-discourse-location',
initialize(container, app) { initialize(container, app) {
app.DiscoveryCategoryRoute = buildCategoryRoute('latest'); app.DiscoveryCategoryRoute = buildCategoryRoute('latest');
app.DiscoveryParentCategoryRoute = buildCategoryRoute('latest'); app.DiscoveryParentCategoryRoute = buildCategoryRoute('latest');
app.DiscoveryCategoryNoneRoute = buildCategoryRoute('latest', {no_subcategories: true}); app.DiscoveryCategoryNoneRoute = buildCategoryRoute('latest', {no_subcategories: true});
var site = container.lookup('site:main'); const site = Discourse.Site.current();
site.get('filters').forEach(function(filter) { site.get('filters').forEach(function(filter) {
app["Discovery" + filter.capitalize() + "Controller"] = DiscoverySortableController.extend(); app["Discovery" + filter.capitalize() + "Controller"] = DiscoverySortableController.extend();
app["Discovery" + filter.capitalize() + "Route"] = buildTopicRoute(filter); app["Discovery" + filter.capitalize() + "Route"] = buildTopicRoute(filter);

View File

@ -0,0 +1,53 @@
import Session from 'discourse/models/session';
import AppEvents from 'discourse/lib/app-events';
import Store from 'discourse/models/store';
import DiscourseURL from 'discourse/lib/url';
import DiscourseLocation from 'discourse/lib/discourse-location';
function inject() {
const app = arguments[0],
name = arguments[1],
singletonName = Ember.String.underscore(name).replace(/_/, '-') + ':main';
Array.prototype.slice.call(arguments, 2).forEach(function(dest) {
app.inject(dest, name, singletonName);
});
}
function injectAll(app, name) {
inject(app, name, 'controller', 'component', 'route', 'view', 'model');
}
export default {
name: "inject-discourse-objects",
initialize(container, app) {
const appEvents = AppEvents.create();
app.register('app-events:main', appEvents, { instantiate: false });
injectAll(app, 'appEvents');
DiscourseURL.appEvents = appEvents;
app.register('store:main', Store);
inject(app, 'store', 'route', 'controller');
// Inject Discourse.Site to avoid using Discourse.Site.current()
const site = Discourse.Site.current();
app.register('site:main', site, { instantiate: false });
injectAll(app, 'site');
// Inject Discourse.SiteSettings to avoid using Discourse.SiteSettings globals
app.register('site-settings:main', Discourse.SiteSettings, { instantiate: false });
injectAll(app, 'siteSettings');
// Inject Session for transient data
app.register('session:main', Session.current(), { instantiate: false });
injectAll(app, 'session');
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
inject(app, 'currentUser', 'component', 'route', 'controller');
app.register('message-bus:main', window.MessageBus, { instantiate: false });
inject(app, 'messageBus', 'route', 'controller', 'view', 'component');
app.register('location:discourse-location', DiscourseLocation);
}
};

View File

@ -2,7 +2,7 @@ import { mapRoutes } from 'discourse/router';
export default { export default {
name: "map-routes", name: "map-routes",
after: 'inject-objects', after: 'inject-discourse-objects',
initialize(container, app) { initialize(container, app) {
app.register('router:main', mapRoutes()); app.register('router:main', mapRoutes());

View File

@ -1,3 +1,3 @@
export default Discourse.View.extend({ export default Ember.View.extend({
classNames: ["topic-unsubscribe"] classNames: ["topic-unsubscribe"]
}); });

View File

@ -0,0 +1,22 @@
import extractValue from './utils/extract-value';
export default function decoratorAlias(fn, errorMessage) {
return function(...params) {
// determine if user called as @computed('blah', 'blah') or @computed
if (params.length === 0) {
throw new Error(errorMessage);
} else {
return function(target, key, desc) {
return {
enumerable: desc.enumerable,
configurable: desc.configurable,
writable: desc.writable,
initializer: function() {
var value = extractValue(desc);
return fn.apply(null, params.concat(value));
}
};
};
}
};
}

View File

@ -0,0 +1,63 @@
import handleDescriptor from './utils/handle-descriptor';
import isDescriptor from './utils/is-descriptor';
import extractValue from './utils/extract-value';
export default function computedDecorator(...params) {
// determine if user called as @computed('blah', 'blah') or @computed
if (isDescriptor(params[params.length - 1])) {
return handleDescriptor(...arguments);
} else {
return function(/* target, key, desc */) {
return handleDescriptor(...arguments, params);
};
}
}
export function readOnly(target, name, desc) {
return {
writable: false,
enumerable: desc.enumerable,
configurable: desc.configurable,
initializer: function() {
var value = extractValue(desc);
return value.readOnly();
}
};
}
import decoratorAlias from './decorator-alias';
export var on = decoratorAlias(Ember.on, 'Can not `on` without event names');
export var observes = decoratorAlias(Ember.observer, 'Can not `observe` without property names');
import macroAlias from './macro-alias';
export var alias = macroAlias(Ember.computed.alias);
export var and = macroAlias(Ember.computed.and);
export var bool = macroAlias(Ember.computed.bool);
export var collect = macroAlias(Ember.computed.collect);
export var empty = macroAlias(Ember.computed.empty);
export var equal = macroAlias(Ember.computed.equal);
export var filter = macroAlias(Ember.computed.filter);
export var filterBy = macroAlias(Ember.computed.filterBy);
export var gt = macroAlias(Ember.computed.gt);
export var gte = macroAlias(Ember.computed.gte);
export var lt = macroAlias(Ember.computed.lt);
export var lte = macroAlias(Ember.computed.lte);
export var map = macroAlias(Ember.computed.map);
export var mapBy = macroAlias(Ember.computed.mapBy);
export var match = macroAlias(Ember.computed.match);
export var max = macroAlias(Ember.computed.max);
export var min = macroAlias(Ember.computed.min);
export var none = macroAlias(Ember.computed.none);
export var not = macroAlias(Ember.computed.not);
export var notEmpty = macroAlias(Ember.computed.notEmpty);
export var oneWay = macroAlias(Ember.computed.oneWay);
export var or = macroAlias(Ember.computed.or);
export var readOnly = macroAlias(Ember.computed.readOnly);
export var reads = macroAlias(Ember.computed.reads);
export var setDiff = macroAlias(Ember.computed.setDiff);
export var sort = macroAlias(Ember.computed.sort);
export var sum = macroAlias(Ember.computed.sum);
export var union = macroAlias(Ember.computed.union);
export var uniq = macroAlias(Ember.computed.uniq);

View File

@ -0,0 +1,24 @@
import isDescriptor from './utils/is-descriptor';
function handleDescriptor(target, property, desc, fn, params = []) {
return {
enumerable: desc.enumerable,
configurable: desc.configurable,
writable: desc.writable,
initializer: function() {
return fn(...params);
}
};
}
export default function macroAlias(fn) {
return function(...params) {
if (isDescriptor(params[params.length - 1])) {
return handleDescriptor(...params, fn);
} else {
return function(target, property, desc) {
return handleDescriptor(target, property, desc, fn, params);
};
}
};
}

View File

@ -0,0 +1,4 @@
export default function extractValue(desc) {
return desc.value ||
(typeof desc.initializer === 'function' && desc.initializer());
}

View File

@ -0,0 +1,67 @@
import Ember from 'ember';
import extractValue from './extract-value';
const { computed, get } = Ember;
export default function handleDescriptor(target, key, desc, params = []) {
return {
enumerable: desc.enumerable,
configurable: desc.configurable,
writeable: desc.writeable,
initializer: function() {
let computedDescriptor;
if (desc.writable) {
var val = extractValue(desc);
if (typeof val === 'object') {
let value = { };
if (val.get) { value.get = callUserSuppliedGet(params, val.get); }
if (val.set) { value.set = callUserSuppliedSet(params, val.set); }
computedDescriptor = value;
} else {
computedDescriptor = callUserSuppliedGet(params, val);
}
} else {
throw new Error('ember-computed-decorators does not support using getters and setters');
}
return computed.apply(null, params.concat(computedDescriptor));
}
};
}
function niceAttr(attr) {
const parts = attr.split('.');
let i;
for (i = 0; i < parts.length; i++) {
if (parts[i] === '@each' ||
parts[i] === '[]' ||
parts[i].indexOf('{') !== -1) {
break;
}
}
return parts.slice(0, i).join('.');
}
function callUserSuppliedGet(params, func) {
params = params.map(niceAttr);
return function() {
let paramValues = params.map(p => get(this, p));
return func.apply(this, paramValues);
};
}
function callUserSuppliedSet(params, func) {
params = params.map(niceAttr);
return function(key, value) {
let paramValues = params.map(p => get(this, p));
paramValues.unshift(value);
return func.apply(this, paramValues);
};
}

View File

@ -0,0 +1,7 @@
export default function isDescriptor(item) {
return item &&
typeof item === 'object' &&
'writable' in item &&
'enumerable' in item &&
'configurable' in item;
}

View File

@ -1,7 +1,7 @@
<% <%
if Rails.env.development? || Rails.env.test? if Rails.env.development? || Rails.env.test?
require_asset ("ember-template-compiler.js") require_asset ("ember-template-compiler.js")
require_asset ("ember.custom.debug.js") require_asset ("ember.debug.js")
else else
require_asset ("ember-template-compiler.js") require_asset ("ember-template-compiler.js")
require_asset ("ember.prod.js") require_asset ("ember.prod.js")

View File

@ -5,6 +5,10 @@
//= require ./pagedown_custom.js //= require ./pagedown_custom.js
// Stuff we need to load first // Stuff we need to load first
//= require_tree ./ember-addons/utils
//= require ./ember-addons/decorator-alias
//= require ./ember-addons/macro-alias
//= require ./ember-addons/ember-computed-decorators
//= require ./discourse/lib/load-script //= require ./discourse/lib/load-script
//= require ./discourse/lib/notification-levels //= require ./discourse/lib/notification-levels
//= require ./discourse/lib/app-events //= require ./discourse/lib/app-events
@ -94,4 +98,5 @@
//= require_tree ./discourse/helpers //= require_tree ./discourse/helpers
//= require_tree ./discourse/templates //= require_tree ./discourse/templates
//= require_tree ./discourse/routes //= require_tree ./discourse/routes
//= require_tree ./discourse/pre-initializers
//= require_tree ./discourse/initializers //= require_tree ./discourse/initializers

View File

@ -26,8 +26,8 @@
}); });
<% if Rails.env.development? || Rails.env.test? %> <% if Rails.env.development? || Rails.env.test? %>
Ember.ENV.RAISE_ON_DEPRECATION = true //Ember.ENV.RAISE_ON_DEPRECATION = true
Ember.LOG_STACKTRACE_ON_DEPRECATION = true //Ember.LOG_STACKTRACE_ON_DEPRECATION = true
<% end %> <% end %>
</script> </script>

View File

@ -31,7 +31,7 @@ class DiscourseIIFE < Sprockets::Processor
req_path = path.sub(Rails.root.to_s, '') req_path = path.sub(Rails.root.to_s, '')
.sub("/app/assets/javascripts", "") .sub("/app/assets/javascripts", "")
.sub("/test/javascripts", "") .sub("/test/javascripts", "")
res << "\nwindow.__jshintSrc = window.__jshintSrc || {}; window.__jshintSrc['/assets#{req_path}'] = #{data.to_json};\n" res << "\nwindow.__eslintSrc = window.__eslintSrc || {}; window.__eslintSrc['/assets#{req_path}'] = #{data.to_json};\n"
end end
res res

View File

@ -83,8 +83,6 @@ module Tilt
@output = klass.v8.eval(generate_source(scope)) @output = klass.v8.eval(generate_source(scope))
end end
source = @output.dup
# For backwards compatibility with plugins, for now export the Global format too. # For backwards compatibility with plugins, for now export the Global format too.
# We should eventually have an upgrade system for plugins to use ES6 or some other # We should eventually have an upgrade system for plugins to use ES6 or some other
# resolve based API. # resolve based API.
@ -129,7 +127,7 @@ module Tilt
end end
req_path = "/assets/#{scope.logical_path}.#{extension}" req_path = "/assets/#{scope.logical_path}.#{extension}"
@output << "\nwindow.__jshintSrc = window.__jshintSrc || {}; window.__jshintSrc['#{req_path}'] = #{data.to_json};\n" @output << "\nwindow.__eslintSrc = window.__eslintSrc || {}; window.__eslintSrc['#{req_path}'] = #{data.to_json};\n"
end end
@output @output
@ -139,7 +137,7 @@ module Tilt
def generate_source(scope) def generate_source(scope)
js_source = ::JSON.generate(data, quirks_mode: true) js_source = ::JSON.generate(data, quirks_mode: true)
js_source = "babel.transform(#{js_source}, {ast: false, whitelist: ['es6.constants', 'es6.properties.shorthand', 'es6.arrowFunctions', 'es6.blockScoping', 'es6.destructuring', 'es6.templateLiterals', 'es6.regex.unicode']})['code']" js_source = "babel.transform(#{js_source}, {ast: false, whitelist: ['es6.constants', 'es6.properties.shorthand', 'es6.arrowFunctions', 'es6.blockScoping', 'es6.destructuring', 'es6.spread', 'es6.parameters', 'es6.templateLiterals', 'es6.regex.unicode', 'es7.decorators']})['code']"
"new module.exports.Compiler(#{js_source}, '#{module_name(scope.root_path, scope.logical_path)}', #{compiler_options}).#{compiler_method}()" "new module.exports.Compiler(#{js_source}, '#{module_name(scope.root_path, scope.logical_path)}', #{compiler_options}).#{compiler_method}()"
end end

View File

@ -1,107 +0,0 @@
module("JSHint");
<%= "const JSHINT_OPTS = #{File.read(File.join(Rails.root, '.jshintrc'))};" %>
var qHint = function(name, sourceFile) {
return asyncTestDiscourse(name, function() {
if (typeof window.__jshintSrc !== "undefined") {
var src = window.__jshintSrc[sourceFile];
if (src) {
start();
qHint.validateFile(src, JSHINT_OPTS);
return;
}
}
});
};
qHint.validateFile = function (source, options, globals) {
var i, len, err;
source = source.replace(/^[^]*\/\/ IIFE Wrapped Content Begins:\n\n/m, "");
source = source.replace(/\n\n\/\/ IIFE Wrapped Content Ends[^]*$/m, "");
if (JSHINT(source, options, globals)) {
ok(true);
return;
}
for (i = 0, len = JSHINT.errors.length; i < len; i++) {
err = JSHINT.errors[i];
if (!err) {
continue;
}
ok(false, err.reason +
" on line " + err.line +
", character " + err.character);
}
};
var XMLHttpFactories = [
function () { return new XMLHttpRequest(); },
function () { return new ActiveXObject("Msxml2.XMLHTTP"); },
function () { return new ActiveXObject("Msxml3.XMLHTTP"); },
function () { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
function createXMLHTTPObject() {
for (var i = 0; i < XMLHttpFactories.length; i++) {
try {
return XMLHttpFactories[i]();
} catch (e) {}
}
return false;
}
// modified version of XHR script by PPK
// http://www.quirksmode.org/js/xmlhttp.html
// attached to qHint to allow substitution / mocking
qHint.sendRequest = function (url, callback) {
var req = createXMLHTTPObject();
if (!req) {
return;
}
var method = "GET";
req.open(method,url + "?" + (new Date().getTime()),true);
req.onreadystatechange = function () {
if (req.readyState != 4) {
return;
}
callback(req);
};
if (req.readyState == 4) {
return;
}
req.send();
};
<%
TO_IGNORE = File.read("#{Rails.root}/.jshintignore").split("\n")
def jshint(dir, remove)
result = ""
Dir.glob(dir).each do |f|
filename = f.sub("#{Rails.root}/#{remove}", "")
ok = true
TO_IGNORE.each do |ig|
ok = false unless (filename.index(ig.sub(remove, '')).nil?)
end
depend_on filename
result << "qHint('#{filename}', '/assets/#{filename}', JSHINT_OPTS);\n" if ok
end
result
end
%>
<%= jshint("#{Rails.root}/test/**/*.js", "test/javascripts/") %>
<%= jshint("#{Rails.root}/app/assets/javascripts/**/*.js", "app/assets/javascripts/") %>
<%= jshint("#{Rails.root}/app/assets/javascripts/**/*.es6", "app/assets/javascripts/") %>

View File

@ -75,7 +75,7 @@ test("removes the href and put it as a data attribute", function() {
ok(DiscourseURL.redirectTo.calledOnce); ok(DiscourseURL.redirectTo.calledOnce);
}); });
asyncTest("restores the href after a while", function() { asyncTestDiscourse("restores the href after a while", function() {
expect(1); expect(1);
track(generateClickEventOn('a')); track(generateClickEventOn('a'));

View File

@ -1,4 +1,3 @@
/*jshint maxlen:250 */
/*global document, sinon, QUnit, Logster */ /*global document, sinon, QUnit, Logster */
//= require env //= require env
@ -12,7 +11,7 @@
//= require jquery.debug //= require jquery.debug
//= require jquery.ui.widget //= require jquery.ui.widget
//= require handlebars //= require handlebars
//= require ember.custom.debug //= require ember.debug
//= require message-bus //= require message-bus
//= require ember-qunit //= require ember-qunit
//= require fake_xml_http_request //= require fake_xml_http_request
@ -36,7 +35,6 @@
//= require sinon-1.7.1 //= require sinon-1.7.1
//= require sinon-qunit-1.0.0 //= require sinon-qunit-1.0.0
//= require jshint
//= require helpers/qunit-helpers //= require helpers/qunit-helpers
//= require helpers/assertions //= require helpers/assertions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long