diff options
81 files changed, 1285 insertions, 1201 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py index 024c821d..25057b43 100644 --- a/askbot/__init__.py +++ b/askbot/__init__.py @@ -14,6 +14,7 @@ VERSION = (0, 7, 48) REQUIREMENTS = { 'akismet': 'akismet', 'django': 'django>=1.3.1,<1.5', + 'compressor': 'django-compressor==1.2', 'jinja2': 'Jinja2', 'coffin': 'Coffin>=0.3', 'south': 'South>=0.7.1', @@ -40,7 +41,7 @@ REQUIREMENTS = { if platform.system() != 'Windows': REQUIREMENTS['lamson'] = 'Lamson' - + #necessary for interoperability of django and coffin try: from askbot import patches diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py index fd62bc88..c1989f8d 100644 --- a/askbot/conf/__init__.py +++ b/askbot/conf/__init__.py @@ -8,6 +8,7 @@ import askbot.conf.karma_and_badges_visibility import askbot.conf.email import askbot.conf.forum_data_rules import askbot.conf.moderation +import askbot.conf.main_pages import askbot.conf.flatpages import askbot.conf.site_settings import askbot.conf.license diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py index e8a2b539..524ab16a 100644 --- a/askbot/conf/forum_data_rules.py +++ b/askbot/conf/forum_data_rules.py @@ -15,7 +15,7 @@ FORUM_DATA_RULES = livesettings.ConfigurationGroup( EDITOR_CHOICES = ( ('markdown', 'markdown'), - ('tinymce', 'WISYWIG (tinymce)') + ('tinymce', 'WYSIWYG (tinymce)') ) settings.register( @@ -354,7 +354,7 @@ settings.register( ) ) -#todo: looks like there is a bug in askbot.deps.livesettings +#todo: looks like there is a bug in askbot.deps.livesettings #that does not allow Integer values with defaults and choices settings.register( livesettings.StringValue( diff --git a/askbot/conf/main_pages.py b/askbot/conf/main_pages.py new file mode 100644 index 00000000..06339a2f --- /dev/null +++ b/askbot/conf/main_pages.py @@ -0,0 +1,97 @@ +""" +Settings responsible for display of questions lists +""" +from askbot.conf.settings_wrapper import settings +from askbot.conf.super_groups import DATA_AND_FORMATTING +from askbot.deps import livesettings +from django.utils.translation import ugettext_lazy as _ + +MAIN_PAGES = livesettings.ConfigurationGroup( + 'MAIN_PAGES', + _('Logic of the questions page'), + super_group=DATA_AND_FORMATTING + ) + +settings.register( + livesettings.BooleanValue( + MAIN_PAGES, + 'ASK_BUTTON_ENABLED', + default=True, + description=_('Enable big Ask button'), + help_text=_( + 'Disabling this button will reduce number of new questions. ' + 'If this button is disabled, the ask button in the search menu ' + 'will still be available.' + ) + ) +) + +settings.register( + livesettings.BooleanValue( + MAIN_PAGES, + 'ALL_SCOPE_ENABLED', + default=True, + description=_('Enable "All Questions" selector'), + help_text=_('At least one of these selectors must be enabled') + ) +) + +settings.register( + livesettings.BooleanValue( + MAIN_PAGES, + 'UNANSWERED_SCOPE_ENABLED', + default=True, + description=_('Enable "Unanswered Questions" selector'), + help_text=_('At least one of these selectors must be enabled') + ) +) + +settings.register( + livesettings.BooleanValue( + MAIN_PAGES, + 'FOLLOWED_SCOPE_ENABLED', + default=True, + description=_('Enable "Followed Questions" selector'), + help_text=_('At least one of these selectors must be enabled') + ) +) + +def enable_default_selector_if_disabled(old_value, new_value): + scope_switch_name = new_value.upper() + '_SCOPE_ENABLED' + is_enabled = getattr(settings, scope_switch_name) + if is_enabled is False: + settings.update(scope_switch_name, True) + return new_value + +SCOPE_CHOICES_AUTHENTICATED = ( + ('all', _('All Questions')), + ('unanswered', _('Unanswered Questions')), + ('followed', _('Followed Questions')) +) + +settings.register( + livesettings.StringValue( + MAIN_PAGES, + 'DEFAULT_SCOPE_AUTHENTICATED', + choices=SCOPE_CHOICES_AUTHENTICATED, + default='all', + description=_('Default questions selector for the authenticated users'), + update_callback=enable_default_selector_if_disabled + ) +) + +SCOPE_CHOICES_ANONYMOUS = (#anonymous users can't see followed questions + ('all', _('All Questions')), + ('unanswered', _('Unanswered Questions')), +) + +settings.register( + livesettings.StringValue( + MAIN_PAGES, + 'DEFAULT_SCOPE_ANONYMOUS', + choices=SCOPE_CHOICES_ANONYMOUS, + default='all', + description=_('Default questions selector for the anonymous users'), + update_callback=enable_default_selector_if_disabled + ) +) diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py index 0240d7f5..b9f9325c 100644 --- a/askbot/const/__init__.py +++ b/askbot/const/__init__.py @@ -112,7 +112,7 @@ DEFAULT_POST_SORT_METHOD = 'activity-desc' POST_SCOPE_LIST = ( ('all', _('all')), ('unanswered', _('unanswered')), - ('favorite', _('favorite')), + ('followed', _('followed')), ) DEFAULT_POST_SCOPE = 'all' diff --git a/askbot/deployment/__init__.py b/askbot/deployment/__init__.py index 1ba5c202..5477b284 100644 --- a/askbot/deployment/__init__.py +++ b/askbot/deployment/__init__.py @@ -217,6 +217,8 @@ def collect_missing_options(options_dict): print 'name %s cannot be used for the database name' % value elif value == path_utils.LOG_DIR_NAME: print 'name %s cannot be used for the database name' % value + else: + database_file_name = value if database_file_name: options_dict['database_name'] = database_file_name diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py index 8f33e8c0..9ddb6414 100644 --- a/askbot/deps/django_authopenid/views.py +++ b/askbot/deps/django_authopenid/views.py @@ -99,7 +99,7 @@ def create_authenticated_user_account( user = User.objects.create_user(username, email) user_registered.send(None, user=user) - logging.debug('creating new openid user association for %s') + logging.debug('creating new openid user association for %s', username) if password: user.set_password(password) diff --git a/askbot/deps/livesettings/views.py b/askbot/deps/livesettings/views.py index d12eb602..0f43987c 100644 --- a/askbot/deps/livesettings/views.py +++ b/askbot/deps/livesettings/views.py @@ -7,6 +7,7 @@ from django.views.decorators.cache import never_cache from askbot.deps.livesettings import ConfigurationSettings, forms from askbot.deps.livesettings import ImageValue from askbot.deps.livesettings.overrides import get_overrides +from django.contrib import messages import logging log = logging.getLogger('configuration.views') @@ -15,7 +16,7 @@ def group_settings(request, group, template='livesettings/group_settings.html'): # Determine what set of settings this editor is used for use_db, overrides = get_overrides(); - + mgr = ConfigurationSettings() settings = mgr[group] @@ -42,10 +43,13 @@ def group_settings(request, group, template='livesettings/group_settings.html'): else: continue - if cfg.update(value): - # Give user feedback as to which settings were changed - message='Updated %s on %s' % (cfg.key, cfg.group.key) - request.user.message_set.create(message = message) + try: + if cfg.update(value): + message='Updated %s on %s' % (cfg.key, cfg.group.key) + messages.success(request, message) + #the else if for the settings that are not updated. + except Exception, e: + messages.error(request, e.message) return HttpResponseRedirect(request.path) else: @@ -71,31 +75,31 @@ def site_settings(request): default_group= mgr.groups()[0].key return HttpResponseRedirect(reverse('group_settings', args=[default_group])) #return group_settings(request, group=None, template='livesettings/site_settings.html') - + def export_as_python(request): """Export site settings as a dictionary of dictionaries""" - + from askbot.deps.livesettings.models import Setting, LongSetting import pprint - + work = {} both = list(Setting.objects.all()) both.extend(list(LongSetting.objects.all())) - + for s in both: if not work.has_key(s.site.id): work[s.site.id] = {} sitesettings = work[s.site.id] - + if not sitesettings.has_key(s.group): sitesettings[s.group] = {} sitegroup = sitesettings[s.group] - + sitegroup[s.key] = s.value - + pp = pprint.PrettyPrinter(indent=4) pretty = pp.pformat(work) return render_to_response('livesettings/text.txt', { 'text' : pretty }, mimetype='text/plain') - + export_as_python = never_cache(staff_member_required(export_as_python)) diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst index 4c9e58fd..f59138c5 100644 --- a/askbot/doc/source/changelog.rst +++ b/askbot/doc/source/changelog.rst @@ -3,13 +3,17 @@ Changes in Askbot Development version ------------------- +* Added a placeholder template for the custom javascript on the question page +* Allowed to disable the big "ask" button. +* Some support for the media compression (Tyler Mandry) +* Allowed to enable and disable question scopes on the main page * Added full text support for some languages with Postgresql: Danish, Dutch, English, Finnish, French, German, Hungarian, Italian, Japanese (requires package textsearch_ja), Norwegian, Portugese, Romanian, Russian, Spanish, Swedish, Turkish. * repost answer as a comment under the previous (older) answer -* minor edit option for question, answer and comments, to suppress email alerts -* allowed tags to be created updon marking them as interesting/ignored/subscribed +* minor edit option for question and answer, to suppress email alerts +* allowed tags to be created upon marking them as interesting/ignored/subscribed 0.7.48 (Jan 28, 2013) --------------------- diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst index 71d942bb..3fa086df 100644 --- a/askbot/doc/source/contributors.rst +++ b/askbot/doc/source/contributors.rst @@ -43,6 +43,8 @@ Programming, bug fixes and documentation * `Paul Backhouse <https://github.com/powlo>`_ * `jtrain <https://github.com/jtrain>`_ * Niki Rocco +* `Tyler Mandry <https://github.com/tmandry>`_ +* `Jorge López Pérez <https://github.com/adobo>`_ Translations ------------ diff --git a/askbot/media/bootstrap/css/bootstrap.css b/askbot/media/bootstrap/css/bootstrap.css index e6190005..396e05c6 100644 --- a/askbot/media/bootstrap/css/bootstrap.css +++ b/askbot/media/bootstrap/css/bootstrap.css @@ -935,7 +935,6 @@ input[type="file"] { line-height: 18px \9; } select { - width: 220px; background-color: #ffffff; } select[multiple], @@ -968,6 +967,7 @@ textarea { -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; } +/* input:focus, textarea:focus { border-color: rgba(82, 168, 236, 0.8); @@ -975,10 +975,9 @@ textarea:focus { -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); outline: 0; - outline: thin dotted \9; - /* IE6-9 */ - + outline: thin dotted \9; ***** for IE6-9 * } +*/ input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus, diff --git a/askbot/media/js/live_search.js b/askbot/media/js/live_search.js index 99ffade4..dfae8321 100644 --- a/askbot/media/js/live_search.js +++ b/askbot/media/js/live_search.js @@ -291,10 +291,13 @@ InputToolTip.prototype.setClickHandler = function(handler) { InputToolTip.prototype.createDom = function() { var element = this.makeElement('div'); this._element = element; - - element.html(gettext('search or ask your question')); element.addClass('input-tool-tip'); + element.html(gettext('search or ask your question')); + this.decorate(element); +}; +InputToolTip.prototype.decorate = function(element) { + this._element = element; var handler = this._clickHandler; var me = this; element.click(function() { @@ -581,7 +584,7 @@ FullTextSearch.prototype.reset = function() { FullTextSearch.prototype.refreshXButton = function() { if(this.getSearchQuery().length > 0){ if (this._query.hasClass('searchInput')){ - $('#searchBar').attr('class', 'cancelable'); + $('#searchBar').addClass('cancelable'); this._xButton.show(); } } else { @@ -815,7 +818,9 @@ FullTextSearch.prototype.decorate = function(element) { toolTip.setClickHandler(function() { element.focus(); }); - this._element.after(toolTip.getElement()); + + element.after(toolTip.getElement()); + //below is called after getElement, b/c element must be defined if (this._prevText !== '') { toolTip.hide();//hide if search query is not empty diff --git a/askbot/media/js/post.js b/askbot/media/js/post.js index 691d504b..666fe70b 100644 --- a/askbot/media/js/post.js +++ b/askbot/media/js/post.js @@ -1006,7 +1006,7 @@ var Vote = function(){ questionId = qId; questionSlug = qSlug; questionAuthorId = questionAuthor; - currentUserId = userId; + currentUserId = '' + userId;//convert to string bindEvents(); }, @@ -1624,9 +1624,9 @@ EditCommentForm.prototype.createDom = function(){ this._text_counter = $('<span></span>').attr('class', 'counter'); this._controlsBox.append(this._text_counter); - this._submit_btn = $('<button class="submit small"></button>'); + this._submit_btn = $('<button class="submit"></button>'); this._controlsBox.append(this._submit_btn); - this._cancel_btn = $('<button class="submit small"></button>'); + this._cancel_btn = $('<button class="submit"></button>'); this._cancel_btn.html(gettext('cancel')); this._controlsBox.append(this._cancel_btn); @@ -2022,7 +2022,7 @@ Comment.prototype.getElement = function(){ Comment.superClass_.getElement.call(this); if (this.isBlank() && this.hasContent()){ this.setContent(); - if (enableMathJax === true){ + if (askbot['settings']['mathjaxEnabled'] === true){ MathJax.Hub.Queue(['Typeset', MathJax.Hub]); } } @@ -2318,7 +2318,7 @@ var socialSharing = function(){ URL = window.location.href; var urlBits = URL.split('/'); URL = urlBits.slice(0, -2).join('/') + '/'; - TEXT = escape($('h1 > a').html()); + TEXT = encodeURIComponent($('h1 > a').html()); var hashtag = encodeURIComponent( askbot['settings']['sharingSuffixText'] ); diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js index 21bf4536..8ce4e205 100644 --- a/askbot/media/js/utils.js +++ b/askbot/media/js/utils.js @@ -1,4 +1,3 @@ -//var $, scriptUrl, askbotSkin /** * attention - this function needs to be retired * as it cannot accurately give url to the media file @@ -72,6 +71,18 @@ var joinAsPhrase = function(values) { } }; +/** + * @return {boolean} + */ +var inArray = function(item, itemsList) { + for (var i = 0; i < itemsList.length; i++) { + if (item === itemsList[i]) { + return true; + } + } + return false; +}; + var showMessage = function(element, msg, where) { var div = $('<div class="vote-notification"><h3>' + msg + '</h3>(' + gettext('click to close') + ')</div>'); diff --git a/askbot/media/js/wmd/showdown.js b/askbot/media/js/wmd/showdown.js index 257b8bd1..25872e48 100644 --- a/askbot/media/js/wmd/showdown.js +++ b/askbot/media/js/wmd/showdown.js @@ -155,7 +155,7 @@ var makeHtmlBase = function(text) { } this.makeHtml = function(text){ - if (enableMathJax === false){ + if (askbot['settings']['mathjaxEnabled'] === false){ return makeHtmlBase(text); } else { diff --git a/askbot/media/js/wmd/wmd.js b/askbot/media/js/wmd/wmd.js index 5aeacd98..91d98694 100644 --- a/askbot/media/js/wmd/wmd.js +++ b/askbot/media/js/wmd/wmd.js @@ -122,7 +122,7 @@ Attacklab.wmdBase = function(){ // Adds a listener callback to a DOM element which is fired on a specified // event. util.addEvent = function(elem, event, listener){ - if (elem.attachEvent) { + if (elem && elem.attachEvent) { // IE only. The "on" is mandatory. elem.attachEvent("on" + event, listener); } diff --git a/askbot/media/style/lib_style.less b/askbot/media/style/lib_style.less index 05ab38f5..5e454173 100644 --- a/askbot/media/style/lib_style.less +++ b/askbot/media/style/lib_style.less @@ -17,29 +17,6 @@ @main-font:'Open Sans Condensed', Arial, sans-serif; @secondary-font:Arial; -/* Buttons */ - -.button-style(@h:20px, @f:14px){ - height:@h; - font-size:@f; - text-align:center; - text-decoration:none; - cursor:pointer; - color:@button-label; - font-family:@main-font; - .text-shadow(0px,1px,0px,#c6d9dd); - border-top:#eaf2f3 1px solid; - .linear-gradient(#d1e2e5,#a9c2c7); - .rounded-corners(4px); - .box-shadow(1px, 1px, 2px, #636363) -} - -.button-style-hover{ - .linear-gradient(#cde5e9,#94b3ba); - text-decoration:none; - .text-shadow(0px, 1px, 0px, #c6d9dd); -} - /* General styles for gradients */ .linear-gradient(@start:#eee,@end:#fff,@stop:25%){ diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css index a53ebf37..3c447e56 100644 --- a/askbot/media/style/style.css +++ b/askbot/media/style/style.css @@ -3,21 +3,6 @@ /* Variables for Colors*/ /* Variables for fonts*/ /* "Trebuchet MS", sans-serif;*/ -/* Buttons */ -.button-style-hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} /* General styles for gradients */ /* Receive exactly positions for background Sprite */ /* CSS3 Elements */ @@ -67,6 +52,9 @@ select { font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif; margin-left: 0px; } +select { + width: 100%; +} input[type="text"].prompt, input[type="password"].prompt, input.tipped-input.blank { @@ -214,7 +202,7 @@ body.user-messages { } .wait-icon-box { text-align: center; - margin-bottom: 8px; + margin: 5px 0 8px; } #closeNotify { position: absolute; @@ -474,9 +462,9 @@ body.user-messages { width: 100%; margin: 8px 0 6px 0; padding: 0; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; } #searchBar div.input-tool-tip { margin-top: -40px; @@ -502,6 +490,7 @@ body.user-messages { padding: 0 0 10px 0; margin: 0; position: relative; + width: 100%; } .search-drop-menu ul li { padding: 5px 10px; @@ -521,10 +510,10 @@ body.user-messages { } .search-drop-menu .footer { text-align: center; - padding-bottom: 10px; + padding: 9px 0 10px 0; } .search-drop-menu.empty ul { - padding: 5px; + padding: 1px; margin: 0; } .input-tool-tip { @@ -542,13 +531,30 @@ input[type="submit"].searchBtn { line-height: 22px; text-align: center; float: right; - margin: 7px 28px 0 0; + margin: -39px -48px 0 0; width: 48px; - background: -98px -36px url(../images/sprites.png) no-repeat; + background: -98px -37px url(../images/sprites.png) no-repeat; + border-radius: 0; + -ms-border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + -khtml-border-radius: 0; + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; cursor: pointer; position: relative; z-index: 10001; } +.groups-page input[type="submit"].searchBtn, +.tags-page input[type="submit"].searchBtn, +.badges-pages input[type="submit"].searchBtn, +.user-profile-page input[type="submit"].searchBtn, +.meta input[type="submit"].searchBtn, +.openid-signin input[type="submit"].searchBtn, +.users-page input[type="submit"].searchBtn { + margin-top: 1px; +} .ask-page input[type="submit"].searchBtn { display: none; } @@ -564,45 +570,58 @@ input[type="submit"].searchBtn { .ask-page .search-drop-menu.empty ul { padding: 0; } -.searchBtn:hover { - background: -146px -36px url(../images/sprites.png) no-repeat; -} -.cancelSearchBtn { - font-size: 30px; - color: #ce8888; - background: #fff; - height: 41px; - line-height: 42px; +input[type="submit"].searchBtn:hover { + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background: -146px -37px url(../images/sprites.png) no-repeat; +} +input[type="button"].cancelSearchBtn { + font-size: 30px !important; + color: #aaa; + background: #fff !important; + height: 37px !important; + line-height: 37px; border: 0px; - border-left: #deded0 1px solid; + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; + border-radius: 0; + -ms-border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + -khtml-border-radius: 0; text-align: center; - width: 35px; + width: 35px !important; cursor: pointer; float: right; - margin-top: 7px; + margin: -40px 0 0 0; position: relative; z-index: 10001; } .cancelSearchBtn:hover { color: #d84040; } -#askButton { - /* check blocks/secondary_header.html and widgets/ask_button.html*/ - - line-height: 44px; - margin-top: 6px; - float: right; - text-transform: uppercase; - height: 42px; - font-size: 20px; - text-align: center; - text-decoration: none; +button, +input[type="submit"], +input[type="button"], +input[type="reset"], +.button { cursor: pointer; color: #4a757f; + height: 27px; font-family: 'Open Sans Condensed', Arial, sans-serif; + font-size: 14px; + font-weight: bold; + text-align: center; + text-decoration: none; text-shadow: 0px 1px 0px #c6d9dd; -moz-text-shadow: 0px 1px 0px #c6d9dd; -webkit-text-shadow: 0px 1px 0px #c6d9dd; + border: 0 !important; border-top: #eaf2f3 1px solid; background-color: #d1e2e5; background-repeat: no-repeat; @@ -620,11 +639,20 @@ input[type="submit"].searchBtn { -webkit-box-shadow: 1px 1px 2px #636363; -moz-box-shadow: 1px 1px 2px #636363; box-shadow: 1px 1px 2px #636363; - width: 200px; - /* to match width of sidebar */ - } -#askButton:hover { +button.large, +input[type="submit"].large, +input[type="button"].large, +input[type="reset"].large, +.button.large { + font-size: 20px; + height: 35px; + line-height: 35px; + padding: 0 10px; +} +button:hover, +input[type="submit"]:hover, +.button:hover { background-color: #cde5e9; background-repeat: no-repeat; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); @@ -638,6 +666,31 @@ input[type="submit"].searchBtn { -moz-text-shadow: 0px 1px 0px #c6d9dd; -webkit-text-shadow: 0px 1px 0px #c6d9dd; } +input[type="submit"].link { + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; + text-shadow: 0 0 0 #929292; + -moz-text-shadow: 0 0 0 #929292; + -webkit-text-shadow: 0 0 0 #929292; + font-weight: normal; +} +input[type="submit"].link:hover { + text-decoration: underline; +} +#askButton { + /* check blocks/secondary_header.html and widgets/ask_button.html*/ + + float: right; + font-size: 20px; + height: 42px; + line-height: 44px; + margin-top: 6px; + text-transform: uppercase; + width: 200px; + /* to match width of sidebar */ + +} /* Put the secondary navigation together: 1) raise the search bar by 55px @@ -658,14 +711,47 @@ input[type="submit"].searchBtn { body.anon.ask-page .search-drop-menu { margin: 0; } -body.anon #searchBar, -body.anon .search-drop-menu { - margin-left: 227px; - /* we don't have the "followed" scope */ - +#scopeNav { + height: 41px; + float: left; + width: 280px; +} +.scopes-True-True-False #searchBar, +.scopes-True-True-False .search-drop-menu { + margin-left: 228px; +} +.scopes-True-True-False #scopeNav { + width: 180px; +} +.scopes-True-False-True #searchBar, +.scopes-True-False-True .search-drop-menu { + margin-left: 203px; +} +.scopes-True-False-True #scopeNav { + width: 150px; } -#searchBar.cancelable { - padding-right: 82px; +.scopes-False-True-True #searchBar, +.scopes-False-True-True .search-drop-menu { + margin-left: 286px; +} +.scopes-False-True-True #scopeNav { + width: 238px; +} +.scopes-True-False-False #searchBar, +.scopes-False-True-False #searchBar, +.scopes-False-False-True #searchBar, +.scopes-False-False-False #searchBar, +.scopes-True-False-False .search-drop-menu, +.scopes-False-True-False .search-drop-menu, +.scopes-False-False-True .search-drop-menu, +.scopes-False-False-False .search-drop-menu { + margin-left: 52px; +} +.scopes-True-False-False #scopeNav, +.scopes-False-True-False #scopeNav, +.scopes-False-False-True #scopeNav, +.scopes-False-False-False #scopeNav { + width: 0; } /* ----- Content layout, check two_column_body.html or one_column_body.html ----- */ #ContentLeft { @@ -686,8 +772,9 @@ body.anon .search-drop-menu { /* ----- Sidebar Widgets Box, check main_page/sidebar.html or question/sidebar.html ----- */ .box { background: #fff; - padding: 4px 0px 10px 0px; + padding: 4px 0px 10px 1px; width: 200px; + overflow: hidden; /* widgets for question template */ /* notify by email box */ @@ -785,56 +872,7 @@ body.anon .search-drop-menu { .box .inputs #subscribedTagAdd, .box .inputs #ab-tag-search-add { border: 0; - font-weight: bold; margin-top: -2px; - height: 27px; - font-size: 14px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; -} -.box .inputs #interestingTagAdd:hover, -.box .inputs #ignoredTagAdd:hover, -.box .inputs #ab-tag-search-add:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; } .box .inputs #ab-tag-search-add { width: 47px; @@ -844,60 +882,17 @@ body.anon .search-drop-menu { } .box a.followed, .box a.follow { + height: 34px; + font-size: 21px; line-height: 34px; border: 0; font-weight: normal; margin-top: 3px; display: block; - height: 34px; - font-size: 21px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; margin: 0 auto; padding: 0; width: 130px; } -.box a.followed:hover, -.box a.follow:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} .box a.followed div.unfollow { display: none; } @@ -1341,7 +1336,7 @@ ul.tags.marked-tags, ul#related-tags { list-style: none; margin: 0; - padding: 0; + padding: 0 0 0 1px; line-height: 170%; display: block; } @@ -1360,9 +1355,7 @@ ul.tags.marked-tags li, margin-bottom: 5px; } #tagSelector div.inputs { - clear: both; - float: none; - margin-bottom: 10px; + margin: 6px 0 12px 0; } .tags-page ul.tags li, ul#ab-user-tags li { @@ -1670,40 +1663,7 @@ ul#related-tags li { .add-groups, .add-users { border: 0; - font-weight: bold; margin-top: -2px; - height: 27px; - font-size: 14px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; } .share-input-col { width: 160px; @@ -1716,20 +1676,6 @@ ul#related-tags li { padding: 0 10px; height: 25px; } -.add-groups:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} #id_user, #id_user_author { border: #cce6ec 3px solid; @@ -1749,40 +1695,7 @@ ul#related-tags li { .add-groups, .add-users { border: 0; - font-weight: bold; margin-top: -2px; - height: 27px; - font-size: 14px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; } .add-everyone-group { text-align: center; @@ -1790,20 +1703,6 @@ ul#related-tags li { display: block; padding: 0 10px; } -.add-groups:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} #id_user, #id_user_author { border: #cce6ec 3px solid; @@ -1830,55 +1729,11 @@ ul#related-tags li { .edit-question-page input.submit { float: left; font-weight: normal; + height: 35px; + font-size: 20px; margin-top: 3px; - height: 34px; - font-size: 21px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; margin-right: 7px; } -#fmanswer input.submit:hover, -.ask-page input.submit:hover, -.edit-question-page input.submit:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} .wmd-container { border: #cce6ec 3px solid; } @@ -1886,7 +1741,7 @@ ul#related-tags li { border: none; } .users-page .wmd-container { - width: 200px; + width: auto; } .ask-page .wmd-container, .question-page .wmd-container, @@ -1923,7 +1778,7 @@ ul#related-tags li { border: 0; } .users-page #editor { - width: 192px; + width: 187px; } #id_title { width: 100%; @@ -2190,7 +2045,8 @@ ul#related-tags li { margin-top: 10px; margin-bottom: 8px; } -.question-page .post-controls a { +.question-page .post-controls a, +.question-page .post-controls span.dropdown-toggle { color: #777; padding: 0px 7px 3px 18px; cursor: pointer; @@ -2199,19 +2055,58 @@ ul#related-tags li { font-family: Arial; text-decoration: none; height: 18px; - display: block; - float: right; line-height: 18px; margin-top: -2px; margin-left: 4px; } -.question-page .post-controls a:hover { +.question-page .post-controls a:hover, +.question-page .post-controls span.dropdown-toggle:hover { background-color: #f5f0c9; +} +.question-page .post-controls span.dropdown-toggle { + background: url(../images/sprites.png) no-repeat -7px -242px; border-radius: 3px; -ms-border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px; + position: relative; +} +.question-page .post-controls span.dropdown-toggle:hover { + padding-right: 0; + background: url(../images/sprites.png) no-repeat -7px -274px; +} +.question-page .post-controls span.dropdown-toggle:hover form { + margin: 0; +} +.question-page .post-controls span.dropdown-toggle:hover input { + display: block !important; + height: 20px !important; + line-height: 20px !important; + margin: 0; + padding: 0 5px; + border-radius: 0; + -ms-border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + -khtml-border-radius: 0; + width: 100% !important; +} +.question-page .post-controls span.dropdown-toggle:hover .dropdown-menu { + display: block; + padding: 5px 0; + right: -5px !important; + left: auto; +} +.question-page .post-controls span.dropdown-toggle:hover .dropdown-menu li, +.question-page .post-controls span.dropdown-toggle:hover .dropdown-menu li:hover { + display: block !important; + margin: 0; + padding: 0; + width: 100% !important; +} +.question-page .post-controls span.dropdown-toggle:hover .dropdown-menu li:hover { + background-color: #f5f0c9; } .question-page .post-controls .sep { color: #ccc; @@ -2221,12 +2116,12 @@ ul#related-tags li { } .question-page .post-controls .question-delete, .question-page .answer-controls .question-delete { - background: url(../images/delete.png) no-repeat left 2px; + background: url(../images/delete.png) no-repeat left -1px; padding-left: 11px; } .question-page .post-controls .question-flag, .question-page .answer-controls .question-flag { - background: url(../images/flag.png) no-repeat center left; + background: url(../images/flag.png) no-repeat 2px 0; } .question-page .post-controls .answer-publish, .question-page .answer-controls .answer-publish { @@ -2238,7 +2133,7 @@ ul#related-tags li { } .question-page .post-controls .question-edit, .question-page .answer-controls .question-edit { - background: url(../images/edit2.png) no-repeat 2px center; + background: url(../images/edit2.png) no-repeat 3px 1px; } .question-page .post-controls .question-retag, .question-page .answer-controls .question-retag { @@ -2250,7 +2145,7 @@ ul#related-tags li { } .question-page .post-controls .permant-link, .question-page .answer-controls .permant-link { - background: url(../images/link.png) no-repeat center left; + background: url(../images/link.png) no-repeat 2px 1px; } .question-page .post-controls .answer-convert, .question-page .answer-controls .answer-convert { @@ -2351,14 +2246,21 @@ ul#related-tags li { margin: 3px 0 20px 5px; } .question-page .comments .controls a { + border: none; color: #988e4c; - padding: 0 3px 2px 22px; + padding: 0 3px 5px 22px; font-family: Arial; font-size: 13px; + font-weight: normal; background: url(../images/comment.png) no-repeat center left; + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; + text-shadow: 0 0 0 #929292; + -moz-text-shadow: 0 0 0 #929292; + -webkit-text-shadow: 0 0 0 #929292; } .question-page .comments .controls a:hover { - background-color: #f5f0c9; text-decoration: none; } .question-page .comments .button { @@ -2373,24 +2275,22 @@ ul#related-tags li { padding: 0; } .question-page .comments form.post-comments { - margin: 3px 26px 0 42px; -} -.question-page .comments form.post-comments textarea { - font-size: 13px; - line-height: 1.3; + padding: 6px 6px 7px 42px; + border-bottom: 1px solid #edeeeb; + margin-bottom: 0; } .question-page .comments textarea { - height: 42px; - width: 100%; - margin: 7px 0 5px 1px; + box-sizing: border-box; + border: #cce6ec 3px solid; font-family: Arial; + font-size: 13px; + height: 54px; + line-height: 1.3; + margin: -1px 0 7px 1px; outline: none; overflow: auto; - font-size: 12px; - line-height: 140%; - padding-left: 2px; - padding-top: 3px; - border: #cce6ec 3px solid; + padding: 0px 19px 2px 3px; + width: 100%; } .question-page .comments input { margin-left: 10px; @@ -2398,52 +2298,11 @@ ul#related-tags li { vertical-align: top; width: 100px; } -.question-page .comments button { - line-height: 25px; - margin-bottom: 5px; - height: 27px; - font-size: 12px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - font-family: Arial; - font-weight: bold; -} -.question-page .comments button:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; +.question-page .comments button.submit { + height: 26px; + line-height: 26px; + padding: 0 8px; + margin-right: 6px; } .question-page .comments .counter { display: inline-block; @@ -2459,18 +2318,11 @@ ul#related-tags li { border-bottom: 1px solid #edeeeb; clear: both; margin: 0; - margin-top: 8px; padding-bottom: 4px; overflow: auto; font-family: Arial; font-size: 11px; min-height: 25px; - background: #ffffff url(../images/comment-background.png) bottom repeat-x; - border-radius: 5px; - -ms-border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - -khtml-border-radius: 5px; } .question-page .comments div.comment:hover { background-color: #efefef; @@ -2527,12 +2379,19 @@ ul#related-tags li { padding: 0px; color: #1B79BD; border: none; + height: 13px; width: auto; font-family: Arial; - line-height: 14px; - margin-left: 6px; font-size: 13px; - box-shadow: none; + font-weight: normal; + line-height: 13px; + margin: 0 0 0 8px; + -webkit-box-shadow: 0 0 0 #929292; + -moz-box-shadow: 0 0 0 #929292; + box-shadow: 0 0 0 #929292; + text-shadow: 0 0 0 #929292; + -moz-text-shadow: 0 0 0 #929292; + -webkit-text-shadow: 0 0 0 #929292; } .question-page .comments .comment-body .convert-comment input:hover { text-decoration: underline; @@ -2814,52 +2673,6 @@ ul#related-tags li { .user-profile-page input.submit { font-weight: normal; margin: 5px 0px; - height: 26px; - font-size: 15px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - font-family: Arial; -} -.openid-signin input.submit:hover, -.meta input.submit:hover, -.users-page input.submit:hover, -.user-profile-edit-page input.submit:hover, -.user-profile-page input.submit:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; } .openid-signin .cancel, .meta .cancel, @@ -2884,6 +2697,15 @@ ul#related-tags li { float: left; width: 960px; } +.user-profile-page.inbox-group-join-requests form { + margin-bottom: 0; +} +.user-profile-page.inbox-group-join-requests table { + margin-bottom: 13px; +} +.user-profile-page.inbox-group-join-requests td { + padding-right: 10px; +} .inbox-flags.user-profile-page .re { width: 810px; } @@ -2925,59 +2747,6 @@ ul#related-tags li { border: #cce6ec 3px solid; width: 200px; } -#email-input-fs .submit-b, -#local_login_buttons .submit-b, -#password-fs .submit-b, -#openid-fs .submit-b { - height: 24px; - font-size: 15px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; - font-family: Arial; - font-weight: bold; - padding-right: 10px; - border: 0; -} -#email-input-fs .submit-b:hover, -#local_login_buttons .submit-b:hover, -#password-fs .submit-b:hover, -#openid-fs .submit-b:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; -} .openid-input { background: url(../images/openid.gif) no-repeat; padding-left: 15px; @@ -3086,64 +2855,6 @@ a:hover.medal { margin-top: 10px; margin-bottom: 10px; } -.user-profile-page .inputs input[type='submit'] { - height: 26px; - font-size: 15px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; -} -.user-profile-page input[type='submit'].select-language { - height: 26px; - font-size: 15px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; -} .user-profile-page select { margin-bottom: 12px; } @@ -3164,54 +2875,17 @@ a:hover.medal { .user-about p { font-size: 13px; } +.follow-toggle { + height: auto; +} .follow-toggle, .submit { - border: 0 !important; font-weight: bold; line-height: 26px; margin-top: -2px; - height: 26px; - font-size: 14px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; } .follow-toggle:hover, .submit:hover { - background-color: #cde5e9; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba)); - background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba); - background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba); - text-decoration: none; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; text-decoration: none !important; } .follow-toggle .follow { @@ -4530,35 +4204,6 @@ textarea.tipped-input { border-spacing: 10px; border-collapse: separate; } -.tag-subscriptions button { - height: 27px; - font-size: 14px; - text-align: center; - text-decoration: none; - cursor: pointer; - color: #4a757f; - font-family: 'Open Sans Condensed', Arial, sans-serif; - text-shadow: 0px 1px 0px #c6d9dd; - -moz-text-shadow: 0px 1px 0px #c6d9dd; - -webkit-text-shadow: 0px 1px 0px #c6d9dd; - border-top: #eaf2f3 1px solid; - background-color: #d1e2e5; - background-repeat: no-repeat; - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7)); - background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7); - border-radius: 4px; - -ms-border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - -khtml-border-radius: 4px; - -webkit-box-shadow: 1px 1px 2px #636363; - -moz-box-shadow: 1px 1px 2px #636363; - box-shadow: 1px 1px 2px #636363; -} .tag-subscriptions form { display: inline-block; margin-bottom: 0; diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less index 0857f551..85b18ac1 100644 --- a/askbot/media/style/style.less +++ b/askbot/media/style/style.less @@ -38,6 +38,9 @@ input, select { font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif; margin-left:0px; } +select { + width: 100%; +} input[type="text"].prompt, input[type="password"].prompt, @@ -215,7 +218,7 @@ body.user-messages { .wait-icon-box { text-align: center; - margin-bottom: 8px; + margin: 5px 0 8px; } #closeNotify { @@ -507,9 +510,7 @@ body.user-messages { width: 100%; margin: 8px 0 6px 0; padding: 0; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; + .box-shadow(0, 0, 0); } div.input-tool-tip { @@ -538,6 +539,7 @@ body.user-messages { padding: 0 0 10px 0; margin: 0; position: relative; + width: 100%; li { padding: 5px 10px; position: relative; @@ -559,13 +561,13 @@ body.user-messages { .footer { text-align: center; - padding-bottom: 10px; + padding: 9px 0 10px 0; } } .search-drop-menu.empty { ul { - padding: 5px; + padding: 1px; margin: 0; } } @@ -586,13 +588,28 @@ input[type="submit"].searchBtn { line-height: 22px; text-align: center; float:right; - margin: 7px 28px 0 0; + margin: -39px -48px 0 0; width: 48px; - .sprites(-98px,-36px); + .sprites(-98px,-37px); + .rounded-corners(0); + .box-shadow(0, 0, 0); cursor:pointer; position: relative; z-index: 10001; } + +.groups-page, /* todo: clean up - should not need this */ +.tags-page, +.badges-pages, +.user-profile-page, +.meta, +.openid-signin, +.users-page { + input[type="submit"].searchBtn { + margin-top: 1px; + } +} + .ask-page { input[type="submit"].searchBtn { display: none; @@ -611,23 +628,30 @@ input[type="submit"].searchBtn { } } -.searchBtn:hover { - .sprites(-98px-48,-36px); +input[type="submit"].searchBtn:hover { + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + .sprites(-98px-48,-37px); } -.cancelSearchBtn { - font-size: 30px; - color: #ce8888; - background:#fff; - height: 41px; - line-height: 42px; - border:0px; - border-left:#deded0 1px solid; +input[type="button"].cancelSearchBtn { + font-size: 30px !important; + color: #aaa; + background: #fff !important; + height: 37px !important; + line-height: 37px; + border: 0px; + .box-shadow(0, 0, 0); + .rounded-corners(0); text-align: center; - width: 35px; + width: 35px !important; cursor:pointer; float: right; - margin-top: 7px; + margin: -40px 0 0 0; position: relative; z-index: 10001; } @@ -636,17 +660,63 @@ input[type="submit"].searchBtn { color: #d84040; } -#askButton{ /* check blocks/secondary_header.html and widgets/ask_button.html*/ - line-height:44px; - margin-top:6px; - float:right; - text-transform:uppercase; - .button-style(42px, 20px); - width: 200px;/* to match width of sidebar */ +button, +input[type="submit"], +input[type="button"], +input[type="reset"], +.button { + cursor: pointer; + color: @button-label; + height: 27px; + font-family: @main-font; + font-size: 14px; + font-weight: bold; + text-align: center; + text-decoration: none; + .text-shadow(0px,1px,0px,#c6d9dd); + border: 0 !important; + border-top: #eaf2f3 1px solid; + .linear-gradient(#d1e2e5,#a9c2c7); + .rounded-corners(4px); + .box-shadow(1px, 1px, 2px, #636363) +} +button.large, +input[type="submit"].large, +input[type="button"].large, +input[type="reset"].large, +.button.large { + font-size: 20px; + height: 35px; + line-height: 35px; + padding: 0 10px; } -#askButton:hover{ - .button-style-hover; +button:hover, +input[type="submit"]:hover, +.button:hover { + .linear-gradient(#cde5e9,#94b3ba); + text-decoration:none; + .text-shadow(0px, 1px, 0px, #c6d9dd); +} + +input[type="submit"].link { + .box-shadow(0, 0, 0); + .text-shadow(0, 0, 0); + font-weight: normal; +} + +input[type="submit"].link:hover { + text-decoration: underline; +} + +#askButton { /* check blocks/secondary_header.html and widgets/ask_button.html*/ + float:right; + font-size: 20px; + height: 42px; + line-height: 44px; + margin-top: 6px; + text-transform: uppercase; + width: 200px;/* to match width of sidebar */ } /* @@ -669,16 +739,50 @@ input[type="submit"].searchBtn { body.anon.ask-page .search-drop-menu { margin: 0; } -body.anon { +#scopeNav { + height: 41px; + float: left; + width: 280px; +} +.scopes-True-True-False { #searchBar, .search-drop-menu { - margin-left: 227px;/* we don't have the "followed" scope */ + margin-left: 228px; + } + #scopeNav { + width: 180px; } } -#searchBar.cancelable { - padding-right: 82px; +.scopes-True-False-True { + #searchBar, + .search-drop-menu { + margin-left: 203px; + } + #scopeNav { + width: 150px; + } +} +.scopes-False-True-True { + #searchBar, + .search-drop-menu { + margin-left: 286px; + } + #scopeNav { + width: 238px; + } +} +.scopes-True-False-False, +.scopes-False-True-False, +.scopes-False-False-True, +.scopes-False-False-False { + #searchBar, + .search-drop-menu { + margin-left: 52px; + } + #scopeNav { + width: 0; + } } - /* ----- Content layout, check two_column_body.html or one_column_body.html ----- */ @@ -704,8 +808,9 @@ body.anon { .box { background: #fff; - padding: 4px 0px 10px 0px; + padding: 4px 0px 10px 1px; width:200px; + overflow: hidden; p { margin-bottom: 4px; @@ -806,16 +911,8 @@ body.anon { #subscribedTagAdd, #ab-tag-search-add { border:0; - font-weight:bold; margin-top:-2px; - .button-style(27px, 14px); - .rounded-corners(4px); } - #interestingTagAdd:hover, - #ignoredTagAdd:hover, - #ab-tag-search-add:hover { - .button-style-hover; - } #ab-tag-search-add { width: 47px; } @@ -828,21 +925,17 @@ body.anon { /* widgets for question template */ a.followed, a.follow{ + height: 34px; + font-size: 21px; line-height:34px; border:0; font-weight:normal; margin-top:3px; display:block; - .button-style(34px,21px); .center; width: 130px; } - a.followed:hover, a.follow:hover{ - .button-style-hover; - .text-shadow(0px, 1px, 0px, #c6d9dd); - } - a.followed div.unfollow{ display:none; } @@ -1340,7 +1433,7 @@ ul.tags.marked-tags, ul#related-tags { list-style: none; margin: 0; - padding: 0; + padding: 0 0 0 1px; line-height: 170%; display: block; } @@ -1363,9 +1456,7 @@ ul.tags.marked-tags li, } #tagSelector div.inputs { - clear: both; - float: none; - margin-bottom:10px; + margin: 6px 0 12px 0; } .tags-page ul.tags li, @@ -1666,10 +1757,7 @@ ul#related-tags li { .add-groups, .add-users { border:0; - font-weight:bold; margin-top:-2px; - .button-style(27px, 14px); - .rounded-corners(4px); } .share-input-col { @@ -1685,10 +1773,6 @@ ul#related-tags li { height: 25px; } -.add-groups:hover { - .button-style-hover; -} - #id_user, #id_user_author { border:#cce6ec 3px solid; @@ -1710,10 +1794,7 @@ ul#related-tags li { .add-groups, .add-users { border:0; - font-weight:bold; margin-top:-2px; - .button-style(27px, 14px); - .rounded-corners(4px); } .add-everyone-group { @@ -1723,10 +1804,6 @@ ul#related-tags li { padding: 0 10px; } -.add-groups:hover { - .button-style-hover; -} - #id_user, #id_user_author { border:#cce6ec 3px solid; @@ -1755,18 +1832,12 @@ ul#related-tags li { .edit-question-page input.submit { float: left; font-weight:normal; + height: 35px; + font-size: 20px; margin-top:3px; - .button-style(34px,21px); margin-right:7px; } -#fmanswer input.submit:hover, -.ask-page input.submit:hover, -.edit-question-page input.submit:hover{ - .button-style-hover; - .text-shadow(0px, 1px, 0px, #c6d9dd) -} - .wmd-container { border:#cce6ec 3px solid; textarea { @@ -1774,7 +1845,7 @@ ul#related-tags li { } } .users-page .wmd-container { - width: 200px; + width: auto; } .ask-page, .question-page, @@ -1813,7 +1884,7 @@ ul#related-tags li { } .users-page #editor { - width: 192px; + width: 187px; } #id_title { @@ -2278,22 +2349,25 @@ ul#related-tags li { clear: both; div.controls { - clear: both; + clear: both; float:left; width: 100%; margin: 3px 0 20px 5px; } .controls a { - color: #988e4c; - padding: 0 3px 2px 22px; - font-family:@body-font; - font-size:13px; - background:url(../images/comment.png) no-repeat center left; + border: none; + color: #988e4c; + padding: 0 3px 5px 22px; + font-family: @body-font; + font-size: 13px; + font-weight: normal; + background: url(../images/comment.png) no-repeat center left; + .box-shadow(0, 0, 0); + .text-shadow(0, 0, 0); } .controls a:hover { - background-color: #f5f0c9; text-decoration: none; } @@ -2310,28 +2384,24 @@ ul#related-tags li { } form.post-comments { - margin: 3px 26px 0 42px; - textarea{ - font-size: 13px; - line-height: 1.3; - - } + padding: 6px 6px 7px 42px; + border-bottom: 1px solid #edeeeb; + margin-bottom: 0; } textarea { - height: 42px; - width:100%; - margin: 7px 0 5px 1px; + box-sizing: border-box; + border: #cce6ec 3px solid; font-family: @body-font; + font-size: 13px; + height: 54px; + line-height: 1.3; + margin: -1px 0 7px 1px; outline: none; overflow:auto; - font-size: 12px; - line-height: 140%; - padding-left:2px; - padding-top:3px; - border:#cce6ec 3px solid; + padding: 0px 19px 2px 3px; + width:100%; } - input { margin-left: 10px; margin-top: 1px; @@ -2347,15 +2417,11 @@ ul#related-tags li { vertical-align: top; } - button{ - line-height:25px; - margin: 0 10px 5px -2px; - .button-style(27px, 12px); - font-family:@body-font; - font-weight:bold; - } - button:hover{ - .button-style-hover; + button.submit { + height: 26px; + line-height: 26px; + padding: 0 8px; + margin-right: 6px; } .counter { display: inline-block; @@ -2368,12 +2434,12 @@ ul#related-tags li { } .comment { border-bottom: 1px solid #edeeeb; - clear:both; + clear: both; margin: 0; - padding-bottom:4px; + padding-bottom: 4px; overflow: auto; - font-family:@body-font; - font-size:11px; + font-family: @body-font; + font-size: 11px; min-height: 25px; } div.comment:hover { @@ -2421,29 +2487,32 @@ ul#related-tags li { padding-left:6px; } - .convert-comment{ - display: inline; - white-space: nowrap; - padding-left: 0px; - } + .convert-comment { + display: inline; + white-space: nowrap; + padding-left: 0px; + input { + background: none; + padding: 0px; + color: #1B79BD; + border:none; + height: 13px; + width:auto; + font-family: Arial; + font-size: 13px; + font-weight: normal; + line-height: 13px; + margin: 0 0 0 8px; + .box-shadow(0, 0, 0); + .text-shadow(0, 0, 0); + } - .convert-comment input{ - background: none; - padding: 0px; - color: #1B79BD; - border:none; - width:auto; - font-family: Arial; - line-height: 14px; - margin-left: 6px; - font-size: 13px; - box-shadow: none; + input:hover { + text-decoration: underline; + cursor: pointer; + } } - .convert-comment input:hover{ - text-decoration:underline; - cursor:pointer; - } } .comment-body p{ @@ -2727,11 +2796,6 @@ ul#related-tags li { input.submit{ font-weight:normal; margin:5px 0px; - .button-style(26px,15px); - font-family:@body-font; - } - input.submit:hover{ - .button-style-hover; } .cancel{ background:url(../images/small-button-cancel.png) repeat-x top !important; @@ -2746,6 +2810,18 @@ ul#related-tags li { } } +.user-profile-page.inbox-group-join-requests { + form { + margin-bottom: 0; + } + table { + margin-bottom: 13px; + } + td { + padding-right: 10px; + } +} + .inbox-flags.user-profile-page { .re { width: 810px; @@ -2778,17 +2854,6 @@ ul#related-tags li { border:#cce6ec 3px solid; width:200px; } - .submit-b{ - .button-style(24px,15px); - font-family:@body-font; - font-weight:bold; - padding-right:10px; - border:0; - } - - .submit-b:hover{ - .button-style-hover; - } } @@ -2920,12 +2985,6 @@ a:hover.medal { .inputs { margin-top: 10px; margin-bottom: 10px; - input[type='submit']{ - .button-style(26px,15px); - } - } - input[type='submit'].select-language { - .button-style(26px,15px); } select { margin-bottom: 12px; @@ -2949,16 +3008,17 @@ a:hover.medal { p{font-size:13px;} } +.follow-toggle { + height: auto; +} + .follow-toggle,.submit { - border:0 !important; font-weight:bold; line-height:26px; margin-top:-2px; - .button-style(26px,14px); } .follow-toggle:hover, .submit:hover { - .button-style-hover; text-decoration:none !important; } @@ -4352,10 +4412,6 @@ textarea.tipped-input { border-spacing: 10px; border-collapse: separate; - button { - .button-style(27px, 14px); - } - form { display: inline-block; margin-bottom: 0; diff --git a/askbot/migrations/0013_add_response_count__to_user.py b/askbot/migrations/0013_add_response_count__to_user.py index f3d724e3..68ac0c3c 100644 --- a/askbot/migrations/0013_add_response_count__to_user.py +++ b/askbot/migrations/0013_add_response_count__to_user.py @@ -3,6 +3,7 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): @@ -13,16 +14,12 @@ class Migration(SchemaMigration): a bit hacky but we have to do it as long as we keep patching auth models within the forum application """ - try: - db.add_column( - u'auth_user', - 'response_count', - self.gf('django.db.models.fields.IntegerField')(default=0, ), - keep_default=False - ) - except: - print 'probably already have column User.response_count' - pass + safe_add_column( + u'auth_user', + 'response_count', + self.gf('django.db.models.fields.IntegerField')(default=0, ), + keep_default=False + ) def backwards(self, orm): diff --git a/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py b/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py index f5f913da..f9a5b739 100644 --- a/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py +++ b/askbot/migrations/0014_rename_schema_from_forum_to_askbot.py @@ -10,19 +10,20 @@ app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__))) class Migration(SchemaMigration): def forwards(self, orm): - try: - db.rename_table('forum_anonymousanswer', 'askbot_anonymousanswer') - db.rename_table('forum_anonymousquestion', 'askbot_anonymousquestion') - db.rename_table('forum_emailfeedsetting', 'askbot_emailfeedsetting') - db.rename_table('forum_markedtag', 'askbot_markedtag') - db.rename_table('forum_questionview', 'askbot_questionview') - db.rename_table('forum_validationhash', 'askbot_validationhash') - except: - pass + if app_dir_name == 'forum': + try: + db.rename_table('forum_anonymousanswer', 'askbot_anonymousanswer') + db.rename_table('forum_anonymousquestion', 'askbot_anonymousquestion') + db.rename_table('forum_emailfeedsetting', 'askbot_emailfeedsetting') + db.rename_table('forum_markedtag', 'askbot_markedtag') + db.rename_table('forum_questionview', 'askbot_questionview') + db.rename_table('forum_validationhash', 'askbot_validationhash') + except: + pass def backwards(self, orm): - if app_dirname == 'forum': + if app_dir_name == 'forum': db.rename_table('askbot_anonymousanswer', 'forum_anonymousanswer') db.rename_table('askbot_anonymousquestion', 'forum_anonymousquestion') db.rename_table('askbot_emailfeedsetting', 'forum_emailfeedsetting') diff --git a/askbot/migrations/0018_add___status__field_to_user_model.py b/askbot/migrations/0018_add___status__field_to_user_model.py index 5a713866..b30f30d7 100644 --- a/askbot/migrations/0018_add___status__field_to_user_model.py +++ b/askbot/migrations/0018_add___status__field_to_user_model.py @@ -3,21 +3,19 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): # Adding field 'User.status' - try: - db.add_column( - u'auth_user', - 'status', - self.gf('django.db.models.fields.CharField')(default ='w', max_length = 2), - keep_default=False - ) - except: - pass + safe_add_column( + u'auth_user', + 'status', + self.gf('django.db.models.fields.CharField')(default ='w', max_length = 2), + keep_default=False + ) def backwards(self, orm): diff --git a/askbot/migrations/0026_add_seen_and_new_response_counts_to_user.py b/askbot/migrations/0026_add_seen_and_new_response_counts_to_user.py index 4cd05f83..8b6002bf 100644 --- a/askbot/migrations/0026_add_seen_and_new_response_counts_to_user.py +++ b/askbot/migrations/0026_add_seen_and_new_response_counts_to_user.py @@ -3,16 +3,14 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): # Adding fields - try: - db.add_column('auth_user', 'new_response_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) - db.add_column('auth_user', 'seen_response_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) - except: - pass + safe_add_column('auth_user', 'new_response_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + safe_add_column('auth_user', 'seen_response_count', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) def backwards(self, orm): # Deleting fields diff --git a/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py b/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py index 580c2f25..e5a10faf 100644 --- a/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py +++ b/askbot/migrations/0033_add__consecutive_days_visit_count__to__auth_user.py @@ -3,21 +3,19 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): # Adding field 'User.consecutive_days_visit_count' - try: - db.add_column( - u'auth_user', - 'consecutive_days_visit_count', - self.gf('django.db.models.fields.IntegerField')(default = 0, max_length = 2), - keep_default=False - ) - except: - pass + safe_add_column( + u'auth_user', + 'consecutive_days_visit_count', + self.gf('django.db.models.fields.IntegerField')(default = 0, max_length = 2), + keep_default=False + ) def backwards(self, orm): diff --git a/askbot/migrations/0035_add_country_fields_to_user.py b/askbot/migrations/0035_add_country_fields_to_user.py index 02dd404c..340883ba 100644 --- a/askbot/migrations/0035_add_country_fields_to_user.py +++ b/askbot/migrations/0035_add_country_fields_to_user.py @@ -3,17 +3,15 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): # Adding model country fields to the model auth_user - try: - db.add_column(u'auth_user', 'country', self.gf('django_countries.fields.CountryField')(max_length=2, blank=True, null=True)) - db.add_column(u'auth_user', 'show_country', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)) - except: - pass + safe_add_column(u'auth_user', 'country', self.gf('django_countries.fields.CountryField')(max_length=2, blank=True, null=True)) + safe_add_column(u'auth_user', 'show_country', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True)) def backwards(self, orm): diff --git a/askbot/migrations/0037_add_marked_tags_to_user_profile.py b/askbot/migrations/0037_add_marked_tags_to_user_profile.py index f10f53be..306e16e6 100644 --- a/askbot/migrations/0037_add_marked_tags_to_user_profile.py +++ b/askbot/migrations/0037_add_marked_tags_to_user_profile.py @@ -3,18 +3,16 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): - try: - # Adding field 'User.interesting_tags' - db.add_column(u'auth_user', 'interesting_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) - # Adding field 'User.ignored_tags' - db.add_column(u'auth_user', 'ignored_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) - except: - pass + # Adding field 'User.interesting_tags' + safe_add_column(u'auth_user', 'interesting_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) + # Adding field 'User.ignored_tags' + safe_add_column(u'auth_user', 'ignored_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) def backwards(self, orm): diff --git a/askbot/migrations/0038_add_tag_filter_strategies.py b/askbot/migrations/0038_add_tag_filter_strategies.py index c2596366..a24d12bf 100644 --- a/askbot/migrations/0038_add_tag_filter_strategies.py +++ b/askbot/migrations/0038_add_tag_filter_strategies.py @@ -4,29 +4,27 @@ from south.db import db from south.v2 import SchemaMigration from django.db import models from askbot import const +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): # Adding model country fields to the model auth_user - try: - db.add_column( - u'auth_user', - 'email_tag_filter_strategy', - self.gf( - 'django.db.models.fields.SmallIntegerField' - )(default = const.EXCLUDE_IGNORED) - ) - db.add_column( - u'auth_user', - 'display_tag_filter_strategy', - self.gf( - 'django.db.models.fields.SmallIntegerField' - )(default = const.INCLUDE_ALL) - ) - except: - pass + safe_add_column( + u'auth_user', + 'email_tag_filter_strategy', + self.gf( + 'django.db.models.fields.SmallIntegerField' + )(default = const.EXCLUDE_IGNORED) + ) + safe_add_column( + u'auth_user', + 'display_tag_filter_strategy', + self.gf( + 'django.db.models.fields.SmallIntegerField' + )(default = const.INCLUDE_ALL) + ) def backwards(self, orm): diff --git a/askbot/migrations/0043_add_temporal_extra_column_for_datamigration.py b/askbot/migrations/0043_add_temporal_extra_column_for_datamigration.py index 4a8140a4..7582dc04 100644 --- a/askbot/migrations/0043_add_temporal_extra_column_for_datamigration.py +++ b/askbot/migrations/0043_add_temporal_extra_column_for_datamigration.py @@ -3,14 +3,12 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): - try: - db.add_column(u'auth_user', 'avatar_type', self.gf('django.db.models.fields.CharField')(max_length=1, default='n'), keep_default=False) - except: - pass + safe_add_column(u'auth_user', 'avatar_type', self.gf('django.db.models.fields.CharField')(max_length=1, default='n'), keep_default=False) def backwards(self, orm): db.delete_column(u'auth_user', 'avatar_type') diff --git a/askbot/migrations/0122_auth_user__add_subscribed_tag_field.py b/askbot/migrations/0122_auth_user__add_subscribed_tag_field.py index d84666fb..7f7ff971 100644 --- a/askbot/migrations/0122_auth_user__add_subscribed_tag_field.py +++ b/askbot/migrations/0122_auth_user__add_subscribed_tag_field.py @@ -3,15 +3,13 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): - try: - # Adding field 'User.interesting_tags' - db.add_column(u'auth_user', 'subscribed_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) - except: - pass + # Adding field 'User.interesting_tags' + safe_add_column(u'auth_user', 'subscribed_tags', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) def backwards(self, orm): # Deleting field 'User.interesting_tags' diff --git a/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py b/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py index b5a1e0c9..11b891da 100644 --- a/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py +++ b/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py @@ -3,6 +3,7 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): @@ -10,14 +11,14 @@ class Migration(SchemaMigration): def forwards(self, orm): # Adding field 'Post.is_private' db.start_transaction() - db.add_column('askbot_post', 'is_private', - self.gf('django.db.models.fields.BooleanField')(default=False), - keep_default=False) + safe_add_column('askbot_post', 'is_private', + self.gf('django.db.models.fields.BooleanField')(default=False), + keep_default=False) # Adding field 'ReplyAddress.reply_action' - db.add_column('askbot_replyaddress', 'reply_action', - self.gf('django.db.models.fields.CharField')(default='auto_answer_or_comment', max_length=32), - keep_default=False) + safe_add_column('askbot_replyaddress', 'reply_action', + self.gf('django.db.models.fields.CharField')(default='auto_answer_or_comment', max_length=32), + keep_default=False) # Changing field 'ReplyAddress.post' db.alter_column('askbot_replyaddress', 'post_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['askbot.Post'])) @@ -26,7 +27,7 @@ class Migration(SchemaMigration): try: db.start_transaction() # Adding field 'User.interesting_tags' - db.add_column(u'auth_user', 'email_signature', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) + safe_add_column(u'auth_user', 'email_signature', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False) db.commit_transaction() except: db.rollback_transaction() diff --git a/askbot/migrations/0125_add_show_tags_field_to_user.py b/askbot/migrations/0125_add_show_tags_field_to_user.py index cb7ab2bd..fc299d18 100644 --- a/askbot/migrations/0125_add_show_tags_field_to_user.py +++ b/askbot/migrations/0125_add_show_tags_field_to_user.py @@ -3,6 +3,7 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): @@ -10,16 +11,13 @@ class Migration(SchemaMigration): def forwards(self, orm): # Adding model show_marked_tags fields to the model auth_user - try: - db.add_column( - u'auth_user', - 'show_marked_tags', - self.gf( - 'django.db.models.fields.BooleanField' - )(default=True, blank=True) - ) - except: - pass + safe_add_column( + u'auth_user', + 'show_marked_tags', + self.gf( + 'django.db.models.fields.BooleanField' + )(default=True, blank=True) + ) def backwards(self, orm): diff --git a/askbot/migrations/0126_add_field__auth_user__is_fake.py b/askbot/migrations/0126_add_field__auth_user__is_fake.py index e0928ed7..783d1e27 100644 --- a/askbot/migrations/0126_add_field__auth_user__is_fake.py +++ b/askbot/migrations/0126_add_field__auth_user__is_fake.py @@ -1,17 +1,14 @@ # -*- coding: utf-8 -*- from south.db import db from south.v2 import SchemaMigration +from askbot.migrations_api import safe_add_column class Migration(SchemaMigration): def forwards(self, orm): - try: - # Adding field 'User.is_fake' - db.add_column( - u'auth_user', 'is_fake', - self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) - except: - pass + safe_add_column( + u'auth_user', 'is_fake', + self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False) def backwards(self, orm): db.delete_column('auth_user', 'is_fake') diff --git a/askbot/migrations/__init__.py b/askbot/migrations/__init__.py index 86377b7b..b9683daf 100644 --- a/askbot/migrations/__init__.py +++ b/askbot/migrations/__init__.py @@ -1,5 +1,9 @@ from south.db import db from south.utils import ask_for_it_by_name +from south.v2 import SchemaMigration + +if not db.has_ddl_transactions: + SchemaMigration.no_dry_run = True # Terminal ANSI codes for printing colored text: # - http://code.google.com/p/testoob/source/browse/trunk/src/testoob/reporting/colored.py#20 @@ -67,3 +71,4 @@ def innodb_ready_rename_column(orm, models, table, old_column_name, new_column_n # INFO: ask_for_it_by_name() if equivalent to self.gf() which is usually used in migrations, e.g.: # db.alter_column('askbot_badgedata', 'slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)) db.alter_column(table, new_column_name, field) + db.clear_deferred_sql() diff --git a/askbot/migrations_api/__init__.py b/askbot/migrations_api/__init__.py index 0260f51b..2e172a99 100644 --- a/askbot/migrations_api/__init__.py +++ b/askbot/migrations_api/__init__.py @@ -13,14 +13,19 @@ def safe_add_column(table, column, column_data, keep_default = False): so, we need to add these columns here in separate transactions and roll back if they fail, if we want we could also record - which columns clash """ - try: - db.start_transaction() - db.add_column(table, column, column_data, keep_default = keep_default) - db.commit_transaction() - return True - except: - db.rollback_transaction() - return False + if db.backend_name=='mysql': + if len(db.execute('select column_name from information_schema.columns where table_name=%s and column_name=%s', params=[table, column])) == 0: + db.add_column(table, column, column_data, keep_default = keep_default) + + else: + try: + db.start_transaction() + db.add_column(table, column, column_data, keep_default = keep_default) + db.commit_transaction() + return True + except: + db.rollback_transaction() + return False def mysql_table_supports_full_text_search(table_name): diff --git a/askbot/models/question.py b/askbot/models/question.py index 51a7c24b..455b0845 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -336,12 +336,24 @@ class ThreadManager(BaseQuerySetManager): else: raise Exception('UNANSWERED_QUESTION_MEANING setting is wrong') - elif search_state.scope == 'favorite': - favorite_filter = models.Q(favorited_by=request_user) + elif search_state.scope == 'followed': + followed_filter = models.Q(favorited_by=request_user) if 'followit' in django_settings.INSTALLED_APPS: followed_users = request_user.get_followed_users() - favorite_filter |= models.Q(posts__post_type__in=('question', 'answer'), posts__author__in=followed_users) - qs = qs.filter(favorite_filter) + followed_filter |= models.Q(posts__post_type__in=('question', 'answer'), posts__author__in=followed_users) + + #a special case: "personalized" main page only == + #if followed is the only available scope + #if total number (regardless of users selections) + #followed questions is < than a pagefull - we should mix in a list of + #random questions + if askbot_settings.ALL_SCOPE_ENABLED == askbot_settings.UNANSWERED_SCOPE_ENABLED == False: + followed_question_count = qs.filter(followed_filter).distinct().count() + if followed_question_count < 30: + #here we mix in anything + followed_filter |= models.Q(deleted=False) + + qs = qs.filter(followed_filter) #user contributed questions & answers if search_state.author: diff --git a/askbot/models/signals.py b/askbot/models/signals.py index d538de76..f5187876 100644 --- a/askbot/models/signals.py +++ b/askbot/models/signals.py @@ -25,6 +25,16 @@ user_registered = django.dispatch.Signal(providing_args=['user',]) #todo: move this to authentication app user_logged_in = django.dispatch.Signal(providing_args=['session']) +new_answer_posted = django.dispatch.Signal( + providing_args=['answer', 'user', 'form_data'] +) +answer_edited = django.dispatch.Signal( + providing_args=['answer', 'user', 'form_data'] +) +answer_before_editing = django.dispatch.Signal( + providing_args=['answer', 'user', 'form'] +) + post_updated = django.dispatch.Signal( providing_args=[ 'post', diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py index 7b6b746c..efefbc40 100644 --- a/askbot/search/state_manager.py +++ b/askbot/search/state_manager.py @@ -9,6 +9,7 @@ from django.utils.encoding import smart_str import askbot import askbot.conf +from askbot.conf import settings as askbot_settings from askbot import const from askbot.utils.functions import strip_plus @@ -90,8 +91,11 @@ class SearchState(object): def __init__(self, scope, sort, query, tags, author, page, user_logged_in): # INFO: zip(*[('a', 1), ('b', 2)])[0] == ('a', 'b') - if (scope not in zip(*const.POST_SCOPE_LIST)[0]) or (scope == 'favorite' and not user_logged_in): - self.scope = const.DEFAULT_POST_SCOPE + if (scope not in zip(*const.POST_SCOPE_LIST)[0]) or (scope == 'followed' and not user_logged_in): + if user_logged_in: + self.scope = askbot_settings.DEFAULT_SCOPE_AUTHENTICATED + else: + self.scope = askbot_settings.DEFAULT_SCOPE_ANONYMOUS else: self.scope = scope diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py index 237a1280..3b41dfbd 100644 --- a/askbot/setup_templates/settings.py +++ b/askbot/setup_templates/settings.py @@ -116,6 +116,14 @@ MIDDLEWARE_CLASSES = ( 'askbot.middleware.spaceless.SpacelessMiddleware', ) +JINJA2_EXTENSIONS = ( + 'compressor.contrib.jinja2ext.CompressorExtension', +) + +COMPRESS_PRECOMPILERS = ( + ('text/less', 'lessc {infile} {outfile}'), +) + ROOT_URLCONF = os.path.basename(os.path.dirname(__file__)) + '.urls' @@ -161,6 +169,7 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.humanize', 'django.contrib.sitemaps', + 'django.contrib.messages', #'debug_toolbar', #'haystack', 'askbot', @@ -176,6 +185,8 @@ INSTALLED_APPS = ( 'followit', 'tinymce', #'avatar',#experimental use git clone git://github.com/ericflo/django-avatar.git$ + + 'compressor', ) @@ -234,6 +245,11 @@ CSRF_COOKIE_NAME = 'askbot_csrf' STATICFILES_DIRS = ( ('default/media', os.path.join(ASKBOT_ROOT, 'media')), ) +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', +) RECAPTCHA_USE_SSL = True @@ -248,7 +264,7 @@ TINYMCE_COMPRESSOR = True TINYMCE_SPELLCHECKER = False TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'default/media/js/tinymce/') -TINYMCE_URL = STATIC_URL + 'default/media/js/tinymce/' +#TINYMCE_JS_URL = STATIC_URL + 'default/media/js/tinymce/tiny_mce.js' TINYMCE_DEFAULT_CONFIG = { 'plugins': 'askbot_imageuploader,askbot_attachment', 'convert_urls': False, @@ -268,8 +284,16 @@ TINYMCE_DEFAULT_CONFIG = { 'theme_advanced_resizing': True, 'theme_advanced_resize_horizontal': False, 'theme_advanced_statusbar_location': 'bottom', + 'width': '730', 'height': '250' } #delayed notifications, time in seconds, 15 mins by default NOTIFICATION_DELAY_TIME = 60 * 15 + +GROUP_MESSAGING = { + 'BASE_URL_GETTER_FUNCTION': 'askbot.models.user_get_profile_url', + 'BASE_URL_PARAMS': {'section': 'messages', 'sort': 'inbox'} +} + +ASKBOT_MULTILINGUAL = False diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache index bd77e82e..61ee5993 100644 --- a/askbot/setup_templates/settings.py.mustache +++ b/askbot/setup_templates/settings.py.mustache @@ -163,6 +163,7 @@ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.humanize', 'django.contrib.sitemaps', + 'django.contrib.messages', #'debug_toolbar', #Optional, to enable haystack search #'haystack', @@ -250,10 +251,10 @@ HAYSTACK_SITECONF = 'askbot.search.haystack' #http://django-haystack.readthedocs.org/en/v1.2.7/settings.html HAYSTACK_SEARCH_ENGINE = 'simple' -TINYMCE_COMPRESSOR = True +TINYMCE_COMPRESSOR = True TINYMCE_SPELLCHECKER = False TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'default/media/js/tinymce/') -TINYMCE_URL = STATIC_URL + 'default/media/js/tinymce/' +#TINYMCE_JS_URL = STATIC_URL + 'default/media/js/tinymce/tiny_mce.js' TINYMCE_DEFAULT_CONFIG = { 'plugins': 'askbot_imageuploader,askbot_attachment', 'convert_urls': False, @@ -274,7 +275,7 @@ TINYMCE_DEFAULT_CONFIG = { 'theme_advanced_resizing': True, 'theme_advanced_resize_horizontal': False, 'theme_advanced_statusbar_location': 'bottom', - 'width': '723', + 'width': '730', 'height': '250' } @@ -285,3 +286,5 @@ GROUP_MESSAGING = { 'BASE_URL_GETTER_FUNCTION': 'askbot.models.user_get_profile_url', 'BASE_URL_PARAMS': {'section': 'messages', 'sort': 'inbox'} } + +ASKBOT_MULTILINGUAL = False diff --git a/askbot/setup_templates/urls.py b/askbot/setup_templates/urls.py index 35f1c5b3..4c76781b 100644 --- a/askbot/setup_templates/urls.py +++ b/askbot/setup_templates/urls.py @@ -30,7 +30,7 @@ urlpatterns += patterns('', (r'^tinymce/', include('tinymce.urls')), (r'^robots.txt$', include('robots.urls')), url( # TODO: replace with django.conf.urls.static ? - r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], + r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT.replace('\\','/')}, ), diff --git a/askbot/skins/loaders.py b/askbot/skins/loaders.py index 50276f34..88dc2ef0 100644 --- a/askbot/skins/loaders.py +++ b/askbot/skins/loaders.py @@ -5,6 +5,7 @@ from django.template import TemplateDoesNotExist from django.http import HttpResponse from django.utils import translation from django.conf import settings as django_settings +from django.core.exceptions import ImproperlyConfigured from coffin.common import CoffinEnvironment from jinja2 import loaders as jinja_loaders from jinja2.exceptions import TemplateNotFound @@ -59,9 +60,20 @@ class SkinEnvironment(CoffinEnvironment): or empty string - depending on the existence of file SKIN_PATH/media/style/extra.css """ - url = utils.get_media_url('style/extra.css', ignore_missing = True) + url = None + + if django_settings.ASKBOT_CSS_DEVEL is True: + url = utils.get_media_url('style/extra.less', ignore_missing=True) + rel = "stylesheet/less" + + #second try - if there is no extra.less in devel mode - try css + if url is None: + url = utils.get_media_url('style/extra.css', ignore_missing=True) + rel = "stylesheet" + if url is not None: - return '<link href="%s" rel="stylesheet" type="text/css" />' % url + return '<link href="%s" rel="%s" type="text/less" />' % (url, rel) + return '' def load_skins(): @@ -81,7 +93,12 @@ SKINS = load_skins() def get_skin(request = None): """retreives the skin environment for a given request (request var is not used at this time)""" - return SKINS[askbot_settings.ASKBOT_DEFAULT_SKIN] + skin_name = askbot_settings.ASKBOT_DEFAULT_SKIN + try: + return SKINS[skin_name] + except KeyError: + msg_fmt = 'skin "%s" not found, check value of "ASKBOT_EXTRA_SKINS_DIR"' + raise ImproperlyConfigured(msg_fmt % skin_name) def get_askbot_template(template, request = None): """ diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index f3597820..7d2e0216 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -108,6 +108,26 @@ def test_askbot_url(): msg = 'if ASKBOT_URL setting is not empty, ' + \ 'it must not start with /' + +def test_jinja2(): + """tests Jinja2 settings""" + compressor_ext = 'compressor.contrib.jinja2ext.CompressorExtension' + ext_list = getattr(django_settings, 'JINJA2_EXTENSIONS', None) + errors = list() + if ext_list is None: + errors.append( + "Please add the following line to your settings.py:\n" + "JINJA2_EXTENSIONS = ('%s',)" % compressor_ext + ) + elif compressor_ext not in ext_list: + errors.append( + "Please add to the JINJA2_EXTENSIONS list an item:\n" + "'%s'," % compressor_ext + ) + + print_errors(errors) + + def test_middleware(): """Checks that all required middleware classes are installed in the django settings.py file. If that is not the @@ -231,7 +251,7 @@ def test_template_loader(): errors.append( '"%s" must be the first element of TEMPLATE_LOADERS' % current_loader ) - + print_errors(errors) def test_celery(): @@ -287,6 +307,40 @@ def test_celery(): "in your settings.py file" ) +def test_compressor(): + """test settings for django compressor""" + precompilers = getattr(django_settings, 'COMPRESS_PRECOMPILERS', None) + errors = list() + lessc_item = ('text/less', 'lessc {infile} {outfile}') + if precompilers is None: + errors.append( + 'Please add to your settings.py file: \n' + 'COMPRESS_PRECOMPILERS = (\n' + " ('%s', '%s'),\n" + ')' % lessc_item + ) + else: + if lessc_item not in precompilers: + errors.append( + 'Please add to the COMPRESS_PRECOMPILERS the following item:\n' + "('%s', '%s')," % lessc_item + ) + + js_filters = getattr(django_settings, 'COMPRESS_JS_FILTERS', []) + if len(js_filters) > 0: + errors.append( + 'Askbot does not yet support js minification, please add to your settings.py:\n' + 'COMPRESS_JS_FILTERS = []' + ) + + if 'compressor' not in django_settings.INSTALLED_APPS: + errors.append( + 'add to the INSTALLED_APPS the following entry:\n' + " 'compressor'," + ) + + print_errors(errors) + def test_media_url(): """makes sure that setting `MEDIA_URL` has leading slash""" @@ -472,6 +526,26 @@ def test_staticfiles(): ' python manage.py collectstatic\n' ) + required_finders = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'compressor.finders.CompressorFinder', + ) + + finders = getattr(django_settings, 'STATICFILES_FINDERS', None) + + missing_finders = list() + for finder in required_finders: + if finder not in finders: + missing_finders.append(finder) + + if missing_finders: + errors.append( + 'Please make sure that the following items are \n' + \ + 'part of the STATICFILES_FINDERS tuple, create this tuple, if it is missing:\n' + + ' "' + '",\n "'.join(missing_finders) + '",\n' + ) + print_errors(errors) if django_settings.STATICFILES_STORAGE == \ 'django.contrib.staticfiles.storage.StaticFilesStorage': @@ -609,7 +683,6 @@ def test_tinymce(): required_attrs = ( 'TINYMCE_COMPRESSOR', 'TINYMCE_JS_ROOT', - 'TINYMCE_URL', 'TINYMCE_DEFAULT_CONFIG' ) @@ -664,16 +737,6 @@ def test_tinymce(): error_tpl += '\nNote: we have moved files from "common" into "default"' errors.append(error_tpl % relative_js_path) - #check url setting - url = getattr(django_settings, 'TINYMCE_URL', '') - expected_url = django_settings.STATIC_URL + relative_js_path - old_expected_url = django_settings.STATIC_URL + old_relative_js_path - if urls_equal(url, expected_url) is False: - error_tpl = "add line: TINYMCE_URL = STATIC_URL + '%s'" - if urls_equal(url, old_expected_url): - error_tpl += '\nNote: we have moved files from "common" into "default"' - errors.append(error_tpl % relative_js_path) - if errors: header = 'Please add the tynymce editor configuration ' + \ 'to your settings.py file.' @@ -721,7 +784,7 @@ def test_template_context_processors(): required_processors.append(new_auth_processor) if old_auth_processor in django_settings.TEMPLATE_CONTEXT_PROCESSORS: invalid_processors.append(old_auth_processor) - + missing_processors = list() for processor in required_processors: if processor not in django_settings.TEMPLATE_CONTEXT_PROCESSORS: @@ -790,7 +853,7 @@ def test_group_messaging(): errors.append( "make setting 'GROUP_MESSAGING to be exactly:\n" + settings_sample ) - + url_params = settings.get('BASE_URL_PARAMS', None) else: errors.append('add this to your settings.py:\n' + settings_sample) @@ -819,7 +882,7 @@ def test_multilingual(): errors.append('ASKBOT_MULTILINGUAL=True works only with django >= 1.4') if is_multilang: - middleware = 'django.middleware.locale.LocaleMiddleware' + middleware = 'django.middleware.locale.LocaleMiddleware' if middleware not in django_settings.MIDDLEWARE_CLASSES: errors.append( "add 'django.middleware.locale.LocaleMiddleware' to your MIDDLEWARE_CLASSES " @@ -835,32 +898,42 @@ def test_multilingual(): print_errors(errors) +def test_messages_framework(): + if not 'django.contrib.messages' in django_settings.INSTALLED_APPS: + errors = ('Add to the INSTALLED_APPS section of your settings.py:\n "django.contrib.messages"', ) + print_errors(errors) def run_startup_tests(): """function that runs all startup tests, mainly checking settings config so far """ + #this is first because it gives good info on what to install + test_modules() #todo: refactor this when another test arrives - test_template_loader() - test_encoding() - test_modules() test_askbot_url() + test_avatar() + test_cache_backend() + test_celery() + test_compressor() + test_custom_user_profile_tab() + test_encoding() + test_group_messaging() + test_haystack() + test_jinja2() + test_longerusername() + test_new_skins() + test_media_url() #test_postgres() + test_messages_framework() test_middleware() - test_celery() + test_multilingual() #test_csrf_cookie_domain() + test_secret_key() + test_staticfiles() + test_template_loader() test_template_context_processors() test_tinymce() - test_staticfiles() - test_new_skins() - test_longerusername() - test_avatar() - test_group_messaging() - test_multilingual() - test_haystack() - test_cache_backend() - test_secret_key() settings_tester = SettingsTester({ 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY': { 'value': True, @@ -897,10 +970,8 @@ def run_startup_tests(): } }) settings_tester.run() - test_media_url() if 'manage.py test' in ' '.join(sys.argv): test_settings_for_test_runner() - test_custom_user_profile_tab() @transaction.commit_manually def run(): diff --git a/askbot/templates/answer_edit.html b/askbot/templates/answer_edit.html index f80715ec..875eec5b 100644 --- a/askbot/templates/answer_edit.html +++ b/askbot/templates/answer_edit.html @@ -40,8 +40,18 @@ {% endif %} </div> <div class="after-editor"> - <input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" /> - <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" /> + <input + id="edit_post_form_submit_button" + type="submit" + value="{% trans %}Save edit{% endtrans %}" + class="large submit" + /> + <input + type="button" + value="{% trans %}Cancel{% endtrans %}" + class="large submit" + onclick="history.back(-1);" + /> </div> </form> diff --git a/askbot/templates/authopenid/authopenid_macros.html b/askbot/templates/authopenid/authopenid_macros.html index 9d35ac6f..d0dca8bf 100644 --- a/askbot/templates/authopenid/authopenid_macros.html +++ b/askbot/templates/authopenid/authopenid_macros.html @@ -63,7 +63,7 @@ <h2 id="openid-heading">{% trans %}Please enter your <span>user name</span>, then sign in{% endtrans %}</h2> <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p> <input type="text" name="openid_login_token" /> - <input class="submit-b" type="submit" name="openid_login_with_extra_token" value="{% trans %}Sign in{% endtrans %}"/> + <input type="submit" name="openid_login_with_extra_token" value="{% trans %}Sign in{% endtrans %}"/> </fieldset> {% endif %} {% endmacro %} diff --git a/askbot/templates/authopenid/signin.html b/askbot/templates/authopenid/signin.html index c5a5c47f..ff7d47a4 100644 --- a/askbot/templates/authopenid/signin.html +++ b/askbot/templates/authopenid/signin.html @@ -115,7 +115,7 @@ </tr>
</table>
<p id="local_login_buttons">
- <input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
+ <input name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
{% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
<a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
{% endif %}
@@ -145,7 +145,7 @@ </tr>
</table>
<p id="local_login_buttons">
- <input class="submit-b" name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
+ <input name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
</p>
{% endif %}
</fieldset>
@@ -212,7 +212,6 @@ {% endif %}
{{ account_recovery_form.email }}
<input
- class="submit-b"
type="submit"
{% if view_subtype == 'bad_key' %}
value="{% trans %}Send a new recovery key{% endtrans %}"
diff --git a/askbot/templates/authopenid/widget_signin.html b/askbot/templates/authopenid/widget_signin.html index c3dbcfde..72860120 100644 --- a/askbot/templates/authopenid/widget_signin.html +++ b/askbot/templates/authopenid/widget_signin.html @@ -115,7 +115,7 @@ </tr>
</table>
<p id="local_login_buttons">
- <input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
+ <input name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
{% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
<a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
{% endif %}
@@ -145,7 +145,7 @@ </tr>
</table>
<p id="local_login_buttons">
- <input class="submit-b" name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
+ <input name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
</p>
{% endif %}
</fieldset>
@@ -212,7 +212,6 @@ {% endif %}
{{ account_recovery_form.email }}
<input
- class="submit-b"
type="submit"
{% if view_subtype == 'bad_key' %}
value="{% trans %}Send a new recovery key{% endtrans %}"
diff --git a/askbot/templates/base.html b/askbot/templates/base.html index 6c162057..80230b26 100644 --- a/askbot/templates/base.html +++ b/askbot/templates/base.html @@ -1,3 +1,4 @@ +{% load compress %} <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> @@ -12,7 +13,7 @@ {% endif %} <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" /> - <link + <link rel="alternate" type="application/rss+xml" title="{% trans site_title=settings.APP_SHORT_NAME %}RSS feed from {{ site_title }}{% endtrans %}" @@ -20,7 +21,7 @@ /> {% block before_css %}{% endblock %} {% include "meta/html_head_stylesheets.html" %} - {% include "meta/fonts.html" %} + {% include "meta/fonts.html" %} {# may contain external files #} {% block forestyle %}{% endblock %} {% include "meta/html_head_javascript.html" %} {% block forejs %}{% endblock %} diff --git a/askbot/templates/list_suggested_tags.html b/askbot/templates/list_suggested_tags.html index 31e48c09..660c8308 100644 --- a/askbot/templates/list_suggested_tags.html +++ b/askbot/templates/list_suggested_tags.html @@ -31,8 +31,8 @@ {% if tag.threads.count() == 0 %} <tr class="thread-info" data-thread-id="0"> <td class="per-thread-controls"> - <button class="btn accept">{% trans %}Accept{% endtrans %}</button> - <button class="btn reject">{% trans %}Reject{% endtrans %}</button> + <button class="accept">{% trans %}Accept{% endtrans %}</button> + <button class="reject">{% trans %}Reject{% endtrans %}</button> </td> <td class="thread-links-col"> <span>{% trans %}There are no questions with this tag yet{% endtrans %}</span> @@ -42,8 +42,8 @@ {% for thread in tag.threads.all() %} <tr class="thread-info" data-thread-id="{{ thread.id }}"> <td class="per-thread-controls"> - <button class="btn accept">{% trans %}Accept{% endtrans %}</button> - <button class="btn reject">{% trans %}Reject{% endtrans %}</button> + <button class="accept">{% trans %}Accept{% endtrans %}</button> + <button class="reject">{% trans %}Reject{% endtrans %}</button> </td> <td class="thread-links-col"> <a title="{{ thread._question_post().summary|escape }}" @@ -59,8 +59,8 @@ <tr class="per-tag-controls" data-tag-id="{{ tag.id }}"> <td colspan="4"> {% if tag.threads.count() > 1 %} - <button class="btn accept">{% trans name=tag.name %}Apply tag "{{ name }}" to all above questions{% endtrans %}</button> - <button class="btn reject">{% trans %}Reject tag{% endtrans %}</button> + <button class="accept">{% trans name=tag.name %}Apply tag "{{ name }}" to all above questions{% endtrans %}</button> + <button class="reject">{% trans %}Reject tag{% endtrans %}</button> {% endif %} </td> </tr> diff --git a/askbot/templates/macros.html b/askbot/templates/macros.html index f94fc12d..6c6b22d4 100644 --- a/askbot/templates/macros.html +++ b/askbot/templates/macros.html @@ -258,7 +258,7 @@ poor design of the data or methods on data objects #} -%} {% if acceptance_level in ('open', 'moderated') %} <button - class="group-join-btn follow-toggle {% if membership_level != 'none' %}on on-state{% endif %}" + class="group-join-btn button follow-toggle {% if membership_level != 'none' %}on on-state{% endif %}" data-group-id="{{group_id}}" {% if acceptance_level == 'open' %} data-off-prompt-text="{% trans %}Leave this group{% endtrans %}" @@ -564,7 +564,7 @@ answer {% if answer.accepted() %}accepted-answer{% endif %} {% if answer.author_ {%- macro follow_toggle(follow, name, alias, id) -%} {# follow - boolean; name - object type name; alias - e.g. users name; id - object id #} <div - class="follow-toggle follow-user-toggle" + class="button follow-toggle follow-user-toggle" id="follow-{{ name|escape }}-{{ id }}" > {% if follow %} diff --git a/askbot/templates/main_page/javascript.html b/askbot/templates/main_page/javascript.html index 55b31d00..dc6bdc94 100644 --- a/askbot/templates/main_page/javascript.html +++ b/askbot/templates/main_page/javascript.html @@ -1,6 +1,10 @@ <script type="text/javascript"> + {# cant cache this #} + askbot['settings']['showSortByRelevance'] = {{ show_sort_by_relevance|as_js_bool }}; +</script> +{% compress js %} +<script type="text/javascript"> /*<![CDATA[*/ - askbot['settings']['showSortByRelevance'] = {% if show_sort_by_relevance %}true{% else %}false{% endif %}; $(document).ready(function(){ /*var on_tab = '#nav_questions'; $(on_tab).attr('className','on');*/ @@ -40,6 +44,5 @@ /*]]>*/ </script> <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script> -{% if request.user.is_authenticated() %} <script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script> -{% endif %} +{% endcompress %} diff --git a/askbot/templates/main_page/nothing_found.html b/askbot/templates/main_page/nothing_found.html index 1e2c5445..98629476 100644 --- a/askbot/templates/main_page/nothing_found.html +++ b/askbot/templates/main_page/nothing_found.html @@ -3,7 +3,7 @@ {% if search_state.scope == "unanswered" %} {% trans %}There are no unanswered questions here{% endtrans %} {% endif %} -{% if search_state.scope == "favorite" %} +{% if search_state.scope == "followed" %} {% trans %}No questions here. {% endtrans %} {% trans %}Please follow some questions or follow some users.{% endtrans %} {% endif %} diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html index 90496bc2..78e23d89 100644 --- a/askbot/templates/meta/bottom_scripts.html +++ b/askbot/templates/meta/bottom_scripts.html @@ -13,11 +13,8 @@ noscript.style.backgroundColor = 'transparent'; </script> </div> +{# this section cannot be compressed because lots of data is runtime #} <script type="text/javascript"> - var i18nLang = '{{ language_code }}'; - var scriptUrl = '/{{settings.ASKBOT_URL}}' - var askbotSkin = '{{settings.ASKBOT_DEFAULT_SKIN}}'; - var enableMathJax = {% if settings.ENABLE_MATHJAX %}true{% else %}false{% endif %}; askbot['urls']['mark_read_message'] = '{% url "read_message" %}'; askbot['urls']['get_tags_by_wildcard'] = '{% url "get_tags_by_wildcard" %}'; askbot['urls']['get_tag_list'] = '{% url "get_tag_list" %}'; @@ -28,24 +25,29 @@ askbot['urls']['titleSearch'] = '{% url "title_search" %}'; askbot['urls']['ask'] = '{% url "ask" %}'; askbot['urls']['questions'] = '{% url "questions" %}'; + askbot['settings']['groupsEnabled'] = {{ settings.GROUPS_ENABLED|as_js_bool }}; askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}'; askbot['settings']['minSearchWordLength'] = {{ min_search_word_length }}; + askbot['settings']['mathjaxEnabled'] = {{ settings.ENABLE_MATHJAX|as_js_bool }}; askbot['settings']['sharingSuffixText'] = '{{ settings.SHARING_SUFFIX_TEXT|escape }}'; -</script> -<script - type="text/javascript" - {% if settings.DEBUG %} - src="{{"/js/jquery-1.7.2.min.js"|media}}" + askbot['data']['haveFlashNotifications'] = {{ user_messages|as_js_bool }}; + askbot['data']['activeTab'] = '{{ active_tab }}'; + {% if search_state %} + askbot['data']['searchUrl'] = '{{ search_state.query_string()|escapejs }}'; {% else %} - src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" + askbot['data']['searchUrl'] = ''; {% endif %} -></script> +</script> +{# everything below until the custom js and google analytics is compressable #} +{% compress js %} +<script type="text/javascript" src="{{"/js/jquery-1.7.2.min.js"|media}}"></script> <script type="text/javascript" src='{{"/bootstrap/js/bootstrap.js"|media}}'></script> <!-- History.js --> <script type='text/javascript' src="{{"/js/jquery.history.js"|media }}"></script> <script type='text/javascript' src="{{"/js/utils.js"|media }}"></script> <script type="text/javascript" src="{{'/js/live_search.js'|media}}"></script> {% if settings.ENABLE_MATHJAX %} + {# we don't want to load mathjax just in case, only if it is really enabled #} <script type='text/javascript' src="{{settings.MATHJAX_BASE_URL}}/MathJax.js"> MathJax.Hub.Config({ extensions: ["tex2jax.js"], @@ -59,59 +61,56 @@ $('.mceStatusbar').remove();//a hack to remove the tinyMCE status bar $(document).ready(function(){ // focus input on the search bar endcomment - {% if active_tab in ('users', 'questions', 'tags', 'badges') %} + var activeTab = askbot['data']['activeTab']; + if (inArray(activeTab, ['users', 'questions', 'tags', 'badges'])) { var searchInput = $('#keywords'); - {% elif active_tab == 'ask' %} + } else if (activeTab === 'ask') { var searchInput = $('#id_title'); - {% else %} + } else { var searchInput = undefined; animateHashes(); - {% endif %} + } if (searchInput) { searchInput.focus(); putCursorAtEnd(searchInput); } - {% if active_tab in ('questions', 'badges', 'ask') %} - if (searchInput) { + if (inArray(activeTab, ['questions', 'badges', 'ask']) && searchInput.length) { var search = new FullTextSearch(); askbot['controllers'] = askbot['controllers'] || {}; askbot['controllers']['fullTextSearch'] = search; - {% if search_state %} - search.setSearchUrl('{{ search_state.query_string()|escapejs }}'); - {% else %} - search.setSearchUrl(''); - {% endif %} - {% if active_tab == 'ask' %} + search.setSearchUrl(askbot['data']['searchUrl']); + if (activeTab === 'ask') { search.setAskButtonEnabled(false); - {% endif %} + } search.decorate(searchInput); } - {% endif %} if (askbot['data']['userIsAdminOrMod']) { $('body').addClass('admin'); } - {%if settings.GROUPS_ENABLED %} - askbot['urls']['add_group'] = "{% url add_group %}"; - var group_dropdown = new GroupDropdown({{group_list}}); - $('.dropdown').append(group_dropdown.getElement()); - {%if request.user.is_superuser%} - group_dropdown.enableAddGroups(); - {%endif%} - {% endif %} + if (askbot['settings']['groupsEnabled']) { + askbot['urls']['add_group'] = "{% url add_group %}"; + var group_dropdown = new GroupDropdown({{ group_list }}); + $('.dropdown').append(group_dropdown.getElement()); + if (askbot['data']['userIsAdmin']) { + group_dropdown.enableAddGroups(); + } + } }); -{% if user_messages %} - $('#validate_email_alert').click(function(){notify.close(true)}) - notify.show(); -{% endif %} + if (askbot['data']['haveFlashNotifications']) { + $('#validate_email_alert').click(function(){notify.close(true)}) + notify.show(); + } $('abbr.timeago').timeago(); /*]]>*/ </script> +{% endcompress %} +{# stuff below should not be compressed #} {% if settings.USE_CUSTOM_JS %} <script - src="{% url "custom_js"%}?v={{ settings.MEDIA_RESOURCE_REVISION }}" + src="{% url "custom_js" %}?v={{ settings.MEDIA_RESOURCE_REVISION }}" type="text/javascript" ></script> {% endif %} diff --git a/askbot/templates/meta/editor_data.html b/askbot/templates/meta/editor_data.html index f0402672..d7328b7d 100644 --- a/askbot/templates/meta/editor_data.html +++ b/askbot/templates/meta/editor_data.html @@ -1,16 +1,14 @@ <script type="text/javascript"> {# data necessary for the post editor, goes into endjs block #} - askbot['settings']['tagsAreRequired'] = - {% if settings.TAGS_ARE_REQUIRED %}true{% else %}false{% endif %}; - askbot['settings']['maxTagLength'] = {{settings.MAX_TAG_LENGTH}}; - "each tag must be shorter than %(max_chars)d characters", + askbot['settings']['tagsAreRequired'] = {{ settings.TAGS_ARE_REQUIRED|as_js_bool }} + askbot['settings']['maxTagLength'] = {{ settings.MAX_TAG_LENGTH }}; askbot['messages']['maxTagLength'] = "{% trans max_chars = settings.MAX_TAG_LENGTH %}each tag must be shorter that {{max_chars}} character{% pluralize %}each tag must be shorter than {{max_chars}} characters{% endtrans %}"; - askbot['settings']['maxTagsPerPost'] = {{settings.MAX_TAGS_PER_POST}}; + askbot['settings']['maxTagsPerPost'] = {{ settings.MAX_TAGS_PER_POST }}; askbot['messages']['maxTagsPerPost'] = "{% trans tag_count = settings.MAX_TAGS_PER_POST %}please use {{tag_count}} tag{% pluralize %}please use {{tag_count}} tags or less{% endtrans %}"; askbot['messages']['tagLimits'] = "{% trans tag_count=settings.MAX_TAGS_PER_POST, max_chars=settings.MAX_TAG_LENGTH %}please use up to {{tag_count}} tags, less than {{max_chars}} characters each{% endtrans %}"; askbot['urls']['upload'] = '{% url "upload" %}'; - askbot['settings']['minTitleLength'] = {{settings.MIN_TITLE_LENGTH}}; - askbot['settings']['minQuestionBodyLength'] = {{settings.MIN_QUESTION_BODY_LENGTH}}; - askbot['settings']['minAnswerBodyLength'] = {{settings.MIN_ANSWER_BODY_LENGTH}}; + askbot['settings']['minTitleLength'] = {{ settings.MIN_TITLE_LENGTH }}; + askbot['settings']['minQuestionBodyLength'] = {{ settings.MIN_QUESTION_BODY_LENGTH }}; + askbot['settings']['minAnswerBodyLength'] = {{ settings.MIN_ANSWER_BODY_LENGTH }}; askbot['settings']['tag_editor'] = '{{ tag_editor_settings|escapejs }}'; </script> diff --git a/askbot/templates/meta/html_head_javascript.html b/askbot/templates/meta/html_head_javascript.html index 306f325a..67f0ec88 100644 --- a/askbot/templates/meta/html_head_javascript.html +++ b/askbot/templates/meta/html_head_javascript.html @@ -1,25 +1,18 @@ <script type="text/javascript" src="{{"/js/modernizr.custom.js"|media }}"></script> -<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script> <script type="text/javascript"> var askbot = {}; askbot['data'] = {}; + askbot['data']['userIsAuthenticated'] = {{ request.user.is_authenticated()|as_js_bool }}; {% if request.user.is_authenticated() %} - askbot['data']['userIsAuthenticated'] = true; - askbot['data']['userId'] = {{request.user.id}}; + askbot['data']['userId'] = {{ request.user.id }}; askbot['data']['userName'] = '{{ request.user.username }}'; - askbot['data']['userIsAdminOrMod'] = {% if - request.user.is_administrator() - or request.user.is_moderator() - %}true{% else %}false{% endif %}; - askbot['data']['userIsAdmin'] = {% if - request.user.is_administrator() - %}true{% else %}false{% endif %}; - askbot['data']['userReputation'] = {{request.user.reputation}}; + askbot['data']['userIsAdminOrMod'] = {{ request.user.is_administrator()|as_js_bool }}; + askbot['data']['userIsAdmin'] = {{ request.user.is_administrator()|as_js_bool }}; + askbot['data']['userReputation'] = {{ request.user.reputation }}; {% else %} - askbot['data']['userIsAuthenticated'] = false; askbot['data']['userReputation'] = 0; {% endif %} - askbot['data']['maxCommentLength'] = {{settings.MAX_COMMENT_LENGTH}}; + askbot['data']['maxCommentLength'] = {{ settings.MAX_COMMENT_LENGTH }}; askbot['urls'] = {}; askbot['settings'] = {}; askbot['settings']['editorType'] = '{{ settings.EDITOR_TYPE }}'; @@ -32,4 +25,5 @@ {% endif %} askbot['messages'] = {}; </script> +<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script> {# avoid adding javascript here so that pages load faster #} diff --git a/askbot/templates/meta/html_head_stylesheets.html b/askbot/templates/meta/html_head_stylesheets.html index 23750239..a1bd0015 100644 --- a/askbot/templates/meta/html_head_stylesheets.html +++ b/askbot/templates/meta/html_head_stylesheets.html @@ -1,17 +1,18 @@ -{%if settings.GROUPS_ENABLED%} -<link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" /> -{% endif %} -{% if settings.ASKBOT_CSS_DEVEL == False %} - -<link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" /> +{% if settings.ASKBOT_CSS_DEVEL %} + <link href="{{"/style/style.less"|media }}" rel="stylesheet/less" type="text/css" /> + {{ skin.get_extra_css_link() }} + <script type="text/javascript" src="{{"/js/less.min.js"|media}}"></script> + <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" /> {% else %} -<link href="{{"/style/style.less"|media }}" rel="stylesheet/less" type="text/css" /> -<script type="text/javascript" src="{{"/js/less.min.js"|media}}"></script> + {% compress css %} + <link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" /> + {{ skin.get_extra_css_link() }} + <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" /> + {% endcompress %} {% endif %} -<link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" /> -{{ skin.get_extra_css_link() }} {% if settings.USE_CUSTOM_CSS %} - <link + {# can't compress yet because this comes from live settings #} + <link href="{% url "custom_css" %}?v={{settings.MEDIA_RESOURCE_REVISION}}" rel="stylesheet" type="text/css" diff --git a/askbot/templates/question.html b/askbot/templates/question.html index 9b1f8a6c..5fa32206 100644 --- a/askbot/templates/question.html +++ b/askbot/templates/question.html @@ -8,7 +8,6 @@ {% 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"> @@ -151,6 +150,14 @@ if (flags.length > 0) { removeNode(flags[0]); } + var closeBtn = findChildrenByClassName(controls, 'question-close'); + if ( + closeBtn.length === 1 && + data['userReputation'] < + {{ settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS }} + ) { + removeNode(closeBtn[0]); + } if (//maybe remove "edit" button data['userReputation'] < {{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}} @@ -240,10 +247,47 @@ {% include "question/sidebar.html" %} {% endblock %} {% block endjs %} + <script type='text/javascript'> + {# not compressable #} + {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %} + var codeFriendlyMarkdown = true; + {% else %} + var codeFriendlyMarkdown = false; + {% endif %} + var maxCommentLength = {{settings.MAX_COMMENT_LENGTH}}; + askbot['urls']['postComments'] = '{% url post_comments %}'; + askbot['urls']['editComment'] = '{% url edit_comment %}'; + askbot['urls']['deleteComment'] = '{% url delete_comment %}'; + askbot['urls']['convertComment'] = '{% url comment_to_answer %}'; + askbot['urls']['getComment'] = '{% url get_comment %}'; + askbot['urls']['saveDraftAnswer'] = '{% url save_draft_answer %}'; + askbot['urls']['vote_url'] = '{% url vote question.id %}'; + askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}'; + askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}'; + askbot['urls']['upvote_comment'] = '{% url upvote_comment %}'; + askbot['urls']['delete_post'] = '{% url delete_post %}'; + askbot['urls']['get_html_template'] = '{% url get_html_template %}'; + askbot['urls']['getGroupsList'] = '{% url get_groups_list %}'; + askbot['urls']['publishAnswer'] = '{% url publish_answer %}'; + askbot['data']['userIsThreadModerator'] = {{ user_is_thread_moderator|as_js_bool }}; + askbot['data']['questionAuthorId'] = {{ question.author_id }}; + askbot['data']['threadIsClosed'] = {{ thread.closed|as_js_bool }}; + askbot['data']['answersSortTab'] = '{{ tab_id }}'; + askbot['data']['questionId'] = {{ question.id }}; + askbot['data']['threadSlug'] = '{{ thread.title|slugify }}'; + askbot['messages']['addComment'] = '{% trans %}post a comment{% endtrans %}'; + askbot['settings']['saveCommentOnEnter'] = {{ settings.SAVE_COMMENT_ON_ENTER|as_js_bool }}; + askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}'; + askbot['settings']['enableSharingGoogle'] = {{ settings.ENABLE_SHARING_GOOGLE|as_js_bool }}; + </script> + {% include "meta/editor_data.html" %} + {% compress js %} {% include "question/javascript.html" %} {% if settings.TAG_SOURCE == 'category-tree' %} {% include "meta/category_tree_js.html" %} {% endif %} + {% include "question/custom_javascript.html" ignore missing %} + {% endcompress %} {# <script type="text/javascript"> var messages = askbot['messages']; diff --git a/askbot/templates/question/answer_controls.html b/askbot/templates/question/answer_controls.html index c7d3c4d9..21aafe47 100644 --- a/askbot/templates/question/answer_controls.html +++ b/askbot/templates/question/answer_controls.html @@ -67,6 +67,7 @@ <input type="hidden" name="answer_id" id="id_answer_id" value="{{answer.id}}"/> <input type="submit" + class="link" value="{% trans %}repost as a question comment{% endtrans %}" /> </form> @@ -80,6 +81,7 @@ <input type="hidden" name="answer_id" value="{{ answer.id }}"/> <input type="submit" + class="link" value="{% trans %}repost as a comment under the older answer{% endtrans %}" /> </form> diff --git a/askbot/templates/question/content.html b/askbot/templates/question/content.html index babda6b5..11813813 100644 --- a/askbot/templates/question/content.html +++ b/askbot/templates/question/content.html @@ -25,7 +25,7 @@ {# buttons below cannot be cached yet #} {% if user_already_gave_answer %} <a - class="submit" + class="button submit" href="{% url "edit_answer" previous_answer.id %}" >{% trans %}Edit Your Previous Answer{% endtrans %}</a> <span>{% trans %}(only one answer per question is allowed){% endtrans %}</span> diff --git a/askbot/templates/question/javascript.html b/askbot/templates/question/javascript.html index 55f294c7..d32e14c5 100644 --- a/askbot/templates/question/javascript.html +++ b/askbot/templates/question/javascript.html @@ -1,69 +1,44 @@ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script> -<script type='text/javascript'> - {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %} - var codeFriendlyMarkdown = true; - {% else %} - var codeFriendlyMarkdown = false; - {% endif %} - var maxCommentLength = {{settings.MAX_COMMENT_LENGTH}}; - askbot['urls']['postComments'] = '{% url post_comments %}'; - askbot['urls']['editComment'] = '{% url edit_comment %}'; - askbot['urls']['deleteComment'] = '{% url delete_comment %}'; - askbot['urls']['convertComment'] = '{% url comment_to_answer %}'; - askbot['urls']['getComment'] = '{% url get_comment %}'; - askbot['urls']['saveDraftAnswer'] = '{% url save_draft_answer %}'; - askbot['urls']['vote_url'] = '{% url vote question.id %}'; - askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}'; - askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}'; - askbot['urls']['upvote_comment'] = '{% url upvote_comment %}'; - askbot['urls']['delete_post'] = '{% url delete_post %}'; - askbot['urls']['get_html_template'] = '{% url get_html_template %}'; - askbot['urls']['getGroupsList'] = '{% url get_groups_list %}'; - askbot['urls']['publishAnswer'] = '{% url publish_answer %}'; - askbot['data']['userIsThreadModerator'] = {% if user_is_thread_moderator %}true{% else %}false{% endif %}; - askbot['data']['userCanPostComment'] = {% if user_can_post_comment %}true{% else %}false{% endif %}; - askbot['messages']['addComment'] = '{% trans %}post a comment{% endtrans %}'; - {% if settings.SAVE_COMMENT_ON_ENTER %} - askbot['settings']['saveCommentOnEnter'] = true; - {% else %} - askbot['settings']['saveCommentOnEnter'] = false; - {% endif %} - askbot['settings']['minRepToPostComment'] = {{ settings.MIN_REP_TO_LEAVE_COMMENTS }}; - askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}'; - askbot['settings']['enableEmailAlerts'] = {% if settings.ENABLE_EMAIL_ALERTS %}true{% else %}false{% endif %}; -</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> -{% endif %} +<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script> +<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script> <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script> <script type='text/javascript' src='{{"/js/post.js"|media}}'></script> <script type="text/javascript"> // define reputation needs for comments - var repNeededForComments = 50; $(document).ready(function(){ $("#nav_questions").attr('className',"on"); - var answer_sort_tab = "{{ tab_id }}"; - $("#" + answer_sort_tab).attr('className',"on"); + $("#" + askbot['data']['answersSortTab']).attr('className',"on"); - Vote.init({{ question.id }}, '{{ thread.title|slugify }}', '{{ question.author_id }}','{{ request.user.id }}'); + Vote.init( + askbot['data']['questionId'], + askbot['data']['threadSlug'], + askbot['data']['questionAuthorId'], + askbot['data']['userId'] + ); - {% if not thread.closed and request.user.is_authenticated %}initEditor();{% endif %} + if ((askbot['data']['threadIsClosed'] === false) && askbot['data']['userIsAuthenticated']) { + initEditor(); + } lanai.highlightSyntax(); - $('#btLogin').bind('click', function(){window.location.href='{{ settings.LOGIN_URL }}'; } ) + $('#btLogin').bind('click', function(){ + window.location.href='{{ settings.LOGIN_URL }}'; + }); if (window.location.hash === 'fmanswer'){ $('#fmanswer textarea').focus(); } - {% if settings.ENABLE_SHARING_GOOGLE %}$.getScript("//apis.google.com/js/plusone.js"){% endif %} - {% if request.user.id == question.author_id %} + if (askbot['settings']['enableSharingGoogle']) { + $.getScript("//apis.google.com/js/plusone.js"); + } + + if (askbot['data']['userId'] === askbot['data']['questionAuthorId']) { $("#fmanswer_button").click(function() { $("#fmanswer").show(); $("#fmanswer_button").hide(); }); - {%endif%} + } if (askbot['data']['userIsAuthenticated']) { var draftHandler = new DraftAnswer(); @@ -79,7 +54,9 @@ if (id_value != ""){ var previous_color = $(id_value).css('background-color'); $(id_value).css('backgroundColor', '#FFF8C6'); - $(id_value).animate({backgroundColor: '#ff7f2a'}, 1000).animate({backgroundColor: '#FFF8C6'}, 1000, function(){ + $(id_value).animate( + {backgroundColor: '#ff7f2a'}, 1000 + ).animate({backgroundColor: '#FFF8C6'}, 1000, function(){ $(id_value).css('backgroundColor', previous_color); }); } @@ -108,4 +85,3 @@ ); } </script> -{% include "meta/editor_data.html" %} diff --git a/askbot/templates/question/new_answer_form.html b/askbot/templates/question/new_answer_form.html index 90fe8786..2235f4f4 100644 --- a/askbot/templates/question/new_answer_form.html +++ b/askbot/templates/question/new_answer_form.html @@ -7,7 +7,7 @@ {% if request.user.is_anonymous() and settings.ALLOW_POSTING_BEFORE_LOGGING_IN == False %} {% if not thread.closed %} <a - class="submit" + class="button submit" href="{{settings.LOGIN_URL}}?next={% url question question.id %}" >{% trans %}Login/Signup to Answer{% endtrans %}</a> {% endif %} diff --git a/askbot/templates/question/sidebar.html b/askbot/templates/question/sidebar.html index 905ce781..17820096 100644 --- a/askbot/templates/question/sidebar.html +++ b/askbot/templates/question/sidebar.html @@ -173,6 +173,8 @@ {#% endcache %#} {% endif %} -<div class="box"> - {{ settings.SIDEBAR_QUESTION_FOOTER }} -</div> +{% if settings.SIDEBAR_QUESTION_FOOTER %} + <div class="box"> + {{ settings.SIDEBAR_QUESTION_FOOTER }} + </div> +{% endif %} diff --git a/askbot/templates/question_edit.html b/askbot/templates/question_edit.html index 7cf1c143..1aaa972c 100644 --- a/askbot/templates/question_edit.html +++ b/askbot/templates/question_edit.html @@ -54,8 +54,8 @@ </div> {% endif %} </div> - <input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" /> - <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" /> + <input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="large submit" /> + <input type="button" value="{% trans %}Cancel{% endtrans %}" class="large submit" onclick="history.back(-1);" /> </div> </form> diff --git a/askbot/templates/tags/form_bulk_tag_subscription.html b/askbot/templates/tags/form_bulk_tag_subscription.html index d588cfaf..95168e45 100644 --- a/askbot/templates/tags/form_bulk_tag_subscription.html +++ b/askbot/templates/tags/form_bulk_tag_subscription.html @@ -9,7 +9,7 @@ <form action="." method="POST" accept-charset="utf-8"> <table border="0"> {{form.as_table()}} -<tr><td colspan='2' style='text-align: right;'><input type="submit" class="submit" value="Save"></td></tr> +<tr><td/><td><input type="submit" class="submit" value="Save"></td></tr> </table> </form> {% endblock %} diff --git a/askbot/templates/user_inbox/group_join_requests.html b/askbot/templates/user_inbox/group_join_requests.html index 2defe5e1..c4c4d29d 100644 --- a/askbot/templates/user_inbox/group_join_requests.html +++ b/askbot/templates/user_inbox/group_join_requests.html @@ -22,7 +22,6 @@ /> <input type="hidden" name="action" value="approve"/> <input - class="btn" type="submit" value="{% trans %}Approve{% endtrans %}" /> @@ -38,7 +37,6 @@ /> <input type="hidden" name="action" value="deny"/> <input - class="btn" type="submit" value="{% trans %}Deny{% endtrans %}" /> diff --git a/askbot/templates/widgets/ask_button.html b/askbot/templates/widgets/ask_button.html index e202b110..f8ea82bd 100644 --- a/askbot/templates/widgets/ask_button.html +++ b/askbot/templates/widgets/ask_button.html @@ -4,6 +4,7 @@ {% endif %} <a id="askButton" + class="button" href="{{ search_state.full_ask_url() }}{% if group %}{% if '?' in search_state.full_ask_url() %}&{% else %}?{% endif %}group_id={{ group.id }}{% endif %}" >{% if group %}{% trans %}Ask the Group{% endtrans %}{% else %}{% trans %}Ask Your Question{% endtrans %}{% endif %}</a> {% endif %} diff --git a/askbot/templates/widgets/footer.html b/askbot/templates/widgets/footer.html index 75721e50..e57aad99 100644 --- a/askbot/templates/widgets/footer.html +++ b/askbot/templates/widgets/footer.html @@ -53,7 +53,7 @@ {% endspaceless %} </div> <div class="powered-link"> - <a href="http://askbot.org" target="_blank"> + <a href="http://askbot.com" target="_blank"> Powered by Askbot version {{settings.ASKBOT_VERSION}} </a> </div> diff --git a/askbot/templates/widgets/scope_nav.html b/askbot/templates/widgets/scope_nav.html index b68d899c..254c3b48 100644 --- a/askbot/templates/widgets/scope_nav.html +++ b/askbot/templates/widgets/scope_nav.html @@ -1,17 +1,33 @@ +{% set need_scope_links = ( + settings.ALL_SCOPE_ENABLED|to_int + + settings.UNANSWERED_SCOPE_ENABLED|to_int + + (request.user.is_authenticated() and settings.FOLLOWED_SCOPE_ENABLED)|to_int + > 1 + ) +%} <div id="scopeNav"> -{% if active_tab != "ask" %} - {% if not search_state %} {# get empty SearchState() if there's none #} - {% set search_state=search_state|get_empty_search_state %} +{% if need_scope_links %} + {% if active_tab != "ask" %} + {% if not search_state %} {# get empty SearchState() if there's none #} + {% set search_state=search_state|get_empty_search_state %} + {% endif %} + {% if settings.ALL_SCOPE_ENABLED %} + <a class="scope-selector {% if scope == 'all' %}on{% endif %}" + href="{{ search_state.change_scope('all').full_url() }}" + title="{% trans %}see all questions{% endtrans %}">{% trans %}ALL{% endtrans %}</a> + {% endif %} + {% if settings.UNANSWERED_SCOPE_ENABLED %} + <a class="scope-selector {% if scope == 'unanswered' %}on{% endif %}" + href="{{ search_state.change_scope('unanswered').change_sort('answers-asc').full_url() }}" + title="{% trans %}see unanswered questions{% endtrans %}">{% trans %}UNANSWERED{% endtrans %}</a> + {% endif %} + {% if request.user.is_authenticated() and settings.FOLLOWED_SCOPE_ENABLED %} + <a class="scope-selector {% if scope == 'followed' %}on{% endif %}" + href="{{ search_state.change_scope('followed').full_url() }}" + title="{% trans %}see your followed questions{% endtrans %}">{% trans %}FOLLOWED{% endtrans %}</a> + {% endif %} + {% else %} + <div class="scope-selector ask-message">{% trans %}Please ask your question here{% endtrans %}</div> {% endif %} - <a class="scope-selector {% if scope == 'all' %}on{% endif %}" - href="{{ search_state.change_scope('all').full_url() }}" title="{% trans %}see all questions{% endtrans %}">{% trans %}ALL{% endtrans %}</a> - <a class="scope-selector {% if scope == 'unanswered' %}on{% endif %}" - href="{{ search_state.change_scope('unanswered').change_sort('answers-asc').full_url() }}" title="{% trans %}see unanswered questions{% endtrans %}">{% trans %}UNANSWERED{% endtrans %}</a> - {% if request.user.is_authenticated() %} - <a class="scope-selector {% if scope == 'favorite' %}on{% endif %}" - href="{{ search_state.change_scope('favorite').full_url() }}" title="{% trans %}see your followed questions{% endtrans %}">{% trans %}FOLLOWED{% endtrans %}</a> - {% endif %} -{% else %} - <div class="scope-selector ask-message">{% trans %}Please ask your question here{% endtrans %}</div> {% endif %} </div> diff --git a/askbot/templates/widgets/search_bar.html b/askbot/templates/widgets/search_bar.html index 8c485c73..5f0bb8de 100644 --- a/askbot/templates/widgets/search_bar.html +++ b/askbot/templates/widgets/search_bar.html @@ -1,23 +1,32 @@ {% if active_tab != "ask" %} {% spaceless %} -<div id="searchBar" {% if query %}class="cancelable"{% endif %}> +<div + id="searchBar" + class="{% if query %}cancelable{% endif %}" +> {# url action depends on which tab is active #} - {% if active_tab == "tags" %} - <input type="hidden" name="t" value="tag"/> - {% else %} - {% if active_tab == "users" %} - <input type="hidden" name="t" value="user"/> - {% endif %} - {% endif %} - {# class was searchInput #} - <input - class="searchInput" - type="text" - autocomplete="off" - value="{{ query|default_if_none('') }}" - name="query" - id="keywords" - /> + {% if active_tab == "tags" %} + <input type="hidden" name="t" value="tag"/> + {% elif active_tab == "users" %} + <input type="hidden" name="t" value="user"/> + {% endif %} + <input + class="searchInput" + type="text" + autocomplete="off" + value="{{ query|default_if_none('') }}" + name="query" + id="keywords" + /> + <input type="submit" value="" name="search" class="searchBtn" /> + <input type="button" + value="X" + name="reset_query" + class="cancelSearchBtn" + {% if not query %}{# query is only defined by questions view (active_tab) #} + style="display: none;" + {% endif %} + /> </div> {% endspaceless %} {% endif %} diff --git a/askbot/templates/widgets/secondary_header.html b/askbot/templates/widgets/secondary_header.html index defd7148..f3f78fa7 100644 --- a/askbot/templates/widgets/secondary_header.html +++ b/askbot/templates/widgets/secondary_header.html @@ -2,6 +2,11 @@ <div id="secondaryHeader"> <div class="content-wrapper"> {# form is wrapping search buttons and the search bar inputs #} + {% set enabled_scopes_class = 'scopes-' + + '%s'|format(settings.ALL_SCOPE_ENABLED) + '-' + + '%s'|format(settings.UNANSWERED_SCOPE_ENABLED) + '-' + + '%s'|format((request.user.is_authenticated() and settings.FOLLOWED_SCOPE_ENABLED)) + %} <form {% if active_tab == "tags" %} action="{% url tags %}" @@ -10,6 +15,7 @@ {% else %} action="{% url questions %}" id="searchForm" {% endif %} + class="{{ enabled_scopes_class }}" method="get"> <div> {# @@ -26,16 +32,9 @@ three buttons below are in the opposite order because they are floated at the right #} - {% include "widgets/ask_button.html" %} - <input type="submit" value="" name="search" class="searchBtn" /> - <input type="button" - value="X" - name="reset_query" - class="cancelSearchBtn" - {% if not query %}{# query is only defined by questions view (active_tab) #} - style="display: none;" - {% endif %} - /> + {% if settings.ASK_BUTTON_ENABLED %} + {% include "widgets/ask_button.html" %} + {% endif %} {# clears button floats #} <div class="clearfix"></div> </div> diff --git a/askbot/templates/widgets/tag_selector.html b/askbot/templates/widgets/tag_selector.html index 7c6fe92e..ba304d2c 100644 --- a/askbot/templates/widgets/tag_selector.html +++ b/askbot/templates/widgets/tag_selector.html @@ -14,6 +14,7 @@ "remove '%(tag_name)s' from the list of interesting tags"| format(tag_name = tag_name) #} + <div class="clearfix"></div> <div class="inputs"> <input id="interestingTagInput" autocomplete="off" type="text"/> <input id="interestingTagAdd" type="submit" value="{% trans %}add{% endtrans %}"/> @@ -49,6 +50,7 @@ "remove '%(tag_name)s' from the list of ignored tags"| format(tag_name = tag_name) #} + <div class="clearfix"></div> <div class="inputs"> <input id="subscribedTagInput" autocomplete="off" type="text"/> <input id="subscribedTagAdd" type="submit" value="{% trans %}add{% endtrans%}"/> diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py index e927ccbf..6fd12aab 100644 --- a/askbot/templatetags/extra_filters_jinja.py +++ b/askbot/templatetags/extra_filters_jinja.py @@ -39,10 +39,20 @@ def add_tz_offset(datetime_object): return str(datetime_object) + ' ' + TIMEZONE_STR @register.filter +def as_js_bool(some_object): + if bool(some_object): + return 'true' + return 'false' + +@register.filter def is_current_language(lang): return lang == django_get_language() @register.filter +def to_int(value): + return int(value) + +@register.filter def safe_urlquote(text, quote_plus = False): if quote_plus: return urllib.quote_plus(text.encode('utf8')) diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py index 91c25867..8d775fd0 100644 --- a/askbot/tests/db_api_tests.py +++ b/askbot/tests/db_api_tests.py @@ -3,6 +3,7 @@ functions that happen on behalf of users e.g. ``some_user.do_something(...)`` """ +from bs4 import BeautifulSoup from django.core import exceptions from django.core.urlresolvers import reverse from django.test.client import Client @@ -667,3 +668,35 @@ class GroupTests(AskbotTestCase): self.assertEqual(acts[0].recipients.count(), 1) recipient = acts[0].recipients.all()[0] self.assertEqual(recipient, mod) + +class LinkPostingTests(AskbotTestCase): + + def assert_no_link(self, html): + soup = BeautifulSoup(html) + links = soup.findAll('a') + self.assertEqual(len(links), 0) + + def assert_has_link(self, html, url): + soup = BeautifulSoup(html) + links = soup.findAll('a') + self.assertTrue(len(links) > 0) + self.assertEqual(links[0]['href'], url) + + @with_settings( + EDITOR_TYPE='markdown', + MIN_REP_TO_SUGGEST_LINK=5, + MIN_REP_TO_INSERT_LINK=30 + ) + def test_admin_can_help_low_rep_user_insert_link(self): + #create a low rep user + low = self.create_user('low', reputation=10) + #create an admin + admin = self.create_user('admin', status='d') + #low re user posts a question with a link + text = 'hello, please read http://wikipedia.org' + question = self.post_question(user=low, body_text=text) + self.assert_no_link(question.html) + self.edit_question(user=admin, question=question, body_text=text + ' ok') + self.assert_has_link(question.html, 'http://wikipedia.org') + + diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py index d11890a8..c9fe4b99 100644 --- a/askbot/tests/email_alert_tests.py +++ b/askbot/tests/email_alert_tests.py @@ -738,7 +738,7 @@ class FeedbackTests(utils.AskbotTestCase): } response = client.post(reverse('feedback'), data) self.assertEquals(response.status_code, 200) - self.assertEquals(response.template.name, 'feedback.html') + self.assertEquals(response.templates[0].name, 'feedback.html') def test_mail_moderators(self): """tests askbot.mail_moderators() diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py index c4ee8554..ef43ebf8 100644 --- a/askbot/tests/page_load_tests.py +++ b/askbot/tests/page_load_tests.py @@ -256,7 +256,7 @@ class PageLoadTestCase(AskbotTestCase): template='main_page.html', ) self.try_url( - url_name=reverse('questions') + SearchState.get_empty().change_scope('favorite').query_string(), + url_name=reverse('questions') + SearchState.get_empty().change_scope('followed').query_string(), plain_url_passed=True, status_code=status_code, @@ -724,7 +724,9 @@ class CommandViewTests(AskbotTestCase): def test_load_object_description_fails(self): response = self.client.get(reverse('load_object_description')) - self.assertEqual(response.status_code, 404)#bad request + soup = BeautifulSoup(response.content) + title = soup.find_all('h1')[0].contents[0] + self.assertEqual(title, 'Page not found') def test_set_tag_filter_strategy(self): user = self.create_user('someuser') diff --git a/askbot/tests/search_state_tests.py b/askbot/tests/search_state_tests.py index 18f5eb36..27622629 100644 --- a/askbot/tests/search_state_tests.py +++ b/askbot/tests/search_state_tests.py @@ -64,7 +64,7 @@ class SearchStateTests(AskbotTestCase): def test_edge_cases_1(self): ss = SearchState( - scope='favorite', # this is not a valid choice for non-logger users + scope='followed', # this is not a valid choice for non-logger users sort='age-desc', query=' alfa', tags='miki, mini', @@ -83,7 +83,7 @@ class SearchStateTests(AskbotTestCase): ) ss = SearchState( - scope='favorite', + scope='followed', sort='age-desc', query=' alfa', tags='miki, mini', @@ -93,11 +93,11 @@ class SearchStateTests(AskbotTestCase): user_logged_in=True ) self.assertEqual( - 'scope:favorite/sort:age-desc/query:alfa/tags:miki,mini/author:12/page:2/', + 'scope:followed/sort:age-desc/query:alfa/tags:miki,mini/author:12/page:2/', ss.query_string() ) self.assertEqual( - 'scope:favorite/sort:age-desc/query:alfa/tags:miki,mini/author:12/page:2/', + 'scope:followed/sort:age-desc/query:alfa/tags:miki,mini/author:12/page:2/', ss.deepcopy().query_string() ) diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py index ee3cd37e..141f229a 100644 --- a/askbot/tests/utils.py +++ b/askbot/tests/utils.py @@ -96,11 +96,12 @@ class AskbotTestCase(TestCase): def create_user( self, - username = 'user', - email = None, - notification_schedule = None, - date_joined = None, - status = 'a' + username='user', + email=None, + notification_schedule=None, + date_joined=None, + reputation=1, + status='a' ): """creates user with username, etc and makes the result accessible as @@ -116,11 +117,12 @@ class AskbotTestCase(TestCase): email = username + '@example.com' user_object = create_user( - username = username, - email = email, - notification_schedule = notification_schedule, - date_joined = date_joined, - status = status + username=username, + email=email, + notification_schedule=notification_schedule, + date_joined=date_joined, + status=status, + reputation=reputation ) setattr(self, username, user_object) diff --git a/askbot/views/readers.py b/askbot/views/readers.py index ce92ded6..fa39426c 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -40,6 +40,7 @@ from askbot import const from askbot.utils import functions from askbot.utils.html import sanitize_html from askbot.utils.decorators import anonymous_forbidden, ajax_only, get_only +from askbot.utils.loading import load_module from askbot.search.state_manager import SearchState, DummySearchState from askbot.templatetags import extra_tags from askbot.conf import settings as askbot_settings @@ -614,6 +615,14 @@ def question(request, id):#refactor - long subroutine. display question body, an data.update(context.get_for_tag_editor()) + extra_context = getattr( + django_settings, 'ASKBOT_QUESTION_PAGE_EXTRA_CONTEXT', None + ) + if extra_context: + extra_context_getter = load_module(extra_context) + extra_data = extra_context_getter(request, data) + data.update(extra_data) + return render(request, 'question.html', data) def revisions(request, id, post_type = None): diff --git a/askbot/views/users.py b/askbot/views/users.py index 0305eb48..a1304dfb 100644 --- a/askbot/views/users.py +++ b/askbot/views/users.py @@ -726,6 +726,7 @@ def show_group_join_requests(request, user, context): ).order_by('-active_at') data = { 'active_tab':'users', + 'inbox_section': 'group-join-requests', 'page_class': 'user-profile-page', 'tab_name' : 'join_requests', 'tab_description' : _('group joining requests'), diff --git a/askbot/views/writers.py b/askbot/views/writers.py index f886b7a6..896ef09d 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -35,12 +35,14 @@ from django.views.decorators import csrf from askbot import exceptions as askbot_exceptions from askbot import forms from askbot import models +from askbot.models import signals from askbot.conf import settings as askbot_settings from askbot.utils import decorators from askbot.utils.forms import format_errors from askbot.utils.functions import diff_date from askbot.utils import url_utils from askbot.utils.file_utils import store_file +from askbot.utils.loading import load_module from askbot.views import context from askbot.templatetags import extra_filters_jinja as template_filters from askbot.importers.stackexchange import management as stackexchange#todo: may change @@ -479,6 +481,13 @@ def edit_question(request, id): def edit_answer(request, id): answer = get_object_or_404(models.Post, id=id) revision = answer.get_latest_revision() + + class_path = getattr(settings, 'ASKBOT_EDIT_ANSWER_FORM', None) + if class_path: + edit_answer_form_class = load_module(class_path) + else: + edit_answer_form_class = forms.EditAnswerForm + try: request.user.assert_can_edit_answer(answer) if request.method == "POST": @@ -493,18 +502,18 @@ def edit_answer(request, id): # Replace with those from the selected revision rev = revision_form.cleaned_data['revision'] revision = answer.revisions.get(revision = rev) - form = forms.EditAnswerForm( + form = edit_answer_form_class( answer, revision, user=request.user ) else: - form = forms.EditAnswerForm( - answer, - revision, - request.POST, - user=request.user - ) + form = edit_answer_form_class( + answer, + revision, + request.POST, + user=request.user + ) else: - form = forms.EditAnswerForm( + form = edit_answer_form_class( answer, revision, request.POST, user=request.user ) revision_form = forms.RevisionForm(answer, revision) @@ -522,12 +531,27 @@ def edit_answer(request, id): is_private=is_private, suppress_email=suppress_email ) + + signals.answer_edited.send(None, + answer=answer, + user=user, + form_data=form.cleaned_data + ) + return HttpResponseRedirect(answer.get_absolute_url()) else: revision_form = forms.RevisionForm(answer, revision) - form = forms.EditAnswerForm(answer, revision, user=request.user) + form = edit_answer_form_class(answer, revision, user=request.user) if request.user.can_make_group_private_posts(): form.initial['post_privately'] = answer.is_private() + + #gives a chance to set extra initial data on the form + signals.answer_before_editing.send(None, + answer=answer, + user=request.user, + form=form + ) + data = { 'page_class': 'edit-answer-page', 'active_tab': 'questions', @@ -555,7 +579,15 @@ def answer(request, id):#process a new answer """ question = get_object_or_404(models.Post, post_type='question', id=id) if request.method == "POST": - form = forms.AnswerForm(request.POST, user=request.user) + + custom_class_path = getattr(settings, 'ASKBOT_NEW_ANSWER_FORM', None) + if custom_class_path: + form_class = load_module(custom_class_path) + else: + form_class = forms.AnswerForm + + form = form_class(request.POST, user=request.user) + if form.is_valid(): wiki = form.cleaned_data['wiki'] text = form.cleaned_data['text'] @@ -581,6 +613,13 @@ def answer(request, id):#process a new answer is_private = is_private, timestamp = update_time, ) + + signals.new_answer_posted.send(None, + answer=answer, + user=user, + form_data=form.cleaned_data + ) + return HttpResponseRedirect(answer.get_absolute_url()) except askbot_exceptions.AnswerAlreadyGiven, e: request.user.message_set.create(message = unicode(e)) diff --git a/askbot_requirements.txt b/askbot_requirements.txt index a9a939b4..ea9dd005 100644 --- a/askbot_requirements.txt +++ b/askbot_requirements.txt @@ -20,6 +20,6 @@ python-openid pystache==0.3.1 pytz sanction -django-tinymce +django-tinymce==1.5.1b2 longerusername beautifulsoup4 diff --git a/askbot_requirements_dev.txt b/askbot_requirements_dev.txt index 1fbd064c..b88592cf 100644 --- a/askbot_requirements_dev.txt +++ b/askbot_requirements_dev.txt @@ -8,6 +8,8 @@ oauth2 Lamson markdown2 html5lib==0.90 +django-appconf +django-compressor==1.2 django-keyedcache django-threaded-multihost django-robots |