diff --git a/vanilla/applications/vanilla/controllers/class.discussioncontroller.php b/vanilla/applications/vanilla/controllers/class.discussioncontroller.php index 2a63681..fa7fb9e 100644 --- a/vanilla/applications/vanilla/controllers/class.discussioncontroller.php +++ b/vanilla/applications/vanilla/controllers/class.discussioncontroller.php @@ -391,8 +391,8 @@ public function getNew($discussionID, $lastCommentID = 0) { */ public function initialize() { parent::initialize(); - $this->addDefinition('ConfirmDeleteCommentHeading', t('ConfirmDeleteCommentHeading', 'Delete Comment')); - $this->addDefinition('ConfirmDeleteCommentText', t('ConfirmDeleteCommentText', 'Are you sure you want to delete this comment?')); + $this->addDefinition('ConfirmDeleteCommentHeading', t('ConfirmDeleteCommentHeading', 'Delete')); + $this->addDefinition('ConfirmDeleteCommentText', t('ConfirmDeleteCommentText', 'Are you sure you want to delete this item?')); $this->Menu->highlightRoute('/discussions'); } diff --git a/vanilla/applications/vanilla/js/discussion.js b/vanilla/applications/vanilla/js/discussion.js index 09f66cb..64dc29d 100755 --- a/vanilla/applications/vanilla/js/discussion.js +++ b/vanilla/applications/vanilla/js/discussion.js @@ -401,13 +401,42 @@ jQuery(document).ready(function($) { return false; }); + var currentCommentView = gdn.urlQueryParam(window.location.href, 'view'); + var deliveryType = 'VIEW'; + if (currentCommentView) { + deliveryType = currentCommentView == 'flat'?'BOOL':'VIEW'; + } // Delete comment $('a.DeleteComment').popup({ + okButtonText:'Delete', + cancelButtonText: 'Cancel', confirm: true, - confirmHeading: gdn.definition('ConfirmDeleteCommentHeading', 'Delete Comment'), - confirmText: gdn.definition('ConfirmDeleteCommentText', 'Are you sure you want to delete this comment?'), + confirmHtml: '\ +
\ + \ +
', + confirmHeading: gdn.definition('ConfirmDeleteCommentHeading', 'Delete'), + confirmText: gdn.definition('ConfirmDeleteCommentText', 'Are you sure you want to delete this item?'), followConfirm: false, - deliveryType: gdn.urlQueryParam( $('a.DeleteComment').attr('href'), 'deliveryType'), //'VIEW' - threaded, 'BOOL' - flat + deliveryType: gdn.urlQueryParam( $('a.DeleteComment').attr('href'), 'deliveryType')? + gdn.urlQueryParam( $('a.DeleteComment').attr('href'), 'deliveryType'): deliveryType, //'VIEW' - threaded, 'BOOL' - flat afterConfirm: function(json, sender) { var row = $(sender).parents('li.ItemComment'); if (json.ErrorMessage) { diff --git a/vanilla/applications/vanilla/models/class.categorymodel.php b/vanilla/applications/vanilla/models/class.categorymodel.php index 73c0f8c..d75d5e0 100644 --- a/vanilla/applications/vanilla/models/class.categorymodel.php +++ b/vanilla/applications/vanilla/models/class.categorymodel.php @@ -931,6 +931,10 @@ public static function checkPermission($category, $permission, $fullMatch = true } if($groupID && $groupID > 0) { + // FIX: https://github.com/topcoder-platform/forums/issues/587 + if ($userID == 0) { + return false; + } $result = checkGroupPermission($userID, $groupID, $categoryID, $permissionCategoryID, $permission, $fullMatch); } else { $result = PermissionModel::checkPermission($userPermissions,$permission, $fullMatch, 'Category', $permissionCategoryID) diff --git a/vanilla/js/library/jquery.popup.js b/vanilla/js/library/jquery.popup.js new file mode 100644 index 0000000..211faa7 --- /dev/null +++ b/vanilla/js/library/jquery.popup.js @@ -0,0 +1,458 @@ +/* +This is a highly modified version of the Facebox plugin for jQuery by Chris +Wanstrath. Original Credits: + +Facebox (for jQuery) +version: 1.0 (12/19/2007) +@requires jQuery v1.2 or later +Examples at http://famspam.com/facebox/ +Licensed under the MIT: http://www.opensource.org/licenses/mit-license.php +Copyright 2007 Chris Wanstrath [ chris@ozmm.org ] +*/ + +(function($) { + + // Allows generating a popup by jQuery.popup('contents') + $.popup = function(options, data) { + // Merge default settings: + var settings = $.extend({}, $.popup.settings, options); + $.popup.init(settings) + + if (data) { + $.isFunction(data) ? data.call(this, settings) : $.popup.reveal(settings, data); + } else { + $.popup.load(settings); + } + } + + $.fn.popup = function(options) { + + /* + * Since upgrading jQuery to 1.10.2 this does not work, as $.browser was + * removed. The author of this popup plugin does not explain why + * ie6+7 don't get popups, but at this point in time it's no matter. Just + * make sure the popup function works as expected. + */ + var browser = navigator.userAgent.toLowerCase(); + // IE7 or less gets no popups because they're jerks + if (/msie\s6/.test(browser) || /msie\s7/.test(browser)) { + return false; + } + + // Merge the two settings arrays into a central data store + var settings = $.extend({}, $.popup.settings, options); + + // Need to rewrite how popup is called, to incorporate + // event delegation, as live() removed from jQuery in 1.7, and Vanilla + // upgraded to 1.10.2 on Jan28, 2014. + //this.live('click', function() { + var selector = this.selector; + $(document).on('click', selector, function() { + settings.sender = this; + $.extend(settings, { popupType: $(this).attr('popupType') }); + + $.popup.init(settings); + + $.popup.load(settings); + + return false; + }); + + this.mouseover(function() { + settings.sender = this; + if ($.popup.findTarget(settings)) + $(this).addClass(settings.mouseoverClass); + }); + + this.mouseout(function() { + settings.sender = this; + if ($.popup.findTarget(settings)) + $(this).removeClass(settings.mouseoverClass); + }); + + return this; + } + + $.popup.findTarget = function(settings) { + settings.foundTarget = settings.targetUrl; + + // See if the matched element was an anchor. If it was, use the href. + if (!settings.foundTarget) { + if ($(settings.sender).attr('href') != undefined) { + settings.foundTarget = settings.sender.href; + } else { + // See if there were any anchors within the matched element. + // If there are, use the href from the first one. + var anchor = $(settings.sender).find('a:first'); + if (anchor.length > 0) { + settings.foundTarget = anchor[0].href; + } + } + } + + return settings.foundTarget; + } + + // Close a jquery popup and release escape key bindings + $.popup.close = function(settings, response) { + $(document).unbind('keydown.popup'); + $('#'+settings.popupId).trigger('popupClose'); + $('.Overlay').remove(); + + return false; + } + + $.popup.init = function(settings) { + // Define a unique identifier for this popup + var i = 1; + var popupId = 'Popup'; + while ($('#'+popupId).size() > 0) { + popupId = 'Popup'+i; + i++; + } + settings.popupId = popupId; + var popupHtml = ''; + if (!settings.confirm) + popupHtml = settings.popupHtml; + else + popupHtml = settings.confirmHtml; + + popupHtml = popupHtml.replace('{popup.id}', settings.popupId); + + $('body').append(popupHtml); + if (settings.containerCssClass != '') + $('#'+settings.popupId).addClass(settings.containerCssClass); + + var pagesize = $.popup.getPageSize(); + $('div.Overlay').css({height: pagesize[1]}); + + var pagePos = $.popup.getPagePosition(); + $('#'+settings.popupId).css({ + top: pagePos.top, + left: pagePos.left + }); + $('#'+settings.popupId).show(); + + $('#'+settings.popupId+' .Body').css({ + 'max-height': pagesize[3] * .8, + 'overflow-y': 'auto' + }); + + $(document).bind('keydown.popup', function(e) { + if (e.keyCode == 27) + $.popup.close(settings); + }) + + if (settings.onUnload) { + $('#'+settings.popupId).bind('popupClose',function(){ + setTimeout(settings.onUnload,1); + }); + } + + // Replace language definitions + if (!settings.confirm) { + $('#'+settings.popupId+' .Close').click(function() { + return $.popup.close(settings); + }); + } else { + // 'Confirm' popup heading + var confirmHeading = (settings.confirmHeading) ? settings.confirmHeading : gdn.definition('ConfirmHeading', 'Confirm'); + $('#'+settings.popupId+' .Content h1').text(confirmHeading); + + // 'Confirm' popup body text + var confirmText = (settings.confirmText) ? settings.confirmText : gdn.definition('ConfirmText', 'Are you sure you want to do that?'); + $('#'+settings.popupId+' .Content p').text(confirmText); + + var okButtonText = settings.okButtonText; + $('#' + settings.popupId + ' .Okay').val(okButtonText? okButtonText: gdn.definition('Okay', 'Okay')); + + var cancelButtonText = settings.cancelButtonText; + $('#'+settings.popupId+' .Cancel').val((cancelButtonText)?cancelButtonText:gdn.definition('Cancel', 'Cancel')).click(function() { + $.popup.close(settings); + }); + } + } + + $.popup.loading = function(settings) { + settings.onLoad(settings); + if ($('#'+settings.popupId+' .Loading').length == 1) + return true; + + $('#'+settings.popupId+' .Content').empty(); + $('#'+settings.popupId+' .Body').children().hide().end().append('
 
'); + // Trigger an even that plugins can attach to when popups are loading. + $('body').trigger('popupLoading'); + } + + $.popup.load = function(settings) { + if (!settings.confirm) { + $.popup.loading(settings); + } + + var target = $.popup.findTarget(settings); + if (settings.confirm) { + // Bind to the "Okay" button click + $('#'+settings.popupId+' .Okay').focus().click(function() { + if (settings.followConfirm) { + // follow the target + document.location = target; + } else { + // request the target via ajax + var ajaxData = {'DeliveryType' : settings.deliveryType, 'DeliveryMethod' : 'JSON'}; + if (settings.doPost) { + ajaxData.TransientKey = gdn.definition('TransientKey'); + } + $.popup.loading(settings); + + $.ajax({ + method: settings.doPost ? 'POST' : 'GET', + url: target, + data: ajaxData, + dataType: 'json', + error: function(xhr) { + gdn.informError(xhr); + }, + success: function(json) { + $.popup.close(settings); + settings.afterConfirm(json, settings.sender); + gdn.inform(json); + gdn.processTargets(json.Targets); + + if (json.RedirectUrl) + setTimeout(function() { document.location.replace(json.RedirectUrl); }, 300); + } + }); + } + }); + } else { + if (target) { + var ajaxData = { 'DeliveryType': settings.deliveryType }; + if (settings.doPost) { + ajaxData.TransientKey = gdn.definition('TransientKey'); + } + + $.ajax({ + method: settings.doPost ? 'POST' : 'GET', + url: target, + data: ajaxData, + error: function(request, textStatus, errorThrown) { + $.popup.reveal(settings, request.responseText); + }, + success: function(data) { + $.popup.reveal(settings, data); + } + }); +// $.get(target, {'DeliveryType': settings.deliveryType}, function(data) { +// $.popup.reveal(settings, data) +// }); + } + } + } + + $.popup.reveal = function(settings, data) { + // First see if we've retrieved json or something else + var json = false; + if (data instanceof Array) { + json = false; + } else if (data !== null && typeof(data) == 'object') { + json = data; + } + + if (json == false) { + // This is something other than json, so just put it into the popup directly + if (data) { // Prevent blank popups + $('#'+settings.popupId+' .Content').append(data).trigger('contentLoad'); + } + + } else { + gdn.inform(json); + formSaved = json['FormSaved']; + data = json['Data']; + + // Add any js that's come in. + $(json.js).each(function(i, el){ + var v_js = document.createElement('script'); + v_js.type = 'text/javascript'; + v_js.src = gdn.url(el); + document.getElementsByTagName('head')[0].appendChild(v_js); + }); + + // mosullivan - need to always reload the data b/c when uninviting ppl + // we need to reload the invitation table. Is there a reason not to reload + // the content? + // if (formSaved == false) + if (data) { // Prevent blank popups + $('#'+settings.popupId+' .Content').html(data).trigger('contentLoad'); + } + } + + $('#'+settings.popupId+' .Loading').remove(); + $('#'+settings.popupId+' .Body').children().fadeIn('normal'); + + $('#'+settings.popupId+' .Close').unbind().click(function() { + return $.popup.close(settings); + }); + + settings.afterLoad(); + + // Now, if there are any forms in the popup, hijack them if necessary. + if (settings.hijackForms == true) { + $('#'+settings.popupId+' form').ajaxForm({ + data: { + 'DeliveryType': settings.deliveryType, + 'DeliveryMethod': 'JSON' + }, + dataType: 'json', + beforeSubmit: function() { + settings.onSave(settings); // Notify the user that it is being saved. + }, + success: function(json) { + gdn.inform(json); + gdn.processTargets(json.Targets); + + if (json.FormSaved == true) { + if (json.RedirectUrl) + setTimeout(function() { document.location.replace(json.RedirectUrl); }, 300); + + settings.afterSuccess(settings, json); + $.popup.close(settings, json); + } else { + $.popup.reveal(settings, json) // Setup the form again + } + }, + error: function(xhr) { + $('.InProgress', this).removeClass('InProgress'); + gdn.informError(xhr); + } + }); + + + // Hijack links to navigate within the same popup. + $('#'+settings.popupId+' .PopLink').click(function() { + $.popup.loading(settings); + + // Ajax the link into the current popup. + $.get($(this).attr('href'), {'DeliveryType': settings.deliveryType}, function(data, textStatus, xhr) { + if (typeof(data) == 'object') { + if (data.RedirectUrl) + setTimeout(function() { document.location.replace(data.RedirectUrl); }, 300); + } + $.popup.reveal(settings, data); + //$('#'+settings.popupId+' .Content').html(data); + }); + + return false; + }); + } + + // If there is a cancel button in the popup, hide it (the popup has it's own close button) + $('#'+settings.popupId+' a.Cancel').hide(); + + // Trigger an even that plugins can attach to when popups are revealed. + $('body').trigger('popupReveal'); + + return false; + } + + $.popup.settings = { + targetUrl: false, // Use this URL instead of one provided by the matched element? + doPost: false, // Use POST, instead of GET, when performing an AJAX request? + confirm: false, // Pop up a confirm message? + followConfirm: false, // Follow the confirm url after OK, or request it with ajax? + afterConfirm: function(json, sender) { + // Called after the confirm url has been loaded via ajax + }, // Event to fire if the confirm was ajaxed + hijackForms: true, // Hijack popup forms so they are handled in-page instead of posting the entire page back + deliveryType: 'VIEW', // Adds DeliveryType=3 to url so Garden doesn't pull the entire page + mouseoverClass: 'Popable', // CssClass to be applied to a popup link when hovering + onSave: function(settings) { + if (settings.sender) { + $('#'+settings.popupId+' .Button:submit').attr('disabled', true).addClass('InProgress'); + } + }, + onLoad: function(settings) { + // Called before the "loading..." is displayed + }, + onUnload: function(settings, response) { + // Called after the popup is closed + }, + afterSuccess: function() { + // Called after an ajax request resulted in success, and before "close" is called. + }, + containerCssClass: '', + popupHtml: '\ +
\ + \ +
', + confirmHtml: '\ +
\ + \ +
', + afterLoad: function() {} + } + + $.popup.inFrame = function() { + try { + if (top !== self && $(parent.document).width()) + return true; + } catch(e) { } + + return false; + } + + $.popup.getPageSize = function() { + var inFrame = $.popup.inFrame(); + var doc = $(inFrame ? parent.document : document); + var win = $(inFrame ? parent.window : window); + arrayPageSize = new Array( + $(doc).width(), + $(doc).height(), + $(win).width(), + $(win).height() + ); + return arrayPageSize; + }; + + $.popup.getPagePosition = function() { + var inFrame = $.popup.inFrame(); + var doc = $(inFrame ? parent.document : document); + var win = $(inFrame ? parent.window : window); + var scroll = { 'top':doc.scrollTop(), 'left':doc.scrollLeft() }; + var t = scroll.top + ($(win).height() / 10); + if (inFrame) { + var el = $(parent.document).find('iframe[id^=vanilla]'); + el = el ? el : $(document); // Just in case iframe is not id'd properly + t -= (el.offset().top); + // Don't slide above or below the frame bounds. + var diff = $(doc).height() - $(document).height(); + var maxOffset = $(document).height() - diff; + if (t < 0) { + t = 0; + } else if (t > maxOffset) { + t = maxOffset; + } + } + return {'top':t, 'left':scroll.left}; + }; + +})(jQuery);