summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-08-20 10:54:41 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-08-20 10:54:41 -0400
commitb52e72b5c74c4c672cf8e81cf83f8c281bd765c2 (patch)
tree1d2bed4cce9c4c7156f51ffb2741da17afe5ad5c
parent8b41842bfc6461a8b2f9b6bc9d80a3a82d54e81d (diff)
downloadaskbot-b52e72b5c74c4c672cf8e81cf83f8c281bd765c2.tar.gz
askbot-b52e72b5c74c4c672cf8e81cf83f8c281bd765c2.tar.bz2
askbot-b52e72b5c74c4c672cf8e81cf83f8c281bd765c2.zip
popups for shared with users and groups lists
-rw-r--r--askbot/management/commands/askbot_add_test_content.py2
-rw-r--r--askbot/skins/common/media/js/post.js74
-rw-r--r--askbot/skins/common/media/js/utils.js126
-rw-r--r--askbot/skins/default/templates/question.html1
-rw-r--r--askbot/skins/default/templates/question/javascript.html1
-rw-r--r--askbot/skins/default/templates/widgets/groups_list.html4
-rw-r--r--askbot/skins/default/templates/widgets/user_list.html8
-rw-r--r--askbot/skins/loaders.py12
-rw-r--r--askbot/views/commands.py33
-rw-r--r--askbot/views/readers.py4
10 files changed, 250 insertions, 15 deletions
diff --git a/askbot/management/commands/askbot_add_test_content.py b/askbot/management/commands/askbot_add_test_content.py
index ace629d0..17d3ffd0 100644
--- a/askbot/management/commands/askbot_add_test_content.py
+++ b/askbot/management/commands/askbot_add_test_content.py
@@ -14,7 +14,7 @@ NUM_COMMENTS = 20
# karma. This can be calculated dynamically - max of MIN_REP_TO_... settings
INITIAL_REPUTATION = 500
-BAD_STUFF = "<script>alert('hohoho')</script>"
+BAD_STUFF = ''#"<script>alert('hohoho')</script>"
# Defining template inputs.
USERNAME_TEMPLATE = BAD_STUFF + "test_user_%s"
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
index 5f2484ee..cafc6840 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -207,6 +207,65 @@ var CPValidator = function(){
/**
* @constructor
*/
+var ThreadUsersDialog = function() {
+ SimpleControl.call(this);
+ this._heading_text = 'Add heading with the setHeadingText()';
+};
+inherits(ThreadUsersDialog, SimpleControl);
+
+ThreadUsersDialog.prototype.setHeadingText = function(text) {
+ this._heading_text = text;
+};
+
+ThreadUsersDialog.prototype.showUsers = function(html) {
+ this._dialog.setContent(html);
+ this._dialog.show();
+};
+
+ThreadUsersDialog.prototype.startShowingUsers = function() {
+ var me = this;
+ var threadId = this._threadId;
+ var url = this._url;
+ $.ajax({
+ type: 'GET',
+ data: {'thread_id': threadId},
+ dataType: 'json',
+ url: url,
+ cache: false,
+ success: function(data){
+ if (data['success'] == true){
+ me.showUsers(data['html']);
+ } else {
+ showMessage(me.getElement(), data['message'], 'after');
+ }
+ }
+ });
+};
+
+ThreadUsersDialog.prototype.decorate = function(element) {
+ this._element = element;
+ ThreadUsersDialog.superClass_.decorate.call(this, element);
+ this._threadId = element.data('threadId');
+ this._url = element.data('url');
+ var dialog = new ModalDialog();
+ dialog.setRejectButtonText('');
+ dialog.setAcceptButtonText(gettext('Back to the question'));
+ dialog.setHeadingText(this._heading_text);
+ dialog.setAcceptHandler(function(){ dialog.hide(); });
+ var dialog_element = dialog.getElement();
+ $(dialog_element).find('.modal-footer').css('text-align', 'center');
+ $(document).append(dialog_element);
+ this._dialog = dialog;
+ var me = this;
+ this.setHandler(function(){
+ me.startShowingUsers();
+ });
+};
+
+
+/**
+ * @constructor
+ */
var DraftPost = function() {
WrappedElement.call(this);
};
@@ -249,7 +308,7 @@ DraftPost.prototype.getSaveHandler = function() {
return function(save_synchronously) {
if (me.shouldSave()) {
$.ajax({
- type: 'POST',
+ type: 'GET',
cache: false,
dataType: 'json',
async: save_synchronously ? false : true,
@@ -3867,6 +3926,19 @@ $(document).ready(function() {
});
usersAc.decorate(usersInput);
}
+
+ var showSharedUsers = $('.see-related-users');
+ if (showSharedUsers.length) {
+ var usersPopup = new ThreadUsersDialog();
+ usersPopup.setHeadingText(gettext('Shared with the following users:'));
+ usersPopup.decorate(showSharedUsers);
+ }
+ var showSharedGroups = $('.see-related-groups');
+ if (showSharedGroups.length) {
+ var groupsPopup = new ThreadUsersDialog();
+ groupsPopup.setHeadingText(gettext('Shared with the following groups:'));
+ groupsPopup.decorate(showSharedGroups);
+ }
});
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
index 01239304..b8a716ec 100644
--- a/askbot/skins/common/media/js/utils.js
+++ b/askbot/skins/common/media/js/utils.js
@@ -569,6 +569,132 @@ DeleteIcon.prototype.setContent = function(content){
}
/**
+ * @contstructor
+ * Simple modal dialog with Ok/Cancel buttons by default
+ */
+var ModalDialog = function() {
+ WrappedElement.call(this);
+ this._accept_button_text = gettext('Ok');
+ this._reject_button_text = gettext('Cancel');
+ this._heading_text = 'Add heading by setHeadingText()';
+ this._initial_content = undefined;
+ this._accept_handler = function(){};
+ var me = this;
+ this._reject_handler = function() { me.hide(); };
+ this._content_element = undefined;
+};
+inherits(ModalDialog, WrappedElement);
+
+ModalDialog.prototype.show = function() {
+ this._element.modal('show');
+};
+
+ModalDialog.prototype.hide = function() {
+ this._element.modal('hide');
+};
+
+ModalDialog.prototype.setContent = function(content) {
+ this._initial_content = content;
+ if (this._content_element) {
+ this._content_element.html(content);
+ }
+};
+
+ModalDialog.prototype.prependContent = function(content) {
+ this._content_element.prepend(content);
+};
+
+ModalDialog.prototype.setHeadingText = function(text) {
+ this._heading_text = text;
+};
+
+ModalDialog.prototype.setAcceptButtonText = function(text) {
+ this._accept_button_text = text;
+};
+
+ModalDialog.prototype.setRejectButtonText = function(text) {
+ this._reject_button_text = text;
+};
+
+ModalDialog.prototype.setAcceptHandler = function(handler) {
+ this._accept_handler = handler;
+};
+
+ModalDialog.prototype.setRejectHandler = function(handler) {
+ this._reject_handler = handler;
+};
+
+ModalDialog.prototype.clearMessages = function() {
+ this._element.find('.alert').remove();
+};
+
+ModalDialog.prototype.setMessage = function(text, message_type) {
+ var box = new AlertBox();
+ box.setText(text);
+ if (message_type === 'error') {
+ box.setError(true);
+ }
+ this.prependContent(box.getElement());
+};
+
+ModalDialog.prototype.createDom = function() {
+ this._element = this.makeElement('div')
+ var element = this._element;
+
+ element.addClass('modal');
+
+ //1) create header
+ var header = this.makeElement('div')
+ header.addClass('modal-header');
+ element.append(header);
+
+ var close_link = this.makeElement('div');
+ close_link.addClass('close');
+ close_link.attr('data-dismiss', 'modal');
+ close_link.html('x');
+ header.append(close_link);
+
+ var title = this.makeElement('h3');
+ title.html(this._heading_text);
+ header.append(title);
+
+ //2) create content
+ var body = this.makeElement('div')
+ body.addClass('modal-body');
+ element.append(body);
+ this._content_element = body;
+ if (this._initial_content) {
+ this._content_element.append(this._initial_content);
+ }
+
+ //3) create footer with accept and reject buttons (ok/cancel).
+ var footer = this.makeElement('div');
+ footer.addClass('modal-footer');
+ element.append(footer);
+
+ var accept_btn = this.makeElement('button');
+ accept_btn.addClass('btn btn-primary');
+ accept_btn.html(this._accept_button_text);
+ footer.append(accept_btn);
+
+ if (this._reject_button_text) {
+ var reject_btn = this.makeElement('button');
+ reject_btn.addClass('btn cancel');
+ reject_btn.html(this._reject_button_text);
+ footer.append(reject_btn);
+ }
+
+ //4) attach event handlers to the buttons
+ setupButtonEventHandlers(accept_btn, this._accept_handler);
+ if (this._reject_button_text) {
+ setupButtonEventHandlers(reject_btn, this._reject_handler);
+ }
+ setupButtonEventHandlers(close_link, this._reject_handler);
+
+ this.hide();
+};
+
+/**
* attaches a modal menu with a text editor
* to a link. The modal menu is from bootstrap.js
*/
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
index c810aecb..7c3ef372 100644
--- a/askbot/skins/default/templates/question.html
+++ b/askbot/skins/default/templates/question.html
@@ -8,6 +8,7 @@
{% block forestyle %}
<link rel="canonical" href="{{settings.APP_URL|strip_path}}{{question.get_absolute_url()}}" />
<link rel="stylesheet" type="text/css" href="{{'/js/wmd/wmd.css'|media}}" />
+ <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
{% endblock %}
{% block forejs %}
<script type="text/javascript">
diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html
index 4399c823..bc640623 100644
--- a/askbot/skins/default/templates/question/javascript.html
+++ b/askbot/skins/default/templates/question/javascript.html
@@ -27,6 +27,7 @@
{% endif %}
askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}';
</script>
+<script type="text/javascript" src='{{"/bootstrap/js/bootstrap.js"|media}}'></script>
{% if settings.EDITOR_TYPE == 'markdown' %}
<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
diff --git a/askbot/skins/default/templates/widgets/groups_list.html b/askbot/skins/default/templates/widgets/groups_list.html
new file mode 100644
index 00000000..0669f34f
--- /dev/null
+++ b/askbot/skins/default/templates/widgets/groups_list.html
@@ -0,0 +1,4 @@
+{% import "macros.html" as macros %}
+{% for group in groups %}
+ <p>{{ macros.user_group(group) }}</p>
+{% endfor %}
diff --git a/askbot/skins/default/templates/widgets/user_list.html b/askbot/skins/default/templates/widgets/user_list.html
index e51abc5b..52cf8bd4 100644
--- a/askbot/skins/default/templates/widgets/user_list.html
+++ b/askbot/skins/default/templates/widgets/user_list.html
@@ -1,4 +1,4 @@
-{%from "macros.html" import gravatar %}
+{% import "macros.html" as macros %}
<div class="userList">
<table class="list-table">
<tr>
@@ -6,10 +6,10 @@
{% for user in users %}
<div class="user">
<ul>
- <li class="thumb">{{ gravatar(user, 32) }}</li>
- <li><a href="{% url user_profile user.id, user.username|slugify %}{% if profile_section %}?sort={{profile_section}}{% endif %}">{{user.username|escape}}</a>{{ user_country_flag(user) }}</li>
+ <li class="thumb">{{ macros.gravatar(user, 32) }}</li>
+ <li><a href="{% url user_profile user.id, user.username|slugify %}{% if profile_section %}?sort={{profile_section}}{% endif %}">{{user.username|escape}}</a>{{ macros.user_country_flag(user) }}</li>
<li>{{
- user_score_and_badge_summary(
+ macros.user_score_and_badge_summary(
user,
karma_mode = karma_mode,
badges_mode = badges_mode
diff --git a/askbot/skins/loaders.py b/askbot/skins/loaders.py
index aa3188e9..c1367fe5 100644
--- a/askbot/skins/loaders.py
+++ b/askbot/skins/loaders.py
@@ -115,14 +115,20 @@ def get_template(template, request = None):
skin.set_language(request.LANGUAGE_CODE)
return skin.get_template(template)
+def render_into_skin_as_string(template, data, request):
+ context = RequestContext(request, data)
+ template = get_template(template, request)
+ return template.render(context)
+
def render_into_skin(template, data, request, mimetype = 'text/html'):
"""in the future this function will be able to
switch skin depending on the site administrator/user selection
right now only admins can switch
"""
- context = RequestContext(request, data)
- template = get_template(template, request)
- return HttpResponse(template.render(context), mimetype = mimetype)
+ return HttpResponse(
+ render_into_skin_as_string(template, data, request),
+ mimetype=mimetype
+ )
def render_text_into_skin(text, data, request):
context = RequestContext(request, data)
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 123fc112..aa602f55 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -30,6 +30,7 @@ from askbot.utils import decorators
from askbot.utils import url_utils
from askbot import mail
from askbot.skins.loaders import render_into_skin, get_template
+from askbot.skins.loaders import render_into_skin_as_string
from askbot import const
@@ -475,15 +476,39 @@ def get_tags_by_wildcard(request):
re_data = simplejson.dumps({'tag_count': count, 'tag_names': list(names)})
return HttpResponse(re_data, mimetype = 'application/json')
-@decorators.ajax_only
@decorators.get_only
def get_thread_shared_users(request):
- pass
+ """returns snippet of html with users"""
+ thread_id = request.GET['thread_id']
+ thread_id = IntegerField().clean(thread_id)
+ thread = models.Thread.objects.get(id=thread_id)
+ users = thread.get_users_shared_with()
+ data = {
+ 'users': users,
+ }
+ html = render_into_skin_as_string('widgets/user_list.html', data, request)
+ re_data = simplejson.dumps({
+ 'html': html,
+ 'users_count': users.count(),
+ 'success': True
+ })
+ return HttpResponse(re_data, mimetype='application/json')
-@decorators.ajax_only
@decorators.get_only
def get_thread_shared_groups(request):
- pass
+ """returns snippet of html with groups"""
+ thread_id = request.GET['thread_id']
+ thread_id = IntegerField().clean(thread_id)
+ thread = models.Thread.objects.get(id=thread_id)
+ groups = thread.get_groups_shared_with()
+ data = {'groups': groups}
+ html = render_into_skin_as_string('widgets/groups_list.html', data, request)
+ re_data = simplejson.dumps({
+ 'html': html,
+ 'groups_count': groups.count(),
+ 'success': True
+ })
+ return HttpResponse(re_data, mimetype='application/json')
@decorators.ajax_only
def get_html_template(request):
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 268227eb..6cc49cc5 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -568,12 +568,12 @@ def question(request, id):#refactor - long subroutine. display question body, an
#shared with ...
users_count, groups_count = thread.get_sharing_info()
shared_users = thread.get_users_shared_with(
- max_count=2,
+ max_count=2,#"visitor" is implicit
exclude_user=request.user
)
sharing_info = {
'users': shared_users,
- 'groups': thread.get_groups_shared_with(max_count=2),
+ 'groups': thread.get_groups_shared_with(max_count=3),
'more_users_count': max(0, users_count - 3),
'more_groups_count': max(0, groups_count - 3)
}