From ccb49a71209eae6592d99f6d0ebe1c93e9e4c0d7 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Sun, 8 Feb 2015 15:56:44 +1030 Subject: [PATCH] Make post types/components more flexible --- .../components/discussions/post-comment.js | 149 ++++++++++++++++++ .../discussions/post-content-comment.js | 8 - .../components/discussions/post-wrapper.js | 62 -------- .../app/components/ui/controls/item-list.js | 2 +- .../core/ember/app/models/post-stream.js | 12 +- .../components/discussions/post-comment.hbs | 24 +++ .../discussions/post-content-comment.hbs | 23 --- ...{post-content-title.hbs => post-title.hbs} | 0 .../components/discussions/post-wrapper.hbs | 8 - .../components/discussions/stream-content.hbs | 4 +- .../components/ui/controls/item-list.hbs | 4 +- framework/core/src/Flarum/Core/Posts/Post.php | 15 ++ 12 files changed, 203 insertions(+), 108 deletions(-) create mode 100644 framework/core/ember/app/components/discussions/post-comment.js delete mode 100644 framework/core/ember/app/components/discussions/post-content-comment.js delete mode 100644 framework/core/ember/app/components/discussions/post-wrapper.js create mode 100644 framework/core/ember/app/templates/components/discussions/post-comment.hbs delete mode 100644 framework/core/ember/app/templates/components/discussions/post-content-comment.hbs rename framework/core/ember/app/templates/components/discussions/{post-content-title.hbs => post-title.hbs} (100%) delete mode 100644 framework/core/ember/app/templates/components/discussions/post-wrapper.hbs diff --git a/framework/core/ember/app/components/discussions/post-comment.js b/framework/core/ember/app/components/discussions/post-comment.js new file mode 100644 index 000000000..b6f0b3c7f --- /dev/null +++ b/framework/core/ember/app/components/discussions/post-comment.js @@ -0,0 +1,149 @@ +import Ember from 'ember'; + +import TaggedArray from '../../utils/tagged-array'; +import ActionButton from '../ui/controls/action-button'; +import ComposerEdit from '../discussions/composer-edit'; +import AlertMessage from '../alert-message'; +import humanTime from '../../utils/human-time'; + +var precompileTemplate = Ember.Handlebars.compile; + +// @todo extend a base post class +export default Ember.Component.extend({ + tagName: 'article', + layoutName: 'components/discussions/post-comment', + + editDescription: function() { + return 'Edited by '+this.get('post.editUser.username')+' '+humanTime(this.get('post.editTime')); + }.property('post.editTime', 'post.editUser'), + + post: Ember.computed.alias('content'), + + classNames: ['post'], + classNameBindings: ['post.deleted', 'post.edited'], + + didInsertElement: function() { + var $this = this.$(); + $this.css({opacity: 0}); + + setTimeout(function() { + $this.animate({opacity: 1}, 'fast'); + }, 100); + + this.set('controls', TaggedArray.create()); + this.trigger('populateControls', this.get('controls')); + + this.set('header', TaggedArray.create()); + this.trigger('populateHeader', this.get('header')); + }, + + populateControlsDefault: function(controls) { + if (this.get('post.deleted')) { + this.addControl('restore', 'Restore', 'reply', 'canEdit'); + this.addControl('delete', 'Delete', 'times', 'canDelete'); + } else { + this.addControl('edit', 'Edit', 'pencil', 'canEdit'); + this.addControl('hide', 'Delete', 'times', 'canEdit'); + } + }.on('populateControls'), + + populateHeaderDefault: function(header) { + header.pushObjectWithTag(Ember.Component.create({ + tagName: 'h3', + classNames: ['user'], + layout: precompileTemplate('{{#link-to "user" post.user}}{{user-avatar post.user}} {{post.user.username}}{{/link-to}}'), + post: this.get('post') + })); + + header.pushObjectWithTag(Ember.Component.create({ + tagName: 'li', + layout: precompileTemplate('{{#link-to "discussion" post.discussion (query-params start=post.number) class="time"}}{{human-time post.time}}{{/link-to}}'), + post: this.get('post') + })); + + header.pushObjectWithTag(Ember.Component.extend({ + tagName: 'li', + hideItem: Ember.computed.not('parent.post.isEdited'), + layout: precompileTemplate('{{fa-icon "pencil"}}'), + parent: this, + didInsertElement: function() { + this.$('.post-edited').tooltip(); + }, + updateTooltip: function() { + Ember.run.scheduleOnce('afterRender', this, function() { + this.$('.post-edited').tooltip('fixTitle'); + }); + }.observes('parent.editDescription') + }).create()); + }.on('populateHeader'), + + addControl: function(tag, label, icon, permissionAttribute) { + if (permissionAttribute && !this.get('post').get(permissionAttribute)) { + return; + } + + var self = this; + var action = function() { + self.get('controller').send(tag); + }; + + var item = ActionButton.create({label: label, icon: icon, action: action}); + this.get('controls').pushObjectWithTag(item, tag); + }, + + savePost: function(post, data) { + var controller = this; + var composer = this.get('composer'); + + composer.set('content.loading', true); + this.get('alerts').send('clearAlerts'); + + post.set('content', data.content); + + return post.save().then(function(post) { + composer.send('hide'); + }, + function(reason) { + var errors = reason.errors; + for (var i in reason.errors) { + var message = AlertMessage.create({ + type: 'warning', + message: reason.errors[i] + }); + controller.get('alerts').send('alert', message); + } + }) + .finally(function() { + composer.set('content.loading', false); + }); + }, + + actions: { + renderControls: function() { + this.set('renderControls', this.get('controls')); + // if (!this.get('controls.length')) { + // this.get('controls').pushObject(Ember.Component.create({tagName: 'li', classNames: ['dropdown-header'], layout: Ember.Handlebars.compile('No actions available')})); + // } + }, + + edit: function() { + var component = this; + var post = this.get('post'); + var composer = this.get('composer'); + + // If the composer is already set up for this post, then we + // don't need to change its content - we can just show it. + if (!(composer.get('content') instanceof ComposerEdit) || composer.get('content.post') !== post) { + composer.switchContent(ComposerEdit.create({ + user: post.get('user'), + post: post, + submit: function(data) { + component.savePost(post, data); + } + })); + } + + composer.send('show'); + } + } +}); diff --git a/framework/core/ember/app/components/discussions/post-content-comment.js b/framework/core/ember/app/components/discussions/post-content-comment.js deleted file mode 100644 index 7ed7d64b6..000000000 --- a/framework/core/ember/app/components/discussions/post-content-comment.js +++ /dev/null @@ -1,8 +0,0 @@ -import Ember from 'ember'; - -export default Ember.Component.extend({ - tagName: 'article', - layoutName: 'components/discussions/post-content-comment', - - editDescription: '' -}); diff --git a/framework/core/ember/app/components/discussions/post-wrapper.js b/framework/core/ember/app/components/discussions/post-wrapper.js deleted file mode 100644 index fb8e3cde7..000000000 --- a/framework/core/ember/app/components/discussions/post-wrapper.js +++ /dev/null @@ -1,62 +0,0 @@ -import Ember from 'ember'; - -// import TaggedArray from '../../utils/tagged-array'; -// import ActionButton from '../ui/controls/action-button'; - -export default Ember.Component.extend({ - tagName: 'article', - layoutName: 'components/discussions/post-wrapper', - - // controls: null, - - post: Ember.computed.alias('content'), - - contentComponent: function() { - return 'discussions/post-content-'+this.get('post.type'); - }.property('post.type'), - - classNames: ['post'], - classNameBindings: ['post.deleted', 'post.edited'], - - // construct: function() { - // // this.set('controls', Menu.create()); - - // // var post = this.get('post'); - - // // if (post.get('deleted')) { - // // this.addControl('restore', 'Restore', 'reply', 'canEdit'); - // // this.addControl('delete', 'Delete', 'times', 'canDelete'); - // // } else { - // // if (post.get('type') == 'comment') { - // // this.addControl('edit', 'Edit', 'pencil', 'canEdit'); - // // this.addControl('hide', 'Delete', 'times', 'canEdit'); - // // } else { - // // this.addControl('delete', 'Delete', 'times', 'canDelete'); - // // } - // // } - // }.on('init'), - - didInsertElement: function() { - var $this = this.$(); - $this.css({opacity: 0}); - - setTimeout(function() { - $this.animate({opacity: 1}, 'fast'); - }, 100); - }, - - // addControl: function(tag, title, icon, permissionAttribute) { - // if (permissionAttribute && ! this.get('post').get(permissionAttribute)) { - // return; - // } - - // var self = this; - // var action = function(post) { - // self.get('controller').send(actionName, post); - // }; - - // var item = MenuItem.extend({title: title, icon: icon, action: action}); - // this.get('controls').addItem(tag, item); - // } - -}); diff --git a/framework/core/ember/app/components/ui/controls/item-list.js b/framework/core/ember/app/components/ui/controls/item-list.js index 367d3de7b..e50f9fbc4 100644 --- a/framework/core/ember/app/components/ui/controls/item-list.js +++ b/framework/core/ember/app/components/ui/controls/item-list.js @@ -12,7 +12,7 @@ export default Ember.Component.extend({ } var listItems = []; this.get('items').forEach(function(item) { - if (item.tagName !== 'li') { + if (item.get('tagName') !== 'li') { item = ComponentItem.extend({component: item}); } listItems.push(item); diff --git a/framework/core/ember/app/models/post-stream.js b/framework/core/ember/app/models/post-stream.js index 7c7233072..4478c507d 100644 --- a/framework/core/ember/app/models/post-stream.js +++ b/framework/core/ember/app/models/post-stream.js @@ -168,11 +168,17 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, makeItem: function(indexStart, indexEnd, post) { - return Ember.Object.create({ + var item = Ember.Object.create({ indexStart: indexStart, - indexEnd: indexEnd, - content: post + indexEnd: indexEnd }); + if (post) { + item.setProperties({ + content: post, + component: 'discussions/post-'+post.get('type') + }); + } + return item; }, findNearestTo: function(index, property) { diff --git a/framework/core/ember/app/templates/components/discussions/post-comment.hbs b/framework/core/ember/app/templates/components/discussions/post-comment.hbs new file mode 100644 index 000000000..e5492ff40 --- /dev/null +++ b/framework/core/ember/app/templates/components/discussions/post-comment.hbs @@ -0,0 +1,24 @@ +{{#if controls}} + {{ui/controls/dropdown-button + items=renderControls + class="contextual-controls" + buttonClass="btn btn-default btn-icon btn-sm btn-naked" + buttonClick="renderControls" + menuClass="pull-right"}} +{{/if}} + +{{#if post.isDeleted}} + {{fa-icon "trash-o" class="post-icon"}} +{{/if}} + +
+ {{ui/controls/item-list items=header}} +
+ +
+ {{{post.contentHtml}}} +
+ + diff --git a/framework/core/ember/app/templates/components/discussions/post-content-comment.hbs b/framework/core/ember/app/templates/components/discussions/post-content-comment.hbs deleted file mode 100644 index 5d9f5f9a4..000000000 --- a/framework/core/ember/app/templates/components/discussions/post-content-comment.hbs +++ /dev/null @@ -1,23 +0,0 @@ -{{#if post.deleteTime}} - {{fa-icon "trash-o" class="post-icon"}} -{{/if}} - -
-

- {{#link-to "user" post.user}}{{user-avatar post.user}} {{post.user.username}}{{/link-to}} -

- {{#link-to "discussion" post.discussion (query-params start=post.number) class="time"}} - {{human-time post.time}} - {{/link-to}} - {{#if post.editTime}} - {{fa-icon "pencil"}} - {{/if}} -
- -
- {{{post.contentHtml}}} -
- - diff --git a/framework/core/ember/app/templates/components/discussions/post-content-title.hbs b/framework/core/ember/app/templates/components/discussions/post-title.hbs similarity index 100% rename from framework/core/ember/app/templates/components/discussions/post-content-title.hbs rename to framework/core/ember/app/templates/components/discussions/post-title.hbs diff --git a/framework/core/ember/app/templates/components/discussions/post-wrapper.hbs b/framework/core/ember/app/templates/components/discussions/post-wrapper.hbs deleted file mode 100644 index 499d54c2a..000000000 --- a/framework/core/ember/app/templates/components/discussions/post-wrapper.hbs +++ /dev/null @@ -1,8 +0,0 @@ -{{ui/controls/dropdown-button - items=controls - class="contextual-controls" - buttonClass="btn btn-default btn-icon btn-sm btn-naked" - buttonClick="populateControls" - menuClass="pull-right"}} - -{{dynamic-component type=contentComponent post=post}} diff --git a/framework/core/ember/app/templates/components/discussions/stream-content.hbs b/framework/core/ember/app/templates/components/discussions/stream-content.hbs index 65e9cebbf..3f3b36399 100644 --- a/framework/core/ember/app/templates/components/discussions/stream-content.hbs +++ b/framework/core/ember/app/templates/components/discussions/stream-content.hbs @@ -1,7 +1,7 @@ {{#each item in stream}} {{#discussions/stream-item item=item stream=stream loadRange="loadRange"}} {{#if item.content}} - {{dynamic-component type=component content=item.content}} + {{dynamic-component type=item.component content=item.content}} {{/if}} {{/discussions/stream-item}} -{{/each}} \ No newline at end of file +{{/each}} diff --git a/framework/core/ember/app/templates/components/ui/controls/item-list.hbs b/framework/core/ember/app/templates/components/ui/controls/item-list.hbs index 1d60ed182..572c5764c 100644 --- a/framework/core/ember/app/templates/components/ui/controls/item-list.hbs +++ b/framework/core/ember/app/templates/components/ui/controls/item-list.hbs @@ -1,3 +1,5 @@ {{#each item in listItems}} - {{view item}} + {{#unless item.hideItem}} + {{view item}} + {{/unless}} {{/each}} diff --git a/framework/core/src/Flarum/Core/Posts/Post.php b/framework/core/src/Flarum/Core/Posts/Post.php index 7c82c9398..03256897b 100755 --- a/framework/core/src/Flarum/Core/Posts/Post.php +++ b/framework/core/src/Flarum/Core/Posts/Post.php @@ -110,4 +110,19 @@ class Post extends Entity throw new PermissionDeniedException; } } + + public function newFromBuilder($attributes = []) + { + if (!empty($attributes->type)) { + $class = 'Flarum\Core\Posts\\'.ucfirst($attributes->type).'Post'; + if (class_exists($class)) { + $instance = new $class; + $instance->exists = true; + $instance->setRawAttributes((array) $attributes, true); + return $instance; + } + } + + return parent::newFromBuilder($attributes); + } }