]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - js/util.js
Merge remote-tracking branch 'mainline/1.0.x' into people_tags_rebase
[quix0rs-gnu-social.git] / js / util.js
index 6bd5d668a9cdddc07d8bfd76f89b0d4ad78c5d04..ee5cbefd8819796985cf58ddd8a0e8612f829922 100644 (file)
@@ -104,7 +104,7 @@ var SN = { // StatusNet
 
                 SN.U.Counter(form);
 
-                NDT = form.find('[name=status_textarea]');
+                NDT = form.find('.notice_data-text:first');
 
                 NDT.bind('keyup', function(e) {
                     SN.U.Counter(form);
@@ -183,7 +183,7 @@ var SN = { // StatusNet
          * @return number of chars
          */
         CharacterCount: function(form) {
-            return form.find('[name=status_textarea]').val().length;
+            return form.find('.notice_data-text:first').val().length;
         },
 
         /**
@@ -253,16 +253,34 @@ var SN = { // StatusNet
                             .attr(SN.C.S.Disabled, SN.C.S.Disabled);
                 },
                 error: function (xhr, textStatus, errorThrown) {
-                    alert(errorThrown || textStatus);
+                    // If the server end reported an error from StatusNet,
+                    // find it -- otherwise we'll see what was reported
+                    // from the browser.
+                    var errorReported = null;
+                    if (xhr.responseXML) {
+                        errorReported = $('#error', xhr.responseXML).text();
+                    }
+                    alert(errorReported || errorThrown || textStatus);
+                    
+                    // Restore the form to original state.
+                    // Hopefully. :D
+                    form
+                        .removeClass(SN.C.S.Processing)
+                        .find('.submit')
+                            .removeClass(SN.C.S.Disabled)
+                            .removeAttr(SN.C.S.Disabled);
                 },
                 success: function(data, textStatus) {
                     if (typeof($('form', data)[0]) != 'undefined') {
                         form_new = document._importNode($('form', data)[0], true);
                         form.replaceWith(form_new);
                     }
-                    else {
+                    else if (typeof($('p', data)[0]) != 'undefined') {
                         form.replaceWith(document._importNode($('p', data)[0], true));
                     }
+                    else {
+                        alert('Unknown error.');
+                    }
                 }
             });
         },
@@ -327,7 +345,7 @@ var SN = { // StatusNet
                 dataType: 'xml',
                 timeout: '60000',
                 beforeSend: function(formData) {
-                    if (form.find('[name=status_textarea]').val() == '') {
+                    if (form.find('.notice_data-text:first').val() == '') {
                         form.addClass(SN.C.S.Warning);
                         return false;
                     }
@@ -394,16 +412,20 @@ var SN = { // StatusNet
                             var replyItem = form.closest('li.notice-reply');
 
                             if (replyItem.length > 0) {
-                                // If this is an inline reply, insert it in place.
+                                // If this is an inline reply, remove the form...
+                                var list = form.closest('.threaded-replies');
+                                var placeholder = list.find('.notice-reply-placeholder');
+                                replyItem.remove();
+
                                 var id = $(notice).attr('id');
                                 if ($("#"+id).length == 0) {
-                                    var parentNotice = replyItem.closest('li.notice');
-                                    replyItem.replaceWith(notice);
-                                    SN.U.NoticeInlineReplyPlaceholder(parentNotice);
+                                    $(notice).insertBefore(placeholder);
                                 } else {
                                     // Realtime came through before us...
-                                    replyItem.remove();
                                 }
+
+                                // ...and show the placeholder form.
+                                placeholder.show();
                             } else if (notices.length > 0 && SN.U.belongsOnTimeline(notice)) {
                                 // Not a reply. If on our timeline, show it at the top!
 
@@ -423,7 +445,7 @@ var SN = { // StatusNet
                                         .css({display:'none'})
                                         .fadeIn(2500);
                                     SN.U.NoticeWithAttachment($('#'+notice.id));
-                                    SN.U.NoticeReplyTo($('#'+notice.id));
+                                    SN.U.switchInputFormTab("placeholder");
                                 }
                             } else {
                                 // Not on a timeline that this belongs on?
@@ -454,6 +476,74 @@ var SN = { // StatusNet
             });
         },
 
+        FormProfileSearchXHR: function(form) {
+            $.ajax({
+                type: 'POST',
+                dataType: 'xml',
+                url: form.attr('action'),
+                data: form.serialize() + '&ajax=1',
+                beforeSend: function(xhr) {
+                    form
+                        .addClass(SN.C.S.Processing)
+                        .find('.submit')
+                            .addClass(SN.C.S.Disabled)
+                            .attr(SN.C.S.Disabled, SN.C.S.Disabled);
+                },
+                error: function (xhr, textStatus, errorThrown) {
+                    alert(errorThrown || textStatus);
+                },
+                success: function(data, textStatus) {
+                    var results_placeholder = $('#profile_search_results');
+                    if (typeof($('ul', data)[0]) != 'undefined') {
+                        var list = document._importNode($('ul', data)[0], true);
+                        results_placeholder.replaceWith(list);
+                    }
+                    else {
+                        var _error = $('<li/>').append(document._importNode($('p', data)[0], true)); 
+                        results_placeholder.html(_error);
+                    }
+                    form
+                        .removeClass(SN.C.S.Processing)
+                        .find('.submit')
+                            .removeClass(SN.C.S.Disabled)
+                            .attr(SN.C.S.Disabled, false);
+                }
+            });
+        },
+
+        FormPeopletagsXHR: function(form) {
+            $.ajax({
+                type: 'POST',
+                dataType: 'xml',
+                url: form.attr('action'),
+                data: form.serialize() + '&ajax=1',
+                beforeSend: function(xhr) {
+                    form.addClass(SN.C.S.Processing)
+                        .find('.submit')
+                            .addClass(SN.C.S.Disabled)
+                            .attr(SN.C.S.Disabled, SN.C.S.Disabled);
+                },
+                error: function (xhr, textStatus, errorThrown) {
+                    alert(errorThrown || textStatus);
+                },
+                success: function(data, textStatus) {
+                    var results_placeholder = form.parents('.entity_tags');
+                    if (typeof($('.entity_tags', data)[0]) != 'undefined') {
+                        var tags = document._importNode($('.entity_tags', data)[0], true);
+                        $(tags).find('.editable').append($('<button class="peopletags_edit_button"/>'));
+                        results_placeholder.replaceWith(tags);
+                    } else {
+                        results_placeholder.find('p').remove();
+                        results_placeholder.append(document._importNode($('p', data)[0], true));
+                        form.removeClass(SN.C.S.Processing)
+                            .find('.submit')
+                                .removeClass(SN.C.S.Disabled)
+                                .attr(SN.C.S.Disabled, false);
+                    }
+                }
+            });
+        },
+
         normalizeGeoData: function(form) {
             SN.C.I.NoticeDataGeo.NLat = form.find('[name=lat]').val();
             SN.C.I.NoticeDataGeo.NLon = form.find('[name=lon]').val();
@@ -483,6 +573,7 @@ var SN = { // StatusNet
             }
 
         },
+
         /**
          * Fetch an XML DOM from an XHR's response data.
          *
@@ -515,32 +606,20 @@ var SN = { // StatusNet
          * @access private
          */
         NoticeReply: function() {
-            if ($('#content .notice_reply').length > 0) {
-                $('#content .notice').each(function() { SN.U.NoticeReplyTo($(this)); });
-            }
+            $('#content .notice_reply').live('click', function(e) {
+                e.preventDefault();
+                var notice = $(this).closest('li.notice');
+                var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
+                SN.U.NoticeInlineReplyTrigger(notice, '@' + nickname.text());
+                return false;
+            });
         },
 
         /**
-         * Setup function -- DOES NOT trigger actions immediately.
-         *
-         * Sets up event handlers on the given notice's reply button to
-         * tweak the new-notice form with needed variables and focus it
-         * when pushed.
-         *
-         * (This replaces the default reply button behavior to submit
-         * directly to a form which comes back with a specialized page
-         * with the form data prefilled.)
-         *
-         * @param {jQuery} notice: jQuery object containing one or more notices
+         * Stub -- kept for compat with plugins for now.
          * @access private
          */
         NoticeReplyTo: function(notice) {
-            notice.find('.notice_reply').live('click', function(e) {
-                e.preventDefault();
-                var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
-                SN.U.NoticeInlineReplyTrigger(notice, '@' + nickname.text());
-                return false;
-            });
         },
 
         /**
@@ -598,8 +677,8 @@ var SN = { // StatusNet
                 // Update the existing form...
                 nextStep();
             } else {
-                // Remove placeholder if any
-                $('li.notice-reply-placeholder').remove();
+                // Hide the placeholder...
+                var placeholder = list.find('li.notice-reply-placeholder').hide();
 
                 // Create the reply form entry at the end
                 var replyItem = $('li.notice-reply', list);
@@ -609,13 +688,10 @@ var SN = { // StatusNet
                     var intermediateStep = function(formMaster) {
                         var formEl = document._importNode(formMaster, true);
                         replyItem.append(formEl);
-                        list.append(replyItem);
+                        list.append(replyItem); // *after* the placeholder
 
                         var form = replyForm = $(formEl);
-                        SN.U.NoticeLocationAttach(form);
-                        SN.U.FormNoticeXHR(form);
-                        SN.U.FormNoticeEnhancements(form);
-                        SN.U.NoticeDataAttach(form);
+                        SN.Init.NoticeFormSetup(form);
 
                         nextStep();
                     };
@@ -641,25 +717,36 @@ var SN = { // StatusNet
             var placeholder = $('<li class="notice-reply-placeholder">' +
                                     '<input class="placeholder">' +
                                 '</li>');
-            placeholder.click(function() {
-                SN.U.NoticeInlineReplyTrigger(notice);
-            });
-            placeholder.find('input').val(SN.msg('reply_placeholder'));
+            placeholder.find('input')
+                .val(SN.msg('reply_placeholder'));
             list.append(placeholder);
         },
 
         /**
          * Setup function -- DOES NOT apply immediately.
          *
-         * Sets up event handlers for favor/disfavor forms to submit via XHR.
+         * Sets up event handlers for inline reply mini-form placeholders.
          * Uses 'live' rather than 'bind', so applies to future as well as present items.
          */
         NoticeInlineReplySetup: function() {
-            $('.threaded-replies').each(function() {
-                var list = $(this);
-                var notice = list.closest('.notice');
-                SN.U.NoticeInlineReplyPlaceholder(notice);
-            });
+            $('li.notice-reply-placeholder input')
+                .live('focus', function() {
+                    var notice = $(this).closest('li.notice');
+                    SN.U.NoticeInlineReplyTrigger(notice);
+                    return false;
+                });
+            $('li.notice-reply-comments a')
+                .live('click', function() {
+                    var url = $(this).attr('href');
+                    var area = $(this).closest('.threaded-replies');
+                    $.get(url, {ajax: 1}, function(data, textStatus, xhr) {
+                        var replies = $('.threaded-replies', data);
+                        if (replies.length) {
+                            area.replaceWith(document._importNode(replies[0], true));
+                        }
+                    });
+                    return false;
+                });
         },
 
         /**
@@ -1018,8 +1105,7 @@ var SN = { // StatusNet
                 }
 
                 var NGW = form.find('.notice_data-geo_wrap');
-                var geocodeURL = NGW.attr('title');
-                NGW.removeAttr('title');
+                var geocodeURL = NGW.attr('data-api');
 
                 label
                     .attr('title', label.text());
@@ -1119,6 +1205,7 @@ var SN = { // StatusNet
                 wrapper = $('<div class="'+SN.C.S.Success+' geo_status_wrapper"><button class="close" style="float:right">&#215;</button><div class="geo_status"></div></div>');
                 wrapper.find('button.close').click(function() {
                     form.find('[name=notice_data-geo]').removeAttr('checked').change();
+                    return false;
                 });
                 form.append(wrapper);
             }
@@ -1290,10 +1377,22 @@ var SN = { // StatusNet
        switchInputFormTab: function(tag) {
            // The one that's current isn't current anymore
            $('.input_form_nav_tab.current').removeClass('current');
-           $('#input_form_nav_'+tag).addClass('current');
+            if (tag == 'placeholder') {
+                // Hack: when showing the placeholder, mark the tab
+                // as current for 'Status'.
+                $('#input_form_nav_status').addClass('current');
+            } else {
+                $('#input_form_nav_'+tag).addClass('current');
+            }
 
            $('.input_form.current').removeClass('current');
-           $('#input_form_'+tag).addClass('current');
+           $('#input_form_'+tag)
+                .addClass('current')
+                .find('.ajax-notice').each(function() {
+                    var form = $(this);
+                    SN.Init.NoticeFormSetup(form);
+                })
+                .find('textarea:first').focus();
        }
     },
 
@@ -1308,16 +1407,70 @@ var SN = { // StatusNet
          */
         NoticeForm: function() {
             if ($('body.user_in').length > 0) {
-                $('.ajax-notice').each(function() {
-                    var form = $(this);
-                    SN.U.NoticeLocationAttach(form);
-                    SN.U.FormNoticeXHR(form);
-                    SN.U.FormNoticeEnhancements(form);
-                    SN.U.NoticeDataAttach(form);
+                // SN.Init.NoticeFormSetup() will get run
+                // when forms get displayed for the first time...
+
+                // Hack to initialize the placeholder at top
+                $('#input_form_placeholder input.placeholder').focus(function() {
+                    SN.U.switchInputFormTab("status");
+                });
+
+                // Make inline reply forms self-close when clicking out.
+                $('body').bind('click', function(e) {
+                    var currentForm = $('#content .input_forms div.current');
+                    if (currentForm.length > 0) {
+                        if ($('#content .input_forms').has(e.target).length == 0) {
+                            // If all fields are empty, switch back to the placeholder.
+                            var fields = currentForm.find('textarea, input[type=text], input[type=""]');
+                            var anything = false;
+                            fields.each(function() {
+                                anything = anything || $(this).val();
+                            });
+                            if (!anything) {
+                                SN.U.switchInputFormTab("placeholder");
+                            }
+                        }
+                    }
+
+                    var openReplies = $('li.notice-reply');
+                    if (openReplies.length > 0) {
+                        var target = $(e.target);
+                        openReplies.each(function() {
+                            // Did we click outside this one?
+                            var replyItem = $(this);
+                            if (replyItem.has(e.target).length == 0) {
+                                var textarea = replyItem.find('.notice_data-text:first');
+                                var cur = $.trim(textarea.val());
+                                // Only close if there's been no edit.
+                                if (cur == '' || cur == textarea.data('initialText')) {
+                                    var parentNotice = replyItem.closest('li.notice');
+                                    replyItem.remove();
+                                    parentNotice.find('li.notice-reply-placeholder').show();
+                                }
+                            }
+                        });
+                    }
                 });
             }
         },
 
+        /**
+         * Encapsulate notice form setup for a single form.
+         * Plugins can add extra setup by monkeypatching this
+         * function.
+         *
+         * @param {jQuery} form
+         */
+        NoticeFormSetup: function(form) {
+            if (!form.data('NoticeFormSetup')) {
+                SN.U.NoticeLocationAttach(form);
+                SN.U.FormNoticeXHR(form);
+                SN.U.FormNoticeEnhancements(form);
+                SN.U.NoticeDataAttach(form);
+                form.data('NoticeFormSetup', true);
+            }
+        },
+
         /**
          * Run setup code for notice timeline views items:
          *
@@ -1346,10 +1499,28 @@ var SN = { // StatusNet
          */
         EntityActions: function() {
             if ($('body.user_in').length > 0) {
+                $('.form_user_subscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_user_unsubscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_group_join').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_group_leave').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_user_nudge').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_peopletag_subscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_peopletag_unsubscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_user_add_peopletag').live('click', function() { SN.U.FormXHR($(this)); return false; });
+                $('.form_user_remove_peopletag').live('click', function() { SN.U.FormXHR($(this)); return false; });
+
                 SN.U.NewDirectMessage();
             }
         },
 
+        ProfileSearch: function() {
+            if ($('body.user_in').length > 0) {
+                $('.form_peopletag_edit_user_search input.submit').live('click', function() {
+                    SN.U.FormProfileSearchXHR($(this).parents('form')); return false;
+                });
+            }
+        },
+
         /**
          * Run setup code for login form:
          *
@@ -1372,6 +1543,45 @@ var SN = { // StatusNet
             });
         },
 
+        PeopletagAutocomplete: function() {
+            $('.form_tag_user #tags').tagInput({
+                tags: SN.C.PtagACData,
+                tagSeparator: " ",
+                animate: false,
+                formatLine: function (i, e, search, matches) {
+                  var tag = "<b>" + e.tag.substring(0, search.length) + "</b>" + e.tag.substring(search.length);
+
+                  var line = $("<div/>").addClass('mode-' + e.mode);
+                    line.append($("<div class='tagInputLineTag'>" + tag
+                        + " <em class='privacy_mode'>" + e.mode + "</em></div>"));
+                  if (e.freq)
+                    line.append("<div class='tagInputLineFreq'>" + e.freq + "</div>");
+                  return line;
+                }
+            });
+        },
+
+        PeopleTags: function() {
+            $('.user_profile_tags .editable').append($('<button class="peopletags_edit_button"/>'));
+
+            $('.peopletags_edit_button').live('click', function() {
+                var form = $(this).parents('dd').eq(0).find('form');
+                // We can buy time from the above animation
+                if (typeof SN.C.PtagACData === 'undefined') {
+                    $.getJSON(_peopletagAC + '?token=' + $('#token').val(), function(data) {
+                        SN.C.PtagACData = data;
+                        _loadTagInput(SN.Init.PeopletagAutocomplete);
+                    });
+                } else { _loadTagInput(SN.Init.PeopletagAutocomplete); }
+
+                $(this).parents('ul').eq(0).fadeOut(200, function() {form.fadeIn(200).find('input#tags')});
+            })
+
+            $('.user_profile_tags form .submit').live('click', function() {
+                SN.U.FormPeopletagsXHR($(this).parents('form')); return false;
+            });
+        },
+
         /**
          * Set up any generic 'ajax' form so it submits via AJAX with auto-replacement.
          */
@@ -1380,6 +1590,18 @@ var SN = { // StatusNet
                 SN.U.FormXHR($(this));
                 return false;
             });
+            $('form.ajax input[type=submit]').live('click', function() {
+                // Some forms rely on knowing which submit button was clicked.
+                // Save a hidden input field which'll be picked up during AJAX
+                // submit...
+                var button = $(this);
+                var form = button.closest('form');
+                form.find('.hidden-submit-button').remove();
+                $('<input class="hidden-submit-button" type="hidden" />')
+                    .attr('name', button.attr('name'))
+                    .val(button.val())
+                    .appendTo(form);
+            });
         },
 
         /**
@@ -1432,4 +1654,10 @@ $(document).ready(function(){
     if ($('#form_login').length > 0) {
         SN.Init.Login();
     }
+    if ($('#profile_search_results').length > 0) {
+        SN.Init.ProfileSearch();
+    }
+    if ($('.user_profile_tags .editable').length > 0) {
+        SN.Init.PeopleTags();
+    }
 });