mirror of
https://github.com/discourse/discourse.git
synced 2025-05-28 01:56:58 +08:00
Update Polls plugin to work with new Plugin API
This commit is contained in:
@ -2,6 +2,12 @@ import { diff, patch } from 'virtual-dom';
|
|||||||
import { WidgetClickHook } from 'discourse/widgets/click-hook';
|
import { WidgetClickHook } from 'discourse/widgets/click-hook';
|
||||||
import { renderedKey } from 'discourse/widgets/widget';
|
import { renderedKey } from 'discourse/widgets/widget';
|
||||||
|
|
||||||
|
const _cleanCallbacks = {};
|
||||||
|
export function addWidgetCleanCallback(widgetName, fn) {
|
||||||
|
_cleanCallbacks[widgetName] = _cleanCallbacks[widgetName] || [];
|
||||||
|
_cleanCallbacks[widgetName].push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
_tree: null,
|
_tree: null,
|
||||||
_rootNode: null,
|
_rootNode: null,
|
||||||
@ -22,6 +28,13 @@ export default Ember.Component.extend({
|
|||||||
this._timeout = Ember.run.scheduleOnce('render', this, this.rerenderWidget);
|
this._timeout = Ember.run.scheduleOnce('render', this, this.rerenderWidget);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
willClearRender() {
|
||||||
|
const callbacks = _cleanCallbacks[this.get('widget')];
|
||||||
|
if (callbacks) {
|
||||||
|
callbacks.forEach(cb => cb());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
Ember.run.cancel(this._timeout);
|
Ember.run.cancel(this._timeout);
|
||||||
},
|
},
|
||||||
|
@ -4,6 +4,7 @@ import { addPosterIcon } from 'discourse/widgets/poster-name';
|
|||||||
import { addButton } from 'discourse/widgets/post-menu';
|
import { addButton } from 'discourse/widgets/post-menu';
|
||||||
import { includeAttributes } from 'discourse/lib/transform-post';
|
import { includeAttributes } from 'discourse/lib/transform-post';
|
||||||
import { addToolbarCallback } from 'discourse/components/d-editor';
|
import { addToolbarCallback } from 'discourse/components/d-editor';
|
||||||
|
import { addWidgetCleanCallback } from 'discourse/components/mount-widget';
|
||||||
|
|
||||||
let _decorateId = 0;
|
let _decorateId = 0;
|
||||||
function decorate(klass, evt, cb) {
|
function decorate(klass, evt, cb) {
|
||||||
@ -29,23 +30,31 @@ class PluginApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decorateCooked(callback)
|
* decorateCooked(callback, options)
|
||||||
*
|
*
|
||||||
* Used for decorating the `cooked` content of a post after it is rendered using
|
* Used for decorating the `cooked` content of a post after it is rendered using
|
||||||
* jQuery.
|
* jQuery.
|
||||||
*
|
*
|
||||||
* `callback` will be called when it is time to decorate with a jQuery selector.
|
* `callback` will be called when it is time to decorate with a jQuery selector.
|
||||||
*
|
*
|
||||||
|
* Use `options.onlyStream` if you only want to decorate posts within a topic,
|
||||||
|
* and not in other places like the user stream.
|
||||||
|
*
|
||||||
* For example, to add a yellow background to all posts you could do this:
|
* For example, to add a yellow background to all posts you could do this:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* api.decorateCooked($elem => $elem.css({ backgroundColor: 'yellow' }));
|
* api.decorateCooked($elem => $elem.css({ backgroundColor: 'yellow' }));
|
||||||
* ```
|
* ```
|
||||||
**/
|
**/
|
||||||
decorateCooked(cb) {
|
decorateCooked(callback, opts) {
|
||||||
addDecorator(cb);
|
opts = opts || {};
|
||||||
decorate(ComposerEditor, 'previewRefreshed', cb);
|
|
||||||
decorate(this.container.lookupFactory('view:user-stream'), 'didInsertElement', cb);
|
addDecorator(callback);
|
||||||
|
|
||||||
|
if (!opts.onlyStream) {
|
||||||
|
decorate(ComposerEditor, 'previewRefreshed', callback);
|
||||||
|
decorate(this.container.lookupFactory('view:user-stream'), 'didInsertElement', callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,6 +100,10 @@ class PluginApi {
|
|||||||
addToolbarCallback(callback);
|
addToolbarCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanupStream(fn) {
|
||||||
|
addWidgetCleanCallback('post-stream', fn);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _pluginv01;
|
let _pluginv01;
|
||||||
|
@ -10,10 +10,11 @@ export function addDecorator(cb) {
|
|||||||
|
|
||||||
export default class PostCooked {
|
export default class PostCooked {
|
||||||
|
|
||||||
constructor(attrs) {
|
constructor(attrs, getModel) {
|
||||||
this.attrs = attrs;
|
this.attrs = attrs;
|
||||||
this.expanding = false;
|
this.expanding = false;
|
||||||
this._highlighted = false;
|
this._highlighted = false;
|
||||||
|
this.getModel = getModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(prev) {
|
update(prev) {
|
||||||
@ -29,7 +30,7 @@ export default class PostCooked {
|
|||||||
this._fixImageSizes($html);
|
this._fixImageSizes($html);
|
||||||
this._applySearchHighlight($html);
|
this._applySearchHighlight($html);
|
||||||
|
|
||||||
_decorators.forEach(cb => cb($html));
|
_decorators.forEach(cb => cb($html, this.getModel));
|
||||||
return $html[0];
|
return $html[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +221,17 @@ createWidget('expand-post-button', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class DecoratorHelper {
|
||||||
|
constructor(widget) {
|
||||||
|
this.container = widget.container;
|
||||||
|
this._widget = widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
getModel() {
|
||||||
|
return this._widget.findAncestorModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createWidget('post-contents', {
|
createWidget('post-contents', {
|
||||||
buildKey: attrs => `post-contents-${attrs.id}`,
|
buildKey: attrs => `post-contents-${attrs.id}`,
|
||||||
|
|
||||||
@ -240,7 +251,7 @@ createWidget('post-contents', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
html(attrs, state) {
|
html(attrs, state) {
|
||||||
const result = [new PostCooked(attrs)];
|
const result = [new PostCooked(attrs, new DecoratorHelper(this))];
|
||||||
|
|
||||||
if (attrs.cooked_hidden) {
|
if (attrs.cooked_hidden) {
|
||||||
result.push(this.attach('expand-hidden', attrs));
|
result.push(this.attach('expand-hidden', attrs));
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import PostView from "discourse/views/post";
|
import { withPluginApi } from 'discourse/lib/plugin-api';
|
||||||
import TopicController from "discourse/controllers/topic";
|
|
||||||
import Post from "discourse/models/post";
|
|
||||||
|
|
||||||
import { on } from "ember-addons/ember-computed-decorators";
|
|
||||||
|
|
||||||
function createPollView(container, post, poll, vote) {
|
function createPollView(container, post, poll, vote) {
|
||||||
const controller = container.lookup("controller:poll", { singleton: false }),
|
const controller = container.lookup("controller:poll", { singleton: false });
|
||||||
view = container.lookup("view:poll");
|
const view = container.lookup("view:poll");
|
||||||
|
|
||||||
controller.set("vote", vote);
|
controller.set("vote", vote);
|
||||||
controller.setProperties({ model: poll, post });
|
controller.setProperties({ model: poll, post });
|
||||||
@ -15,12 +11,32 @@ function createPollView(container, post, poll, vote) {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
let _pollViews;
|
||||||
name: "extend-for-poll",
|
|
||||||
|
|
||||||
initialize(container) {
|
function initializePolls(api) {
|
||||||
|
|
||||||
|
const TopicController = api.container.lookupFactory('controller:topic');
|
||||||
|
TopicController.reopen({
|
||||||
|
subscribe(){
|
||||||
|
this._super();
|
||||||
|
this.messageBus.subscribe("/polls/" + this.get("model.id"), msg => {
|
||||||
|
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
|
||||||
|
if (post) {
|
||||||
|
post.set('polls', msg.polls);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
unsubscribe(){
|
||||||
|
this.messageBus.unsubscribe('/polls/*');
|
||||||
|
this._super();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Post = api.container.lookupFactory('model:post');
|
||||||
Post.reopen({
|
Post.reopen({
|
||||||
|
_polls: null,
|
||||||
|
pollsObject: null,
|
||||||
|
|
||||||
// we need a proper ember object so it is bindable
|
// we need a proper ember object so it is bindable
|
||||||
pollsChanged: function(){
|
pollsChanged: function(){
|
||||||
const polls = this.get("polls");
|
const polls = this.get("polls");
|
||||||
@ -39,64 +55,51 @@ export default {
|
|||||||
}.observes("polls")
|
}.observes("polls")
|
||||||
});
|
});
|
||||||
|
|
||||||
TopicController.reopen({
|
function cleanUpPollViews() {
|
||||||
subscribe(){
|
if (_pollViews) {
|
||||||
this._super();
|
Object.keys(_pollViews).forEach(pollName => _pollViews[pollName].destroy());
|
||||||
this.messageBus.subscribe("/polls/" + this.get("model.id"), msg => {
|
|
||||||
const post = this.get('model.postStream').findLoadedPost(msg.post_id);
|
|
||||||
if (post) {
|
|
||||||
post.set('polls', msg.polls);
|
|
||||||
}
|
}
|
||||||
});
|
_pollViews = null;
|
||||||
},
|
|
||||||
unsubscribe(){
|
|
||||||
this.messageBus.unsubscribe('/polls/*');
|
|
||||||
this._super();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// overwrite polls
|
function createPollViews($elem, helper) {
|
||||||
PostView.reopen({
|
const $polls = $('.poll', $elem);
|
||||||
|
if (!$polls.length) { return; }
|
||||||
|
|
||||||
@on("postViewInserted", "postViewUpdated")
|
const post = helper.getModel();
|
||||||
_createPollViews($post) {
|
const votes = post.get('polls_votes') || {};
|
||||||
const post = this.get("post"),
|
|
||||||
votes = post.get("polls_votes") || {};
|
|
||||||
|
|
||||||
post.pollsChanged();
|
post.pollsChanged();
|
||||||
const polls = post.get("pollsObject");
|
|
||||||
|
|
||||||
// don't even bother when there's no poll
|
const polls = post.get("pollsObject");
|
||||||
if (!polls) { return; }
|
if (!polls) { return; }
|
||||||
|
|
||||||
// TODO inject cleanly into
|
cleanUpPollViews();
|
||||||
|
const postPollViews = {};
|
||||||
|
|
||||||
// clean-up if needed
|
$polls.each((idx, pollElem) => {
|
||||||
this._cleanUpPollViews();
|
const $div = $("<div>");
|
||||||
|
const $poll = $(pollElem);
|
||||||
|
|
||||||
const pollViews = {};
|
const pollName = $poll.data("poll-name");
|
||||||
|
const pollView = createPollView(helper.container, post, polls[pollName], votes[pollName]);
|
||||||
// iterate over all polls
|
|
||||||
$(".poll", $post).each(function() {
|
|
||||||
const $div = $("<div>"),
|
|
||||||
$poll = $(this),
|
|
||||||
pollName = $poll.data("poll-name"),
|
|
||||||
pollView = createPollView(container, post, polls[pollName], votes[pollName]);
|
|
||||||
|
|
||||||
$poll.replaceWith($div);
|
$poll.replaceWith($div);
|
||||||
Em.run.next(() => pollView.renderer.replaceIn(pollView, $div[0]));
|
Em.run.next(() => pollView.renderer.replaceIn(pollView, $div[0]));
|
||||||
pollViews[pollName] = pollView;
|
postPollViews[pollName] = pollView;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.set("pollViews", pollViews);
|
_pollViews = postPollViews;
|
||||||
},
|
}
|
||||||
|
|
||||||
@on("willClearRender")
|
api.decorateCooked(createPollViews, { onlyStream: true });
|
||||||
_cleanUpPollViews() {
|
api.cleanupStream(cleanUpPollViews);
|
||||||
if (this.get("pollViews")) {
|
|
||||||
_.forEach(this.get("pollViews"), v => v.destroy());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
export default {
|
||||||
|
name: "extend-for-poll",
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
withPluginApi('0.1', initializePolls);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user