| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| from formencode import validators as fev |
| |
| import ew as ew_core |
| import ew.jinja2_ew as ew |
| |
| from allura.lib import validators as V |
| from allura.lib.widgets import form_fields as ffw |
| from allura.lib.widgets import forms as ff |
| from allura import model as M |
| |
| |
| class NullValidator(fev.FancyValidator): |
| perform_validation = True |
| |
| def _to_python(self, value, state): |
| return value |
| |
| def _from_python(self, value, state): |
| return value |
| |
| # Discussion forms |
| |
| |
| class ModerateThread(ff.CsrfForm): |
| defaults = dict( |
| ew.SimpleForm.defaults, |
| submit_text=None) |
| |
| class buttons(ew_core.NameList): |
| delete = ew.SubmitButton(label='Delete Thread') |
| |
| |
| class ModeratePost(ew.SimpleForm): |
| template = 'jinja:allura:templates/widgets/moderate_post.html' |
| defaults = dict( |
| ew.SimpleForm.defaults, |
| submit_text=None) |
| |
| |
| class AttachPost(ff.ForgeForm): |
| defaults = dict( |
| ff.ForgeForm.defaults, |
| submit_text='Attach File', |
| enctype='multipart/form-data') |
| |
| @property |
| def fields(self): |
| fields = [ |
| ew.InputField(name='file_info', field_type='file', |
| label='New Attachment') |
| ] |
| return fields |
| |
| |
| class ModeratePosts(ew.SimpleForm): |
| template = 'jinja:allura:templates/widgets/moderate_posts.html' |
| defaults = dict( |
| ew.SimpleForm.defaults, |
| submit_text=None) |
| |
| def resources(self): |
| for r in super(ModeratePosts, self).resources(): |
| yield r |
| yield ew.JSScript(''' |
| (function($){ |
| var tbl = $('form table'); |
| var checkboxes = $('input[type=checkbox]', tbl); |
| $('a[href=#]', tbl).click(function () { |
| checkboxes.each(function () { |
| if(this.checked) { this.checked = false; } |
| else { this.checked = true; } |
| }); |
| return false; |
| }); |
| }(jQuery));''') |
| |
| |
| class PostFilter(ff.ForgeForm): |
| defaults = dict( |
| ew.SimpleForm.defaults, |
| submit_text=None, |
| method='GET') |
| fields = [ |
| ew.HiddenField( |
| name='page', |
| validator=fev.Int()), |
| ew.FieldSet(label='Post Filter', fields=[ |
| ew.SingleSelectField( |
| name='status', |
| label='Show posts with status', |
| options=[ |
| ew.Option(py_value='-', label='Any'), |
| ew.Option(py_value='spam', label='Spam'), |
| ew.Option(py_value='pending', |
| label='Pending moderation'), |
| ew.Option(py_value='ok', label='Ok')], |
| if_missing='pending'), |
| ew.InputField(name='username', |
| label='Show post filtered by username'), |
| ew.SubmitButton(label='Filter Posts') |
| ]) |
| ] |
| |
| |
| class TagPost(ff.ForgeForm): |
| |
| # this ickiness is to override the default submit button |
| def __call__(self, **kw): |
| result = super(TagPost, self).__call__(**kw) |
| submit_button = ffw.SubmitButton(label=result['submit_text']) |
| result['extra_fields'] = [submit_button] |
| result['buttons'] = [submit_button] |
| return result |
| |
| fields = [ffw.LabelEdit(label='Labels', name='labels', className='title')] |
| |
| def resources(self): |
| for r in ffw.LabelEdit(name='labels').resources(): |
| yield r |
| |
| |
| class EditPost(ff.ForgeForm): |
| template = 'jinja:allura:templates/widgets/edit_post.html' |
| antispam = True |
| defaults = dict( |
| ff.ForgeForm.defaults, |
| show_subject=False, |
| value=None, |
| att_name='file_info') |
| |
| @property |
| def fields(self): |
| fields = ew_core.NameList() |
| fields.append(ffw.MarkdownEdit(name='text')) |
| fields.append(ew.HiddenField(name='forum', if_missing=None)) |
| if ew_core.widget_context.widget: |
| # we are being displayed |
| if ew_core.widget_context.render_context.get('show_subject', self.show_subject): |
| fields.append( |
| ew.TextField(name='subject', attrs=dict(style="width:97%"))) |
| else: |
| # We are being validated |
| validator = fev.UnicodeString(not_empty=True, if_missing='') |
| fields.append(ew.TextField(name='subject', validator=validator)) |
| fields.append(NullValidator(name=self.att_name)) |
| return fields |
| |
| def resources(self): |
| for r in ew.TextField(name='subject').resources(): |
| yield r |
| for r in ffw.MarkdownEdit(name='text').resources(): |
| yield r |
| yield ew.JSScript('''$(document).ready(function () { |
| $("a.attachment_form_add_button").click(function(evt){ |
| $(this).hide(); |
| $(".attachment_form_fields", this.parentNode).show(); |
| evt.preventDefault(); |
| }); |
| $("a.cancel_edit_post").click(function(evt){ |
| $("textarea", this.parentNode).val($("input.original_value", this.parentNode).val()); |
| $(".attachment_form_fields input", this.parentNode).val(''); |
| evt.preventDefault(); |
| }); |
| });''') |
| |
| |
| class NewTopicPost(EditPost): |
| template = 'jinja:allura:templates/widgets/new_topic_post.html' |
| defaults = dict( |
| EditPost.defaults, |
| show_subject=True, |
| forums=None) |
| |
| |
| class _ThreadsTable(ew.TableField): |
| template = 'jinja:allura:templates/widgets/threads_table.html' |
| |
| class fields(ew_core.NameList): |
| _id = ew.HiddenField(validator=V.Ming(M.Thread)) |
| subscription = ew.Checkbox(suppress_label=True) |
| subject = ffw.DisplayOnlyField(label='Topic') |
| url = ffw.DisplayOnlyField() |
| num_replies = ffw.DisplayOnlyField(label='Posts') |
| num_views = ffw.DisplayOnlyField(label='Views') |
| last_post = ffw.DisplayOnlyField(label='Last Post') |
| |
| |
| class SubscriptionForm(ew.SimpleForm): |
| template = 'jinja:allura:templates/widgets/subscription_form.html' |
| value = None |
| threads = None |
| show_subject = False |
| allow_create_thread = False |
| limit = None |
| page = 0 |
| count = 0 |
| submit_text = 'Update Subscriptions' |
| params = ['value', 'threads', 'limit', 'page', 'count', |
| 'show_subject', 'allow_create_thread'] |
| |
| class fields(ew_core.NameList): |
| page_list = ffw.PageList() |
| page_size = ffw.PageSize() |
| threads = _ThreadsTable() |
| |
| def resources(self): |
| for r in super(SubscriptionForm, self).resources(): |
| yield r |
| yield ew.JSScript(''' |
| $(window).load(function () { |
| $('tbody').children(':even').addClass('even'); |
| });''') |
| |
| # Widgets |
| |
| |
| class HierWidget(ew_core.Widget): |
| widgets = {} |
| |
| def prepare_context(self, context): |
| response = super(HierWidget, self).prepare_context(context) |
| response['widgets'] = self.widgets |
| for w in self.widgets.values(): |
| w.parent_widget = self |
| return response |
| |
| def resources(self): |
| for w in self.widgets.itervalues(): |
| for r in w.resources(): |
| yield r |
| |
| |
| class Attachment(ew_core.Widget): |
| template = 'jinja:allura:templates/widgets/attachment.html' |
| params = ['value', 'post'] |
| value = None |
| post = None |
| |
| |
| class DiscussionHeader(HierWidget): |
| template = 'jinja:allura:templates/widgets/discussion_header.html' |
| params = ['value'] |
| value = None |
| widgets = dict( |
| edit_post=EditPost(submit_text='New Thread')) |
| |
| |
| class ThreadHeader(HierWidget): |
| template = 'jinja:allura:templates/widgets/thread_header.html' |
| defaults = dict( |
| HierWidget.defaults, |
| value=None, |
| page=None, |
| limit=None, |
| count=None, |
| show_moderate=False) |
| widgets = dict( |
| page_list=ffw.PageList(), |
| page_size=ffw.PageSize(), |
| moderate_thread=ModerateThread(), |
| tag_post=TagPost()) |
| |
| |
| class Post(HierWidget): |
| template = 'jinja:allura:templates/widgets/post_widget.html' |
| defaults = dict( |
| HierWidget.defaults, |
| value=None, |
| indent=0, |
| page=0, |
| limit=25, |
| show_subject=False, |
| ) |
| widgets = dict( |
| moderate_post=ModeratePost(), |
| edit_post=EditPost(submit_text='Post'), |
| attach_post=AttachPost(submit_text='Attach'), |
| attachment=Attachment()) |
| |
| def resources(self): |
| for r in super(Post, self).resources(): |
| yield r |
| for w in self.widgets.itervalues(): |
| for r in w.resources(): |
| yield r |
| yield ew.CSSScript(''' |
| div.moderate { |
| color:grey; |
| } |
| ''') |
| yield ew.JSLink('js/jquery.lightbox_me.js') |
| yield ew.JSScript(''' |
| (function () { |
| $('div.discussion-post').each(function () { |
| var post = this; |
| $('.submit', post).button(); |
| $('.moderate_post', post).click(function(e){ |
| e.preventDefault(); |
| var mod = $(this).text(); |
| |
| if ($(this).hasClass('delete')) mod = 'Delete'; |
| else if ($(this).hasClass('approve')) mod = 'Approve'; |
| else if ($(this).hasClass('spam')) mod = 'Spam'; |
| else if ($(this).hasClass('undo')) mod = 'Undo'; |
| |
| |
| if (mod === 'Delete' && !confirm('Really delete this post?')) { |
| return; |
| } |
| $.ajax({ |
| type: 'POST', |
| url: this.parentNode.action, |
| data: jQuery(this.parentNode).serialize(), |
| success: function() { |
| if (mod === 'Delete'){ |
| $(post).remove(); |
| } |
| else if (mod === 'Approve'){ |
| $('a.shortlink, form.moderate_spam, form.moderate_approve', post).toggle(); |
| $('div.moderate', post).removeClass('moderate'); |
| } |
| else if (mod == 'Spam'){ |
| spam_block_display($(post), 'show_spam'); |
| } |
| else if (mod == 'Undo'){ |
| spam_block_display($(post), 'hide_spam'); |
| } |
| } |
| }); |
| }); |
| |
| function spam_block_display($post, display_type) { |
| var spam_block = $post.find('.info.grid-15.spam-present'); |
| var row = $post.find('.row').eq(0); |
| |
| if (display_type == 'show_spam') { |
| spam_block.show(); |
| row.hide(); |
| } else if (display_type == 'hide_spam') { |
| spam_block.hide(); |
| row.show(); |
| } |
| } |
| |
| function get_cm($elem) { return $('.CodeMirror', $elem)[0].CodeMirror; } |
| |
| if($('a.edit_post', post)){ |
| $('a.edit_post', post).click(function (evt) { |
| evt.preventDefault(); |
| $('.display_post', post).hide(); |
| |
| // remove the options column, but have to adjust the width of the middle section which is |
| // already hard-coded |
| var $opts = $('.options:first', post); |
| var opts_width = $opts.outerWidth(true); |
| $opts.hide(); |
| var $post_middle = $('div.grid-14:first', post); |
| $post_middle.data('original-width', $post_middle.width()); |
| $post_middle.width($post_middle.width() + opts_width); |
| |
| var $edit_post_form = $('.edit_post_form', post); |
| var cm = get_cm($edit_post_form); |
| $edit_post_form.show(); |
| cm.refresh(); |
| cm.focus(); |
| }); |
| $("a.cancel_edit_post", post).click(function(evt){ |
| $('.display_post', post).show(); |
| $('.options', post).show(); |
| $('.edit_post_form', post).hide(); |
| var $post_middle = $('div.grid-14:first', post); |
| $post_middle.width($post_middle.data('original-width')); |
| }); |
| } |
| if($('.reply_post', post)){ |
| $('.reply_post', post).click(function (evt) { |
| evt.preventDefault(); |
| var $reply_post_form = $('.reply_post_form', post); |
| var cm = get_cm($reply_post_form); |
| $reply_post_form.show(); |
| cm.focus(); |
| }); |
| $('.reply_post', post).button(); |
| } |
| if($('.add_attachment', post)){ |
| $('.add_attachment', post).click(function (evt) { |
| evt.preventDefault(); |
| $('.add_attachment_form', post).show(); |
| }); |
| } |
| if($('.shortlink', post)){ |
| var popup = $('.shortlink_popup', post); |
| $('.shortlink', post).click(function(evt){ |
| evt.preventDefault(); |
| popup.lightbox_me({ |
| onLoad: function() { |
| $('input', popup).select(); |
| } |
| }); |
| }); |
| $('.close', popup).bind('click', function() { |
| popup.hide(); |
| }); |
| } |
| }); |
| |
| //lightbox_me script to create lightbox of attached images |
| $('.lightbox').click(function(e) { |
| var image_source = $(this).data("src"); |
| var image = $('#lightbox').find('img:first'); |
| image.attr("src", image_source); |
| |
| $('#lightbox').lightbox_me({ |
| centered: true |
| }); |
| |
| e.preventDefault(); |
| }); |
| }()); |
| ''') |
| |
| |
| class PostThread(ew_core.Widget): |
| template = 'jinja:allura:templates/widgets/post_thread.html' |
| defaults = dict( |
| ew_core.Widget.defaults, |
| value=None, |
| indent=0, |
| page=0, |
| limit=25, |
| show_subject=False, |
| parent=None, |
| children=None) |
| |
| |
| class Thread(HierWidget): |
| template = 'jinja:allura:templates/widgets/thread_widget.html' |
| name = 'thread' |
| defaults = dict( |
| HierWidget.defaults, |
| value=None, |
| page=None, |
| limit=50, |
| count=None, |
| show_subject=False, |
| new_post_text='+ New Comment') |
| widgets = dict( |
| page_list=ffw.PageList(), |
| thread_header=ThreadHeader(), |
| post_thread=PostThread(), |
| post=Post(), |
| edit_post=EditPost(submit_text='Submit')) |
| |
| def resources(self): |
| for r in super(Thread, self).resources(): |
| yield r |
| for w in self.widgets.itervalues(): |
| for r in w.resources(): |
| yield r |
| yield ew.JSScript(''' |
| $(document).ready(function () { |
| var thread_tag = $('a.thread_tag'); |
| var thread_spam = $('a.sidebar_thread_spam'); |
| var tag_thread_holder = $('#tag_thread_holder'); |
| var allow_moderate = $('#allow_moderate'); |
| var mod_thread_link = $('#mod_thread_link'); |
| var mod_thread_form = $('#mod_thread_form'); |
| if (mod_thread_link.length) { |
| if (mod_thread_form.length) { |
| mod_thread_link.click(function (e) { |
| mod_thread_form.show(); |
| return false; |
| }); |
| } |
| } |
| if (thread_tag.length) { |
| if (tag_thread_holder.length) { |
| var submit_button = $('input[type="submit"]', tag_thread_holder); |
| var cancel_button = $('<a href="#" class="btn link">Cancel</a>').click(function(evt){ |
| evt.preventDefault(); |
| tag_thread_holder.hide(); |
| thread_tag.removeClass('active'); |
| }); |
| submit_button.after(cancel_button); |
| thread_tag.click(function (e) { |
| tag_thread_holder.show(); |
| thread_tag.addClass('active'); |
| // focus the submit to scroll to the form, then focus the subject for them to start typing |
| submit_button.focus(); |
| $('input[type="text"]', tag_thread_holder).focus(); |
| return false; |
| }); |
| } |
| } |
| if (thread_spam.length) { |
| if (allow_moderate.length) { |
| thread_spam[0].style.display='block'; |
| } |
| } |
| }); |
| ''') |
| |
| |
| class Discussion(HierWidget): |
| template = 'jinja:allura:templates/widgets/discussion.html' |
| defaults = dict( |
| HierWidget.defaults, |
| value=None, |
| threads=None, |
| show_subject=False, |
| allow_create_thread=False) |
| widgets = dict( |
| discussion_header=DiscussionHeader(), |
| edit_post=EditPost(submit_text='New Topic'), |
| subscription_form=SubscriptionForm()) |
| |
| def resources(self): |
| for r in super(Discussion, self).resources(): |
| yield r |