diff --git a/r2/r2/controllers/multi.py b/r2/r2/controllers/multi.py index d8d24e86e..2f1775861 100644 --- a/r2/r2/controllers/multi.py +++ b/r2/r2/controllers/multi.py @@ -43,6 +43,7 @@ from r2.lib.validator import ( VModhash, VSRByName, VJSON, + VMarkdown, VMultiPath, VMultiByPath, ) @@ -130,6 +131,10 @@ class MultiApiController(RedditController, OAuth2ResourceController): multi._revert() raise RedditError('MULTI_TOO_MANY_SUBREDDITS', code=409) + if 'description_md' in data: + md = VMarkdown('description_md').run(data['description_md']) + multi.description_md = md + multi._commit() return multi diff --git a/r2/r2/lib/jsontemplates.py b/r2/r2/lib/jsontemplates.py index 2627bd869..508c5ae27 100755 --- a/r2/r2/lib/jsontemplates.py +++ b/r2/r2/lib/jsontemplates.py @@ -257,6 +257,8 @@ class LabeledMultiJsonTemplate(ThingJsonTemplate): subreddits="srs", visibility="visibility", can_edit="can_edit", + description_md="description_md", + description_html="description_html", ) del _data_attrs_["id"] @@ -273,6 +275,10 @@ class LabeledMultiJsonTemplate(ThingJsonTemplate): return self.sr_props(thing, thing.srs) elif attr == "can_edit": return c.user_is_loggedin and thing.can_edit(c.user) + elif attr == "description_html": + # if safemarkdown is passed a falsy string it returns None :/ + description_html = safemarkdown(thing.description_md) or '' + return description_html else: return ThingJsonTemplate.thing_attr(self, thing, attr) diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py index 2b4e03c93..eb02eff67 100755 --- a/r2/r2/lib/pages/pages.py +++ b/r2/r2/lib/pages/pages.py @@ -1845,6 +1845,7 @@ class MultiInfoBar(Templated): self.can_copy = c.user_is_loggedin self.can_rename = c.user_is_loggedin and multi.owner == c.user srs.sort(key=lambda sr: sr.name.lower()) + self.description_md = multi.description_md self.srs = srs @@ -3543,7 +3544,8 @@ class UserText(CachedTemplate): cloneable = False, extra_css = '', name = "text", - expunged=False): + expunged=False, + include_errors=True): css_class = "usertext" if cloneable: @@ -3567,7 +3569,8 @@ class UserText(CachedTemplate): cloneable = cloneable, css_class = css_class, name = name, - expunged=expunged) + expunged=expunged, + include_errors=include_errors) class MediaEmbedBody(CachedTemplate): """What's rendered inside the iframe that contains media objects""" diff --git a/r2/r2/models/subreddit.py b/r2/r2/models/subreddit.py index 37a7b8711..897236396 100644 --- a/r2/r2/models/subreddit.py +++ b/r2/r2/models/subreddit.py @@ -1288,6 +1288,7 @@ class LabeledMulti(tdb_cassandra.Thing, MultiReddit): _views = [] _defaults = dict(MultiReddit._defaults, visibility='private', + description_md='', ) _extra_schema_creation_args = { "key_validation_class": tdb_cassandra.UTF8_TYPE, diff --git a/r2/r2/public/static/css/reddit.less b/r2/r2/public/static/css/reddit.less index fd10cf625..33ee6e329 100755 --- a/r2/r2/public/static/css/reddit.less +++ b/r2/r2/public/static/css/reddit.less @@ -5198,6 +5198,16 @@ table.calendar { } } + .description { + margin: .75em 0; + + .usertext-edit, textarea { + // use !important to override legacy inline style width set by + // show_edit_usertext() + width: 294px !important; + } + } + ul, form.add-sr { margin-left: 12px; } diff --git a/r2/r2/public/static/js/multi.js b/r2/r2/public/static/js/multi.js index e14a23318..310af481f 100644 --- a/r2/r2/public/static/js/multi.js +++ b/r2/r2/public/static/js/multi.js @@ -237,6 +237,8 @@ r.multi.MultiDetails = Backbone.View.extend({ 'change [name="visibility"]': 'setVisibility', 'click .show-copy': 'showCopyMulti', 'click .show-rename': 'showRenameMulti', + 'click .edit-description': 'editDescription', + 'submit .description': 'saveDescription', 'confirm .delete': 'deleteMulti' }, @@ -279,6 +281,10 @@ r.multi.MultiDetails = Backbone.View.extend({ this.$el.toggleClass('readonly', !canEdit) + this.$('.description .usertext-body').html( + _.unescape(this.model.get('description_html')) + ) + this.$('.count').text(this.model.subreddits.length) return this @@ -388,6 +394,21 @@ r.multi.MultiDetails = Backbone.View.extend({ }) }, + editDescription: function() { + show_edit_usertext(this.$el) + }, + + saveDescription: function(ev) { + ev.preventDefault() + this.model.save({ + 'description_md': this.$('.description textarea').val() + }, { + success: _.bind(function() { + hide_edit_usertext(this.$el) + }, this) + }) + }, + focusAdd: function() { this.$('.add-sr .sr-name').focus() } diff --git a/r2/r2/templates/multiinfobar.html b/r2/r2/templates/multiinfobar.html index 0073474f5..ec7251314 100644 --- a/r2/r2/templates/multiinfobar.html +++ b/r2/r2/templates/multiinfobar.html @@ -22,7 +22,7 @@ <%! from r2.lib.strings import strings, Score - from r2.lib.pages import WrappedUser, ModList + from r2.lib.pages import WrappedUser, ModList, UserText %> <%namespace file="utils.html" import="plain_link, thing_timestamp, text_with_links"/> @@ -70,6 +70,15 @@ %endif +
+ ${UserText(None, text=thing.description_md, post_form=None, editable=True, include_errors=False)} + %if thing.can_edit: +
+ +
+ %endif +
+

${unsafe(_('%(count)s subreddits in this multi:') % dict(count='%d ' % len(thing.srs)))}