diff options
-rw-r--r-- | forums/settings.py | 4 | ||||
-rw-r--r-- | forums/urls.py | 6 | ||||
-rw-r--r-- | forums/wsgi.py | 4 | ||||
-rw-r--r-- | static/website/css/main.css | 37 | ||||
-rw-r--r-- | static/website/js/custom.js | 4 | ||||
-rw-r--r-- | static/website/js/thread-user.js | 91 | ||||
-rw-r--r-- | static/website/templates/get-question.html | 111 | ||||
-rw-r--r-- | static/website/templates/index.html | 2 | ||||
-rw-r--r-- | static/website/templates/new-question.html | 2 | ||||
-rw-r--r-- | static/website/templates/search.html | 2 | ||||
-rw-r--r-- | website/context_processors.py | 10 | ||||
-rw-r--r-- | website/templatetags/permission_tags.py | 12 | ||||
-rw-r--r-- | website/urls.py | 1 | ||||
-rw-r--r-- | website/views.py | 45 |
14 files changed, 293 insertions, 38 deletions
diff --git a/forums/settings.py b/forums/settings.py index dc2bb08..2930bc0 100644 --- a/forums/settings.py +++ b/forums/settings.py @@ -1,6 +1,7 @@ #Custom settings from os.path import * from config import * +from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS PROJECT_DIR = abspath(dirname(__file__) + '/../') @@ -139,7 +140,7 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', # Uncomment the next line to enable the admin: - 'django.contrib.admin', + #'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'website', @@ -179,3 +180,4 @@ LOGGING = { AUTH_USER_MODEL = 'drupal_auth.Users' AUTHENTICATION_BACKENDS = ( 'drupal_auth.backends.DrupalAuthBackend', ) DATABASE_ROUTERS = ['drupal_auth.routers.DrupalAuthRouter'] +TEMPLATE_CONTEXT_PROCESSORS += ('website.context_processors.admin_processor', ) diff --git a/forums/urls.py b/forums/urls.py index e129d4b..9a0ec63 100644 --- a/forums/urls.py +++ b/forums/urls.py @@ -1,8 +1,8 @@ from django.conf.urls import patterns, include, url # Uncomment the next two lines to enable the admin: -from django.contrib import admin -admin.autodiscover() +#from django.contrib import admin +#admin.autodiscover() urlpatterns = patterns('', # Examples: @@ -14,7 +14,7 @@ urlpatterns = patterns('', # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: - url(r'^admin/', include(admin.site.urls)), + #url(r'^admin/', include(admin.site.urls)), # User account urls url(r'^accounts/login/', 'forums.views.user_login', name='user_login'), diff --git a/forums/wsgi.py b/forums/wsgi.py index 728eed4..3a52e8b 100644 --- a/forums/wsgi.py +++ b/forums/wsgi.py @@ -24,8 +24,8 @@ sys.path.append('/Sites/venv/forums/') # os.environ["DJANGO_SETTINGS_MODULE"] = "forums.settings" os.environ["DJANGO_SETTINGS_MODULE"] = "forums.settings" -activate_this = '/Sites/venv/bin/activate_this.py' -execfile(activate_this, dict(__file__=activate_this)) +#activate_this = '/Sites/venv/bin/activate_this.py' +#execfile(activate_this, dict(__file__=activate_this)) # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION diff --git a/static/website/css/main.css b/static/website/css/main.css index 2d629ac..ab5226f 100644 --- a/static/website/css/main.css +++ b/static/website/css/main.css @@ -9,6 +9,10 @@ .navbar-default { margin-bottom: 0; } +/* override nicEditor */ +#questionInstance { + background: #ffffff !important; +} /* main styles */ body { background: #fafafa; @@ -54,7 +58,7 @@ body { } #content .editable { padding: 15px 5px 15px 5px; - background: #F0F0F0; + background: #fafafa; } #content .question .title a{ padding: 0 0 7px 0; @@ -94,6 +98,12 @@ body { background: #f5f5f5; color: #424242; } +#question-details-edit { + position: relative; + top: 2px; + margin-top: 2px; + color: #43ac6a; +} #content .question .meta{ position: absolute; right: 0px; @@ -132,11 +142,34 @@ table .title a { .modify a.save { display: none; } - .vs { padding: 0px 5px !important; font-size: x-small; } +.hideme { + display: none; +} +.saving, .saved { + position: fixed; + z-index: 10; + left: 45%; + top: 45%; + padding: 5px 10px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0px 0px 10px #cccccc; + -moz-box-shadow: 0px 0px 10px #cccccc; + -obox-shadow: 0px 0px 10px #cccccc; + box-shadow: 0px 0px 10px #cccccc; +} +.saving { + background: lightyellow; +} +.saved { + background: lightgreen; +} #content .reply { position: relative; border-bottom: 1px solid #f5f5f5; diff --git a/static/website/js/custom.js b/static/website/js/custom.js index da5839b..467ba9d 100644 --- a/static/website/js/custom.js +++ b/static/website/js/custom.js @@ -7,6 +7,8 @@ $(document).ready(function() { $category.change(function() { $("#similar-link").hide(); var category = $(this).val(); + /* see thread-user.js */ + $("#question-details-ok").show(); $.ajax({ url: "/ajax-tutorials/", type: "POST", @@ -59,7 +61,7 @@ $(document).ready(function() { $response = $(data); var similar_count= $response.find("#similar-count").text(); $("#similar-link").show().html(similar_count); - $(".modal-body").html(data); + $("#modal-body").html(data); } }); }); diff --git a/static/website/js/thread-user.js b/static/website/js/thread-user.js index 502f0ce..189d126 100644 --- a/static/website/js/thread-user.js +++ b/static/website/js/thread-user.js @@ -1,5 +1,4 @@ bkLib.onDomLoaded(function() { - var questionNicEditor = new nicEditor({ buttonList : ['fontSize','bold','italic','underline','strikeThrough','subscript','superscript','html','image', 'link'], iconsPath: "/static/website/js/nicEditorIcons.gif", @@ -13,12 +12,19 @@ $(document).ready(function() { * question edit section * set the jquery variables */ + $saving = $(".saving"); + $saved= $(".saved"); $question = $(".question"); $question_modify = $(".question .modify"); $question_edit = $(".question .modify .edit"); $question_save = $(".question .modify .save"); + $question_title = $(".title"); + $question_title_editable = $(".title-editable"); + $question_title_edit = $("#title-edit"); + $question_title_edit_input = $("#title-edit input"); $questionNicPanel = $("#questionNicPanel"); $questionInstance = $("#questionInstance"); + $question_details_edit = $("#question-details-edit"); /* make the question editable and show modify */ //$question.addClass("editable"); @@ -28,9 +34,20 @@ $(document).ready(function() { function modify(thisObj){ thisObj.hide(); thisObj.next().css("display", "block"); + + $question_title.hide(); + $question_title_edit_input.val($.trim($($question_title).text())); + $question_title_edit.show(); + $question_edit.hide(); + $question_save.show(); + $questionNicPanel.show(); $questionInstance.focus(); + $question_details_edit.show(); } + $question_title_editable.click(function(){ + modify($question_edit); + }); $question_edit.click(function () { modify($question_edit); }); @@ -38,30 +55,96 @@ $(document).ready(function() { modify($question_edit); }); $question_save.click(function () { + $saving.show(); $(this).hide(); + $question_title.text($question_title_edit_input.val()); + $question_title_edit.hide(); + $question_title.show(); $questionNicPanel.hide(); + $question_details_edit.hide(); $(this).prev().css("display", "block"); /* make the ajax call */ //var id_length = $question_save.attr("id").length; //var question_id = parseInt($question_save.attr("id").substr(id_length-1)); var question_id = parseInt($question_save.data("qid")); - console.log(question_id); + var question_title = $question_title.text(); var question_body = $questionInstance.html(); $.ajax({ url: "/ajax-question-update/", data:{ question_id: question_id, + question_title: question_title, question_body: question_body, }, type: "POST", dataType: "html", success: function(data){ console.log(data); + $saving.hide(); + $saved.show(); + $saved.fadeOut("slow"); } }); }); + + /* + * question details edit section + * handle everything in the popup + */ + $question_details_edit = $("#question-details-edit"); + $question_details_ok = $("#question-details-ok"); + $question_category = $('#id_category'); + $question_tutorial = $('#id_tutorial'); + $question_minute_range = $('#id_minute_range'); + $question_second_range = $('#id_second_range'); + + $question_details_ok.click(function() { + console.log($(this).data("qid")); + var category = $question_category.val(); + var tutorial = $question_tutorial.val(); + var minute_range = $question_minute_range.val(); + var second_range = $question_second_range.val(); + $.ajax({ + url: "/ajax-details-update/", + data: { + qid: $(this).data("qid"), + category: category, + tutorial: tutorial, + minute_range: minute_range, + second_range: second_range + }, + type: "POST", + success: function(data){ + if(category != 'None') { + $(".category small a").html(category); + $(".category").show() + } else { + $(".category").hide() + } + if(tutorial!= 'None') { + $(".tutorial small a").html(tutorial); + $(".tutorial").show() + } else { + $(".tutorial").hide() + } + if(minute_range!= 'None') { + $(".minute_range small a").html(minute_range); + $(".minute_range").show() + } else { + $(".minute_range").hide() + } + if(second_range != 'None') { + $(".second_range small a").html(second_range); + $(".second_range").show() + } else { + $(".second_range").hide() + } + console.log(data); + } + }); + }); /* * reply edit section * set the dom variables @@ -89,6 +172,7 @@ $(document).ready(function() { }); $reply_save.click(function() { + $saving.show(); var target = $(this).data("target"); replyNicEditor.removeInstance(target); $replyPanelWrapper.hide(); @@ -108,6 +192,9 @@ $(document).ready(function() { }, success: function(data) { console.log(data); + $saving.hide(); + $saved.show(); + $saved.fadeOut("slow"); } }); }); diff --git a/static/website/templates/get-question.html b/static/website/templates/get-question.html index 8c242d6..19c0283 100644 --- a/static/website/templates/get-question.html +++ b/static/website/templates/get-question.html @@ -1,14 +1,26 @@ {% extends 'website/templates/base.html' %} {% load static %} {% load widget_tweaks %} + +{% load permission_tags %} + {% block content %} -<div class="question {% ifequal question.user|stringformat:'s' user|stringformat:'s' %}editable{% endifequal %}"> - <div class="title"> - <a href=""> {{ question.title }} </a> +<span class="saving hideme">saving . . .</span> +<span class="saved hideme">saved</span> + +<div class="question {% if user|can_edit:question %}editable{% endif %}"> + <div class="title {% if user|can_edit:question %}title-editable{% endif %}"> + {{ question.title }} + </div> + + <div id="title-edit" class="hideme"> + <h5>Title</h5> + <input class="form-control" type="text"> + <h5>Question</h5> </div> <div id="questionNicPanel"></div> - <div id="{% ifequal question.user|stringformat:'s' user|stringformat:'s' %}questionInstance{% endifequal %}" class="body"> + <div id="{% if user|can_edit:question %}questionInstance{% endif %}" class="body"> {{ question.body|safe }} </div> <br> @@ -29,34 +41,38 @@ </small> </span> - <span class="minute_range"> + <span class="minute_range {% if question.minute_range == 'None' %}hideme{% endif %}"> <small> <a href="{% url 'website:filter' question.category question.tutorial question.minute_range %}"> {{ question.minute_range }} min </a> </small> </span> - - <span class="second_range"> + + <span class="second_range {% if question.minute_range == 'None' %}hideme{% endif %}"> <small> <a href="{% url 'website:filter' question.category question.tutorial question.minute_range question.second_range%}"> {{ question.second_range }} sec </a> </small> </span> - + + <a id="question-details-edit" data-toggle="modal" data-target="#detailsModal" href="#" class="hideme"> + <span class="glyphicon glyphicon-edit"></span> + </a> + <span class="modify"> - {% ifequal question.uid|stringformat:'s' user.id|stringformat:'s' %} + {% if user|can_edit:question %} <a class="edit btn btn-xs btn-info" href="#">Edit</a> <a class="save btn btn-xs btn-success" data-qid="{{ question.id }}" href="#">Save</a> - {% endifequal %} + {% endif %} </span> <span class="meta"> <small> - <i> - {{ question.date_created|date:"y-d-m" }}, {{ question.date_created|time }} - </i> + <i> + {{ question.date_created|date:"y-d-m" }}, {{ question.date_created|time }} + </i> </small> <span class="user"> @@ -72,7 +88,7 @@ </div> {% for reply in replies %} - <div class="reply {% ifequal reply.uid|stringformat:'s' user.id|stringformat:'s' %}editable{% endifequal %}" id="reply{{reply.id}}"> + <div class="reply {% if user|can_edit:reply %}editable{% endif %}" id="reply{{reply.id}}"> <div class="body" id="body{{ reply.id }}"> {{ reply.body|safe }} @@ -82,12 +98,12 @@ {{ reply.user }} </span> - {% ifequal reply.uid|stringformat:'s' user.id|stringformat:'s' %} + {% if user|can_edit:reply %} <span class="modify" style="display:block"> <a class="edit btn btn-xs btn-info vs" href="#body{{ reply.id}}" data-target="body{{ reply.id }}">Edit</a> <a class="save btn btn-xs btn-success vs" data-target="body{{ reply.id }}" data-rid="{{ reply.id }}" href="#">Save</a> </span> - {% endifequal %} + {% endif %} </div> <!-- /.reply --> {% endfor %} @@ -104,7 +120,7 @@ </div> </div> {% endwith %} - <input class="btn btn-info" type="submit" value="Submit Reply"> + <input class="btn btn-sm btn-info" type="submit" value="Submit Reply"> </form> {% else %} <h4> @@ -112,6 +128,66 @@ </h4> {% endif %} + <!-- Modal --> + <div class="modal fade" id="detailsModal" tabindex="-1" role="dialog" aria-labelledby="detailsModalLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="myModalLabel">Edit Question Details</h4> + </div> + <div class="modal-body"> + + <h5>The Current question is under:</h5> + {{ question.category }} + --> {{ question.tutorial }} + {% if question.minute_range != 'None' %} + --> {{ question.minute_range }} + {% endif %} + {% if question.second_range != 'None' %} + --> {{ question.second_range}} + {% endif %} + + <h5>Move the question to:</h5> + <div class="row"> + <div class="col-lg-4 col-md-4 col-sm-4"> + <select id="id_category" class="form-control"> + <option value="None">Select a Category</option> + <option value="Advanced-C++">Advanced-C++</option> + <option value="BASH">BASH</option> + <option value="Blender">Blender</option> + <option value="C-and-C++">C-and-C++</option> + <option value="CellDesigner">CellDesigner</option> + </select> + </div> + <div class="col-lg-4 col-md-4 col-sm-4"> + <select id="id_tutorial" class="form-control" disabled> + <option value="None">Select a Tutorial</option> + </select> + </div> + <div class="col-lg-2 col-md-2 col-sm-2"> + <select id="id_minute_range" class="form-control" disabled> + <option value="None">min</option> + </select> + </div> + <div class="col-lg-2 col-md-2 col-sm-2"> + <select id="id_second_range" class="form-control" disabled> + <option value="None">sec</option> + </select> + </div> + </div> <!-- /.row --> + <hr> + <div class="pull-right"> + <a id="question-details-ok" class="btn btn-sm btn-success hideme" data-qid={{ question.id }} href="#">Ok</a> + <a class="btn btn-sm btn-default" data-dismiss="modal" href="#">Close</a> + </div> + <div class="clearfix"></div> + + </div> <!-- /.modal-body --> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> + </div><!-- /.modal --> + <script src="{% static 'website/js/nicEdit.js' %}" type="text/javascript"></script> <script type="text/javascript"> bkLib.onDomLoaded(function() { @@ -125,4 +201,5 @@ {% block javascript %} <script src="{% static 'website/js/thread-user.js' %}"></script> + <script src="{% static 'website/js/custom.js' %}"></script> {% endblock %} diff --git a/static/website/templates/index.html b/static/website/templates/index.html index 1823f4e..47ca53c 100644 --- a/static/website/templates/index.html +++ b/static/website/templates/index.html @@ -2,7 +2,7 @@ {% block content %} {% load count_tags %} <h4><u>Recent Questions</u></h4> -<table class="table table-striped table-bordered table-hover"> +<table class="table table-bordered table-hover"> <th> FOSS </th> <th> Tutorial</th> <th> Min </th> diff --git a/static/website/templates/new-question.html b/static/website/templates/new-question.html index 60efa9b..63ae19a 100644 --- a/static/website/templates/new-question.html +++ b/static/website/templates/new-question.html @@ -62,7 +62,7 @@ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title" id="myModalLabel">Similar Questions</h4> </div> - <div class="modal-body"> + <div class="modal-body" id="modal-body"> ... </div> </div><!-- /.modal-content --> diff --git a/static/website/templates/search.html b/static/website/templates/search.html index 8c96acb..3ffc871 100644 --- a/static/website/templates/search.html +++ b/static/website/templates/search.html @@ -5,7 +5,7 @@ <!-- Nav tabs --> <ul class="nav nav-tabs"> - <li><a href="#search-by-keyword" data-toggle="tab">Search by Keyword</a></li> + <li class="active" ><a href="#search-by-keyword" data-toggle="tab">Search by Keyword</a></li> <li><a href="#search-by-time" data-toggle="tab">Search by Time</a></li> </ul> diff --git a/website/context_processors.py b/website/context_processors.py new file mode 100644 index 0000000..2497e7c --- /dev/null +++ b/website/context_processors.py @@ -0,0 +1,10 @@ +from website.views import admins + +def admin_processor(request): + return {'admins': admins} + +def booleans(): + return { + 'True': True, + 'False': False, + } diff --git a/website/templatetags/permission_tags.py b/website/templatetags/permission_tags.py new file mode 100644 index 0000000..b85d747 --- /dev/null +++ b/website/templatetags/permission_tags.py @@ -0,0 +1,12 @@ +from django import template + +from website.views import admins + +register = template.Library() + +def can_edit(user, obj): + if user.id == obj.uid or user.id in admins: + return True + return False + +register.filter(can_edit) diff --git a/website/urls.py b/website/urls.py index bdad667..9288e1e 100644 --- a/website/urls.py +++ b/website/urls.py @@ -19,6 +19,7 @@ urlpatterns = patterns('', url(r'^ajax-tutorials/$', 'website.views.ajax_tutorials', name='ajax_tutorials'), url(r'^ajax-duration/$', 'website.views.ajax_duration', name='ajax_duration'), url(r'^ajax-question-update/$', 'website.views.ajax_question_update', name='ajax_question_update'), + url(r'^ajax-details-update/$', 'website.views.ajax_details_update', name='ajax_details_update'), url(r'^ajax-reply-update/$', 'website.views.ajax_reply_update', name='ajax_reply_update'), url(r'^ajax-similar-questions/$', 'website.views.ajax_similar_questions', name='ajax_similar_questions'), url(r'^ajax-notification-remove/$', 'website.views.ajax_notification_remove', name='ajax_notification_remove'), diff --git a/website/views.py b/website/views.py index e470e09..38bd973 100644 --- a/website/views.py +++ b/website/views.py @@ -12,8 +12,11 @@ from website.models import Question, Reply, Notification, TutorialDetails, Tutor from website.forms import NewQuestionForm, ReplyQuesitionForm from website.helpers import get_video_info +admins = ( + 99999, +) -categories = [ +categories = ( 'Advanced-C++', 'BASH', 'Blender', 'C-and-C++', 'CellDesigner', 'Digital-Divide', 'Drupal', 'Firefox', 'GChemPaint', 'Geogebra', @@ -28,7 +31,7 @@ categories = [ 'QCad', 'R', 'Ruby', 'Scilab', 'Selenium', 'Single-Board-Heater-System', 'Spoken-Tutorial-Technology', 'Step', 'Thunderbird', 'Tux-Typing', 'What-is-Spoken-Tutorial', 'Xfig' -] +) def home(request): marker = 0 @@ -219,6 +222,13 @@ def search(request): # Ajax Section # All the ajax views go below @csrf_exempt +def ajaX_category(request): + context = { + 'categories': categories + } + return render(request, 'website/templates/ajax_categories.html', context) + +@csrf_exempt def ajax_tutorials(request): if request.method == 'POST': category = request.POST.get('category') @@ -241,9 +251,10 @@ def ajax_duration(request): Q(tutorial_detail_id=video_detail.id), Q(language='English') ) - video_path = '/Sites/spoken_tutorial_org/sites/default/files/{0}'.format( - video_resource.tutorial_video - ) + #video_path = '/Sites/spoken_tutorial_org/sites/default/files/{0}'.format( + # video_resource.tutorial_video + #) + video_path = '/home/cheese/test-video.ogv' video_info = get_video_info(video_path) # convert minutes to 1 if less than 0 @@ -264,22 +275,42 @@ def ajax_duration(request): def ajax_question_update(request): if request.method == 'POST': qid = request.POST['question_id'] + title = request.POST['question_title'] body = request.POST['question_body'] question = get_object_or_404(Question, pk=qid) if question: - if question.uid == request.user.id: + if question.uid == request.user.id or request.user.id in admins: + question.title = title question.body = body question.save() return HttpResponse("saved") @csrf_exempt +def ajax_details_update(request): + if request.method == 'POST': + qid = request.POST['qid'] + category = request.POST['category'] + tutorial = request.POST['tutorial'] + minute_range = request.POST['minute_range'] + second_range = request.POST['second_range'] + question = get_object_or_404(Question, pk=qid) + if question: + if question.uid == request.user.id or request.user.id in admins: + question.category = category + question.tutorial = tutorial + question.minute_range = minute_range + question.second_range = second_range + question.save() + return HttpResponse("saved") + +@csrf_exempt def ajax_reply_update(request): if request.method == 'POST': rid = request.POST['reply_id'] body = request.POST['reply_body'] reply= get_object_or_404(Reply, pk=rid) if reply: - if reply.uid == request.user.id: + if reply.uid == request.user.id or request.user.id in admins: reply.body = body reply.save() return HttpResponse("saved") |