Fixes some deprecations:

- LoadMore as a Mixin for discovery, groups
- Removed Views for discovery, groups
This commit is contained in:
Robin Ward 2016-04-28 12:14:50 -04:00
parent 2a2b0d7803
commit 04ec679d82
No known key found for this signature in database
GPG Key ID: 0E091E2B4ED1B83D
38 changed files with 191 additions and 237 deletions

View File

@ -3,7 +3,9 @@ import { on } from 'ember-addons/ember-computed-decorators';
const CATEGORIES_LIST_BODY_CLASS = "categories-list"; const CATEGORIES_LIST_BODY_CLASS = "categories-list";
export default Ember.View.extend(UrlRefresh, { export default Ember.Component.extend(UrlRefresh, {
classNames: ['contents'],
@on("didInsertElement") @on("didInsertElement")
addBodyClass() { addBodyClass() {
$('body').addClass(CATEGORIES_LIST_BODY_CLASS); $('body').addClass(CATEGORIES_LIST_BODY_CLASS);

View File

@ -1,27 +1,15 @@
import UrlRefresh from 'discourse/mixins/url-refresh';
import LoadMore from "discourse/mixins/load-more";
import { on, observes } from "ember-addons/ember-computed-decorators"; import { on, observes } from "ember-addons/ember-computed-decorators";
import LoadMore from "discourse/mixins/load-more";
import UrlRefresh from 'discourse/mixins/url-refresh';
export default Ember.View.extend(LoadMore, UrlRefresh, { const DiscoveryTopicsListComponent = Ember.Component.extend(UrlRefresh, LoadMore, {
_viaComponent: true,
classNames: ['contents'],
eyelineSelector: '.topic-list-item', eyelineSelector: '.topic-list-item',
actions: {
loadMore() {
const self = this;
Discourse.notifyTitle(0);
this.get('controller').loadMoreTopics().then(hasMoreResults => {
Ember.run.schedule('afterRender', () => self.saveScrollPosition());
if (!hasMoreResults) {
this.get('eyeline').flushRest();
} else if ($(window).height() >= $(document).height()) {
this.send("loadMore");
}
});
}
},
@on("didInsertElement") @on("didInsertElement")
@observes("controller.model") @observes("model")
_readjustScrollPosition() { _readjustScrollPosition() {
const scrollTo = this.session.get('topicListScrollPosition'); const scrollTo = this.session.get('topicListScrollPosition');
if (scrollTo && scrollTo >= 0) { if (scrollTo && scrollTo >= 0) {
@ -31,19 +19,33 @@ export default Ember.View.extend(LoadMore, UrlRefresh, {
} }
}, },
@observes("controller.topicTrackingState.incomingCount") @observes("incomingCount")
_updateTitle() { _updateTitle() {
Discourse.notifyTitle(this.get('controller.topicTrackingState.incomingCount')); Discourse.notifyTitle(this.get('incomingCount'));
}, },
// Remember where we were scrolled to
saveScrollPosition() { saveScrollPosition() {
this.session.set('topicListScrollPosition', $(window).scrollTop()); this.session.set('topicListScrollPosition', $(window).scrollTop());
}, },
// When the topic list is scrolled
scrolled() { scrolled() {
this._super(); this._super();
this.saveScrollPosition(); this.saveScrollPosition();
},
actions: {
loadMore() {
Discourse.notifyTitle(0);
this.get('model').loadMore().then(hasMoreResults => {
Ember.run.schedule('afterRender', () => this.saveScrollPosition());
if (!hasMoreResults) {
this.get('eyeline').flushRest();
} else if ($(window).height() >= $(document).height()) {
this.send("loadMore");
}
});
}
} }
}); });
export default DiscoveryTopicsListComponent;

View File

@ -0,0 +1,8 @@
export default Ember.Component.extend({
actions: {
// TODO: When on Ember 1.13, use a closure action
loadMore() {
this.sendAction('loadMore');
}
}
});

View File

@ -138,11 +138,8 @@ const controllerOpts = {
return I18n.t("topics.none.educate." + split[0], { return I18n.t("topics.none.educate." + split[0], {
userPrefsUrl: Discourse.getURL("/users/") + (Discourse.User.currentProp("username_lower")) + "/preferences" userPrefsUrl: Discourse.getURL("/users/") + (Discourse.User.currentProp("username_lower")) + "/preferences"
}); });
}.property('allLoaded', 'model.topics.length'), }.property('allLoaded', 'model.topics.length')
loadMoreTopics() {
return this.get('model').loadMore();
}
}; };
Ember.keys(queryParams).forEach(function(p) { Ember.keys(queryParams).forEach(function(p) {

View File

@ -0,0 +1,27 @@
import { fmt } from 'discourse/lib/computed';
export default Ember.ArrayController.extend({
needs: ['group'],
loading: false,
emptyText: fmt('type', 'groups.empty.%@'),
actions: {
loadMore() {
if (this.get('loading')) { return; }
this.set('loading', true);
const posts = this.get('model');
if (posts && posts.length) {
const beforePostId = posts[posts.length-1].get('id');
const group = this.get('controllers.group.model');
const opts = { beforePostId, type: this.get('type') };
group.findPosts(opts).then(newPosts => {
posts.addObjects(newPosts);
this.set('loading', false);
});
}
}
}
});

View File

@ -1,28 +0,0 @@
/**
Handles displaying posts within a group
**/
export default Ember.ArrayController.extend({
needs: ['group'],
loading: false,
actions: {
loadMore: function() {
if (this.get('loading')) { return; }
this.set('loading', true);
var posts = this.get('model'),
self = this;
if (posts && posts.length) {
var lastPostId = posts[posts.length-1].get('id'),
group = this.get('controllers.group.model');
var opts = {beforePostId: lastPostId, type: this.get('type')};
group.findPosts(opts).then(function(newPosts) {
posts.addObjects(newPosts);
self.set('loading', false);
});
}
}
}
});

View File

@ -1,5 +1,6 @@
import { popupAjaxError } from 'discourse/lib/ajax-error'; import { popupAjaxError } from 'discourse/lib/ajax-error';
import computed from 'ember-addons/ember-computed-decorators'; import computed from 'ember-addons/ember-computed-decorators';
import Group from 'discourse/models/group';
export default Ember.Controller.extend({ export default Ember.Controller.extend({
loading: false, loading: false,
@ -30,10 +31,7 @@ export default Ember.Controller.extend({
}, },
loadMore() { loadMore() {
const Group = require('discourse/models/group').default;
if (this.get("loading")) { return; } if (this.get("loading")) { return; }
// we've reached the end
if (this.get("model.members.length") >= this.get("model.user_count")) { return; } if (this.get("model.members.length") >= this.get("model.user_count")) { return; }
this.set("loading", true); this.set("loading", true);

View File

@ -1,3 +0,0 @@
import IndexController from 'discourse/controllers/group/index';
export default IndexController.extend({type: 'mentions'});

View File

@ -1,3 +0,0 @@
import IndexController from 'discourse/controllers/group/index';
export default IndexController.extend({type: 'topics'});

View File

@ -1,25 +1 @@
var id = 1;
function newKey() {
return "_view_app_event_" + (id++);
}
function createViewListener(eventName, cb) {
var extension = {};
extension[newKey()] = function() {
this.appEvents.on(eventName, this, cb);
}.on('didInsertElement');
extension[newKey()] = function() {
this.appEvents.off(eventName, this, cb);
}.on('willDestroyElement');
return extension;
}
function listenForViewEvent(viewClass, eventName, cb) {
viewClass.reopen(createViewListener(eventName, cb));
}
export { listenForViewEvent, createViewListener };
export default Ember.Object.extend(Ember.Evented); export default Ember.Object.extend(Ember.Evented);

View File

@ -1,4 +1,5 @@
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
import { wantsNewWindow } from 'discourse/lib/intercept-click';
export function isValidLink($link) { export function isValidLink($link) {
return ($link.hasClass("track-link") || return ($link.hasClass("track-link") ||
@ -52,7 +53,7 @@ export default {
} }
// if they want to open in a new tab, do an AJAX request // if they want to open in a new tab, do an AJAX request
if (e.shiftKey || e.metaKey || e.ctrlKey || e.which === 2) { if (wantsNewWindow(e)) {
Discourse.ajax("/clicks/track", { Discourse.ajax("/clicks/track", {
data: { data: {
url: href, url: href,

View File

@ -1,12 +1,16 @@
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
export function wantsNewWindow(e) {
return (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey || (e.button && e.button !== 0));
}
/** /**
Discourse does some server side rendering of HTML, such as the `cooked` contents of Discourse does some server side rendering of HTML, such as the `cooked` contents of
posts. The downside of this in an Ember app is the links will not go through the router. posts. The downside of this in an Ember app is the links will not go through the router.
This jQuery code intercepts clicks on those links and routes them properly. This jQuery code intercepts clicks on those links and routes them properly.
**/ **/
export default function interceptClick(e) { export default function interceptClick(e) {
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; } if (wantsNewWindow(e)) { return; }
const $currentTarget = $(e.currentTarget), const $currentTarget = $(e.currentTarget),
href = $currentTarget.attr('href'); href = $currentTarget.attr('href');

View File

@ -1,12 +1,16 @@
// A Mixin that a view can use to listen for 'url:refresh' when // A Mixin that a view can use to listen for 'url:refresh' when
// it is on screen, and will send an action to the controller to // it is on screen, and will send an action to refresh its data.
// refresh its data.
// //
// This is useful if you want to get around Ember's default // This is useful if you want to get around Ember's default
// behavior of not refreshing when navigating to the same place. // behavior of not refreshing when navigating to the same place.
export default {
didInsertElement() {
this._super();
this.appEvents.on('url:refresh', () => this.sendAction('refresh'));
},
import { createViewListener } from 'discourse/lib/app-events'; willDestroyElement() {
this._super();
export default createViewListener('url:refresh', function() { this.appEvents.off('url:refresh');
this.get('controller').send('refresh'); }
}); };

View File

@ -1,14 +1,24 @@
export default Discourse.Route.extend({ export function buildIndex(type) {
actions: { return Discourse.Route.extend({
didTransition() { return true; } type,
},
model() { model() {
return this.modelFor("group").findPosts(); return this.modelFor("group").findPosts({ type });
}, },
setupController(controller, model) { setupController(controller, model) {
controller.set("model", model); this.controllerFor('group-index').setProperties({ model, type });
this.controllerFor("group").set("showing", "posts"); this.controllerFor("group").set("showing", type);
},
renderTemplate() {
this.render('group-index');
},
actions: {
didTransition() { return true; }
} }
}); });
}
export default buildIndex('posts');

View File

@ -8,5 +8,4 @@ export default Discourse.Route.extend({
controller.set("model", model); controller.set("model", model);
model.findMembers(); model.findMembers();
} }
}); });

View File

@ -1,11 +1,3 @@
export default Discourse.Route.extend({ import { buildIndex } from 'discourse/routes/group-index';
model() { export default buildIndex('mentions');
return this.modelFor("group").findPosts({type: 'mentions'});
},
setupController(controller, model) {
controller.set("model", model);
this.controllerFor("group").set("showing", "mentions");
}
});

View File

@ -1,11 +1,3 @@
export default Discourse.Route.extend({ import { buildIndex } from 'discourse/routes/group-index';
model() { export default buildIndex('messages');
return this.modelFor("group").findPosts({type: 'messages'});
},
setupController(controller, model) {
controller.set("model", model);
this.controllerFor("group").set("showing", "messages");
}
});

View File

@ -1,11 +1,3 @@
export default Discourse.Route.extend({ import { buildIndex } from 'discourse/routes/group-index';
model() { export default buildIndex('topics');
return this.modelFor("group").findPosts({type: 'topics'});
},
setupController(controller, model) {
controller.set("model", model);
this.controllerFor("group").set("showing", "topics");
}
});

View File

@ -1,7 +1,9 @@
<div class='user-stream'> {{#load-more selector=".user-stream .item" action="loadMore"}}
<div class='user-stream'>
{{#each posts as |post|}} {{#each posts as |post|}}
{{group-post post=post}} {{group-post post=post}}
{{else}} {{else}}
<div>{{i18n emptyText}}</div> <div>{{i18n emptyText}}</div>
{{/each}} {{/each}}
</div> </div>
{{/load-more}}

View File

@ -1,5 +1,5 @@
{{#if model.categories}} {{#if model.categories}}
<div class='contents'> {{#discovery-categories refresh="refresh"}}
<table class='topic-list categories'> <table class='topic-list categories'>
<thead> <thead>
<tr> <tr>
@ -54,6 +54,6 @@
{{/each}} {{/each}}
</tbody> </tbody>
</table> </table>
</div> {{/discovery-categories}}
<footer class='topic-list-bottom'></footer> <footer class='topic-list-bottom'></footer>
{{/if}} {{/if}}

View File

@ -15,7 +15,7 @@
{{bulk-select-button selected=selected refreshTarget=controller}} {{bulk-select-button selected=selected refreshTarget=controller}}
<div class='contents'> {{#discovery-topics-list model=model refresh="refresh" incomingCount=topicTrackingState.incomingCount}}
{{#if top}} {{#if top}}
<div class='top-lists'> <div class='top-lists'>
{{period-chooser period=period action="changePeriod"}} {{period-chooser period=period action="changePeriod"}}
@ -48,7 +48,7 @@
expandAllPinned=expandAllPinned expandAllPinned=expandAllPinned
topics=model.topics}} topics=model.topics}}
{{/if}} {{/if}}
</div> {{/discovery-topics-list}}
<footer class='topic-list-bottom'> <footer class='topic-list-bottom'>
{{conditional-loading-spinner condition=model.loadingMore}} {{conditional-loading-spinner condition=model.loadingMore}}

View File

@ -0,0 +1 @@
{{group-post-stream posts=controller emptyText=emptyText loadMore="loadMore"}}

View File

@ -1 +0,0 @@
{{group-post-stream posts=controller emptyText="groups.empty.posts"}}

View File

@ -7,6 +7,8 @@
</form> </form>
</div> </div>
{{/if}} {{/if}}
{{#load-more selector=".group-members tr" action="loadMore"}}
<table class='group-members'> <table class='group-members'>
<tr> <tr>
<th colspan="2">{{i18n 'last_post'}}</th> <th colspan="2">{{i18n 'last_post'}}</th>
@ -37,6 +39,7 @@
</tr> </tr>
{{/each}} {{/each}}
</table> </table>
{{/load-more}}
{{else}} {{else}}
<div>{{i18n "groups.empty.users"}}</div> <div>{{i18n "groups.empty.users"}}</div>
{{/if}} {{/if}}

View File

@ -1 +0,0 @@
{{group-post-stream posts=controller emptyText="groups.empty.mentions"}}

View File

@ -1 +0,0 @@
{{group-post-stream posts=controller emptyText="groups.empty.messages"}}

View File

@ -1 +0,0 @@
{{group-post-stream posts=controller emptyText="groups.empty.topics"}}

View File

@ -1,4 +0,0 @@
import UrlRefresh from 'discourse/mixins/url-refresh';
import ScrollTop from 'discourse/mixins/scroll-top';
export default Ember.View.extend(ScrollTop, UrlRefresh);

View File

@ -1,6 +0,0 @@
import ScrollTop from 'discourse/mixins/scroll-top';
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(ScrollTop, LoadMore, {
eyelineSelector: '.user-stream .item',
});

View File

@ -1,6 +0,0 @@
import ScrollTop from 'discourse/mixins/scroll-top';
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(ScrollTop, LoadMore, {
eyelineSelector: '.group-members tr',
});

View File

@ -1,6 +0,0 @@
import ScrollTop from 'discourse/mixins/scroll-top';
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(ScrollTop, LoadMore, {
eyelineSelector: '.user-stream .item',
});

View File

@ -1,6 +0,0 @@
import ScrollTop from 'discourse/mixins/scroll-top';
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(ScrollTop, LoadMore, {
eyelineSelector: '.user-stream .item',
});

View File

@ -1,3 +1,4 @@
import { wantsNewWindow } from 'discourse/lib/intercept-click';
export default Ember.View.extend({ export default Ember.View.extend({
templateName: 'share', templateName: 'share',
@ -95,7 +96,7 @@ export default Ember.View.extend({
$html.on('click.discoure-share-link', '[data-share-url]', function(e) { $html.on('click.discoure-share-link', '[data-share-url]', function(e) {
// if they want to open in a new tab, let it so // if they want to open in a new tab, let it so
if (e.shiftKey || e.metaKey || e.ctrlKey || e.which === 2) { return true; } if (wantsNewWindow(e)) { return true; }
e.preventDefault(); e.preventDefault();

View File

@ -1,7 +1,6 @@
import AddCategoryClass from 'discourse/mixins/add-category-class'; import AddCategoryClass from 'discourse/mixins/add-category-class';
import AddArchetypeClass from 'discourse/mixins/add-archetype-class'; import AddArchetypeClass from 'discourse/mixins/add-archetype-class';
import ClickTrack from 'discourse/lib/click-track'; import ClickTrack from 'discourse/lib/click-track';
import { listenForViewEvent } from 'discourse/lib/app-events';
import { categoryBadgeHTML } from 'discourse/helpers/category-link'; import { categoryBadgeHTML } from 'discourse/helpers/category-link';
import Scrolling from 'discourse/mixins/scrolling'; import Scrolling from 'discourse/mixins/scrolling';
@ -63,6 +62,9 @@ const TopicView = Ember.View.extend(AddCategoryClass, AddArchetypeClass, Scrolli
return ClickTrack.trackClick(e); return ClickTrack.trackClick(e);
}); });
this.appEvents.on('post:highlight', postNumber => {
Ember.run.scheduleOnce('afterRender', null, highlight, postNumber);
});
}.on('didInsertElement'), }.on('didInsertElement'),
// This view is being removed. Shut down operations // This view is being removed. Shut down operations
@ -77,6 +79,7 @@ const TopicView = Ember.View.extend(AddCategoryClass, AddArchetypeClass, Scrolli
// this happens after route exit, stuff could have trickled in // this happens after route exit, stuff could have trickled in
this.appEvents.trigger('header:hide-topic'); this.appEvents.trigger('header:hide-topic');
this.appEvents.off('post:highlight');
}.on('willDestroyElement'), }.on('willDestroyElement'),
@ -200,8 +203,4 @@ function highlight(postNumber) {
}); });
} }
listenForViewEvent(TopicView, 'post:highlight', postNumber => {
Ember.run.scheduleOnce('afterRender', null, highlight, postNumber);
});
export default TopicView; export default TopicView;

View File

@ -1,3 +1,4 @@
import { wantsNewWindow } from 'discourse/lib/intercept-click';
import { setting } from 'discourse/lib/computed'; import { setting } from 'discourse/lib/computed';
import CleansUp from 'discourse/mixins/cleans-up'; import CleansUp from 'discourse/mixins/cleans-up';
import afterTransition from 'discourse/lib/after-transition'; import afterTransition from 'discourse/lib/after-transition';
@ -57,7 +58,7 @@ export default Ember.View.extend(CleansUp, {
}; };
$('#main-outlet').on(clickDataExpand, '[data-user-card]', (e) => { $('#main-outlet').on(clickDataExpand, '[data-user-card]', (e) => {
if (e.ctrlKey || e.metaKey) { return; } if (wantsNewWindow(e)) { return; }
const $target = $(e.currentTarget), const $target = $(e.currentTarget),
username = $target.data('user-card'); username = $target.data('user-card');
@ -65,7 +66,7 @@ export default Ember.View.extend(CleansUp, {
}); });
$('#main-outlet').on(clickMention, 'a.mention', (e) => { $('#main-outlet').on(clickMention, 'a.mention', (e) => {
if (e.ctrlKey || e.metaKey) { return; } if (wantsNewWindow(e)) { return; }
const $target = $(e.target), const $target = $(e.target),
username = $target.text().replace(/^@/, ''); username = $target.text().replace(/^@/, '');

View File

@ -1,7 +1,8 @@
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
import { iconNode } from 'discourse/helpers/fa-icon'; import { iconNode } from 'discourse/helpers/fa-icon';
import interceptClick from 'discourse/lib/intercept-click'; import { wantsNewWindow } from 'discourse/lib/intercept-click';
import DiscourseURL from 'discourse/lib/url';
export default createWidget('home-logo', { export default createWidget('home-logo', {
tagName: 'div.title', tagName: 'div.title',
@ -40,5 +41,11 @@ export default createWidget('home-logo', {
return h('a', { attributes: { href: this.settings.href } }, this.logo()); return h('a', { attributes: { href: this.settings.href } }, this.logo());
}, },
click: interceptClick click(e) {
if (wantsNewWindow(e)) { return false; }
e.preventDefault();
DiscourseURL.routeTo(this.settings.href);
return false;
}
}); });

View File

@ -1,3 +1,4 @@
import { wantsNewWindow } from 'discourse/lib/intercept-click';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import { iconNode } from 'discourse/helpers/fa-icon'; import { iconNode } from 'discourse/helpers/fa-icon';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
@ -70,7 +71,7 @@ export default createWidget('link', {
}, },
click(e) { click(e) {
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey) { return; } if (wantsNewWindow(e)) { return; }
e.preventDefault(); e.preventDefault();
if (this.attrs.action) { if (this.attrs.action) {

View File

@ -1,3 +1,4 @@
import { wantsNewWindow } from 'discourse/lib/intercept-click';
import RawHtml from 'discourse/widgets/raw-html'; import RawHtml from 'discourse/widgets/raw-html';
import { createWidget } from 'discourse/widgets/widget'; import { createWidget } from 'discourse/widgets/widget';
import DiscourseURL from 'discourse/lib/url'; import DiscourseURL from 'discourse/lib/url';
@ -103,7 +104,7 @@ createWidget('notification-item', {
if (document && document.cookie) { if (document && document.cookie) {
document.cookie = `cn=${id}; expires=Fri, 31 Dec 9999 23:59:59 GMT`; document.cookie = `cn=${id}; expires=Fri, 31 Dec 9999 23:59:59 GMT`;
} }
if (e.isDefaultPrevented() || e.shiftKey || e.metaKey || e.ctrlKey || e.button !== 0) { return; } if (wantsNewWindow(e)) { return; }
e.preventDefault(); e.preventDefault();
this.sendWidgetEvent('linkClicked'); this.sendWidgetEvent('linkClicked');