]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - js/util.js
[CORE][FRAMEWORK] URL_REGEX_VALID_PATH_CHARS didn't recognize the parenthesis sign.
[quix0rs-gnu-social.git] / js / util.js
index e1b26a20d926fe03f05f9c39d5ab8fccae97111b..b645e8b0298aa1dc0d5e218acac82f979f02aa6e 100644 (file)
@@ -32,7 +32,6 @@ var SN = { // StatusNet
             MaxLength: 140,
             PatternUsername: /^[0-9a-zA-Z\-_.]*$/,
             HTTP20x30x: [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307],
-            NoticeFormMaster: null // to be cloned from the one at top
         },
 
         /**
@@ -54,10 +53,20 @@ var SN = { // StatusNet
             NoticeDataGeo: 'notice_data-geo',
             NoticeDataGeoCookie: 'NoticeDataGeo',
             NoticeDataGeoSelected: 'notice_data-geo_selected',
-            StatusNetInstance: 'StatusNetInstance'
         }
     },
 
+    V: {    // Variables
+        // These get set on runtime via inline scripting, so don't put anything here.
+    },
+
+    /**
+     * list of callbacks, categorized into _callbacks['event_name'] = [ callback_function_1, callback_function_2 ]
+     *
+     * @access private
+     */
+    _callbacks: {},
+
     /**
      * Map of localized message strings exported to script from the PHP
      * side via Action::getScriptMessages().
@@ -94,12 +103,12 @@ var SN = { // StatusNet
          * @access private
          */
         FormNoticeEnhancements: function (form) {
-            if (jQuery.data(form[0], 'ElementData') === undefined) {
+            if ($.data(form[0], 'ElementData') === undefined) {
                 var MaxLength = form.find('.count').text();
                 if (MaxLength === undefined) {
                     MaxLength = SN.C.I.MaxLength;
                 }
-                jQuery.data(form[0], 'ElementData', {MaxLength: MaxLength});
+                $.data(form[0], 'ElementData', {MaxLength: MaxLength});
 
                 SN.U.Counter(form);
 
@@ -122,7 +131,7 @@ var SN = { // StatusNet
                 NDT.on('cut', delayedUpdate)
                     .on('paste', delayedUpdate);
             } else {
-                form.find('.count').text(jQuery.data(form[0], 'ElementData').MaxLength);
+                form.find('.count').text($.data(form[0], 'ElementData').MaxLength);
             }
         },
 
@@ -143,7 +152,7 @@ var SN = { // StatusNet
         Counter: function (form) {
             SN.C.I.FormNoticeCurrent = form;
 
-            var MaxLength = jQuery.data(form[0], 'ElementData').MaxLength;
+            var MaxLength = $.data(form[0], 'ElementData').MaxLength;
 
             if (MaxLength <= 0) {
                 return;
@@ -217,6 +226,27 @@ var SN = { // StatusNet
             return url;
         },
 
+        FormNoticeUniqueID: function (form) {
+            var oldId = form.attr('id');
+            var newId = 'form_notice_' + Math.floor(Math.random()*999999999);
+            var attrs = ['name', 'for', 'id'];
+            for (var key in attrs) {
+                if (form.attr(attrs[key]) === undefined) {
+                    continue;
+                }
+                form.attr(attrs[key], form.attr(attrs[key]).replace(oldId, newId));
+            }
+            for (var key in attrs) {
+                form.find("[" + attrs[key] + "*='" + oldId + "']").each(function () {
+                        if ($(this).attr(attrs[key]) === undefined) {
+                            return; // since we're inside the each(function () { ... });
+                        }
+                        var newAttr = $(this).attr(attrs[key]).replace(oldId, newId);
+                        $(this).attr(attrs[key], newAttr);
+                    });
+            }
+        },
+
         /**
          * Grabs form data and submits it asynchronously, with 'ajax=1'
          * parameter added to the rest.
@@ -320,21 +350,6 @@ var SN = { // StatusNet
             // Make sure we don't have a mixed HTTP/HTTPS submission...
             form.attr('action', SN.U.RewriteAjaxAction(form.attr('action')));
 
-            /**
-             * Show a response feedback bit under the new-notice dialog.
-             *
-             * @param {String} cls: CSS class name to use ('error' or 'success')
-             * @param {String} text
-             * @access private
-             */
-            var showFeedback = function (cls, text) {
-                form.append(
-                    $('<p class="form_response"></p>')
-                        .addClass(cls)
-                        .text(text)
-                );
-            };
-
             /**
              * Hide the previous response feedback, if any.
              */
@@ -344,7 +359,7 @@ var SN = { // StatusNet
 
             form.ajaxForm({
                 dataType: 'xml',
-                timeout: '60000',
+                timeout: SN.V.xhrTimeout,
                 beforeSend: function (formData) {
                     if (form.find('.notice_data-text:first').val() == '') {
                         form.addClass(SN.C.S.Warning);
@@ -369,20 +384,20 @@ var SN = { // StatusNet
                     removeFeedback();
                     if (textStatus == 'timeout') {
                         // @fixme i18n
-                        showFeedback('error', 'Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.');
+                        SN.U.showFeedback(form, 'error', 'Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.');
                     } else {
                         var response = SN.U.GetResponseXML(xhr);
                         if ($('.' + SN.C.S.Error, response).length > 0) {
                             form.append(document._importNode($('.' + SN.C.S.Error, response)[0], true));
                         } else {
-                            if (parseInt(xhr.status) === 0 || jQuery.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) >= 0) {
+                            if (parseInt(xhr.status) === 0 || $.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) >= 0) {
                                 form
                                     .resetForm()
                                     .find('.attach-status').remove();
                                 SN.U.FormNoticeEnhancements(form);
                             } else {
                                 // @fixme i18n
-                                showFeedback('error', '(Sorry! We had trouble sending your notice (' + xhr.status + ' ' + xhr.statusText + '). Please report the problem to the site administrator if this happens again.');
+                                SN.U.showFeedback(form, 'error', '(Sorry! We had trouble sending your notice (' + xhr.status + ' ' + xhr.statusText + '). Please report the problem to the site administrator if this happens again.');
                             }
                         }
                     }
@@ -391,61 +406,9 @@ var SN = { // StatusNet
                     removeFeedback();
                     var errorResult = $('#' + SN.C.S.Error, data);
                     if (errorResult.length > 0) {
-                        showFeedback('error', errorResult.text());
+                        SN.U.showFeedback(form, 'error', errorResult.text());
                     } else {
-                        var commandResult = $('#' + SN.C.S.CommandResult, data);
-                        if (commandResult.length > 0) {
-                            showFeedback('success', commandResult.text());
-                        } else {
-                            // New notice post was successful. If on our timeline, show it!
-                            var notice = document._importNode($('li', data)[0], true);
-                            var notices = $('#notices_primary .notices:first');
-                            var replyItem = form.closest('li.notice-reply');
-
-                            if (replyItem.length > 0) {
-                                // 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) {
-                                    $(notice).insertBefore(placeholder);
-                                } // else Realtime came through before us...
-
-                                // ...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!
-
-                                if ($('#' + notice.id).length === 0) {
-                                    var notice_irt_value = form.find('[name=inreplyto]').val();
-                                    var notice_irt = '#notices_primary #notice-' + notice_irt_value;
-                                    if ($('body')[0].id == 'conversation') {
-                                        if (notice_irt_value.length > 0 && $(notice_irt + ' .notices').length < 1) {
-                                            $(notice_irt).append('<ul class="notices"></ul>');
-                                        }
-                                        $($(notice_irt + ' .notices')[0]).append(notice);
-                                    } else {
-                                        notices.prepend(notice);
-                                    }
-                                    $('#' + notice.id)
-                                        .css({display: 'none'})
-                                        .fadeIn(2500);
-                                    SN.U.NoticeWithAttachment($('#' + notice.id));
-                                    SN.U.switchInputFormTab(null);
-                                }
-                            } else {
-                                // Not on a timeline that this belongs on?
-                                // Just show a success message.
-                                // @fixme inline
-                                showFeedback('success', $('title', data).text());
-                            }
-                        }
-                        form.resetForm();
-                        form.find('[name=inreplyto]').val('');
-                        form.find('.attach-status').remove();
-                        SN.U.FormNoticeEnhancements(form);
+                        SN.E.ajaxNoticePosted(form, data, textStatus);
                     }
                 },
                 complete: function (xhr, textStatus) {
@@ -578,6 +541,44 @@ var SN = { // StatusNet
             }
         },
 
+        /**
+         * Setup function -- DOES NOT trigger actions immediately.
+         *
+         * Sets up event handlers on all visible notice's option <a> elements
+         * with the "popup" class so they behave as expected with AJAX.
+         *
+         * (without javascript the link goes to a page that expects you to verify
+         * the action through a form)
+         *
+         * @access private
+         */
+        NoticeOptionsAjax: function () {
+            $(document).on('click', '.notice-options > a.popup', function (e) {
+                e.preventDefault();
+                var noticeEl = $(this).closest('.notice');
+                $.ajax({
+                    url: $(this).attr('href'),
+                    data: {ajax: 1},
+                    success: function (data, textStatus, xhr) {
+                        SN.U.NoticeOptionPopup(data, noticeEl);
+                    },
+                });
+                return false;
+            });
+        },
+
+        NoticeOptionPopup: function (data, noticeEl) {
+            title = $('head > title', data).text();
+            body = $('body', data).html();
+            dialog = $(body).dialog({
+                    height: "auto",
+                    width: "auto",
+                    modal: true,
+                    resizable: true,
+                    title: title,
+                });
+        },
+
         /**
          * Setup function -- DOES NOT trigger actions immediately.
          *
@@ -616,41 +617,18 @@ var SN = { // StatusNet
         NoticeInlineReplyTrigger: function (notice, initialText) {
             // Find the notice we're replying to...
             var id = $($('.notice_id', notice)[0]).text();
-            var replyForm, placeholder;
+            var replyForm;
             var parentNotice = notice;
             var stripForm = true; // strip a couple things out of reply forms that are inline
 
-            // Find the threaded replies view we'll be adding to...
-            var list = notice.closest('.notices');
-            if (list.closest('.old-school').length) {
-                // We're replying to an old-school conversation thread;
-                // use the old-style ping into the top form.
-                SN.U.switchInputFormTab("status");
-                replyForm = $('#input_form_status').find('form');
-                stripForm = false;
-            } else if (list.hasClass('threaded-replies')) {
-                // We're replying to a reply; use reply form on the end of this list.
-                // We'll add our form at the end of this; grab the root notice.
-                parentNotice = list.closest('.notice');
-
-                // See if the form's already open...
-                replyForm = $('.notice-reply-form', list);
-            } else {
-                // We're replying to a parent notice; pull its threaded list
-                // and we'll add on the end of it. Will add if needed.
-                list = $('ul.threaded-replies', notice);
-                if (list.length == 0) {
-                    SN.U.NoticeInlineReplyPlaceholder(notice);
-                    list = $('ul.threaded-replies', notice);
-                } else {
-                    placeholder = $('li.notice-reply-placeholder', notice);
-                    if (placeholder.length == 0) {
-                        SN.U.NoticeInlineReplyPlaceholder(notice);
-                    }
-                }
-
-                // See if the form's already open...
-                replyForm = $('.notice-reply-form', list);
+            var list = notice.find('.threaded-replies');
+            if (list.length == 0) {
+                list = notice.closest('.threaded-replies');
+            }
+            if (list.length == 0) {
+                list = $('<ul class="notices threaded-replies xoxo"></ul>');
+                notice.append(list);
+                list = notice.find('.threaded-replies');
             }
 
             var nextStep = function () {
@@ -663,6 +641,7 @@ var SN = { // StatusNet
                     replyForm.find('label[for=notice_to]').hide();
                     replyForm.find('label[for=notice_private]').hide();
                 }
+                replyItem.show();
 
                 // Set focus...
                 var text = replyForm.find('textarea');
@@ -681,82 +660,64 @@ var SN = { // StatusNet
                     text[0].setSelectionRange(len, len);
                 }
             };
-            if (replyForm.length > 0) {
-                // Update the existing form...
-                nextStep();
-            } else {
-                // Hide the placeholder...
-                placeholder = list.find('li.notice-reply-placeholder').hide();
 
-                // Create the reply form entry at the end
-                var replyItem = $('li.notice-reply', list);
-                if (replyItem.length == 0) {
-                    replyItem = $('<li class="notice-reply"></li>');
-
-                    var intermediateStep = function (formMaster) {
-                        var formEl = document._importNode(formMaster, true);
-                        replyItem.append(formEl);
-                        list.append(replyItem); // *after* the placeholder
-
-                        var form = $(formEl);
-                        replyForm = form;
-                        SN.Init.NoticeFormSetup(form);
-
-                        nextStep();
-                    };
-                    if (SN.C.I.NoticeFormMaster) {
-                        // We've already saved a master copy of the form.
-                        // Clone it in!
-                        intermediateStep(SN.C.I.NoticeFormMaster);
-                    } else {
-                        // Fetch a fresh copy of the notice form over AJAX.
-                        // Warning: this can have a delay, which looks bad.
-                        // @fixme this fallback may or may not work
-                        var url = $('#form_notice').attr('action');
-                        $.get(url, {ajax: 1}, function (data, textStatus, xhr) {
-                            intermediateStep($('form', data)[0]);
-                        });
-                    }
-                }
+            // Create the reply form entry
+            var replyItem = $('li.notice-reply', list);
+            if (replyItem.length == 0) {
+                replyItem = $('<li class="notice-reply"></li>');
             }
-        },
-
-        NoticeInlineReplyPlaceholder: function (notice) {
-            var list = notice.find('ul.threaded-replies');
-            if (list.length == 0) {
-                list = $('<ul class="notices threaded-replies xoxo"></ul>');
-                notice.append(list);
-                list = notice.find('ul.threaded-replies');
+            replyForm = replyItem.children('form');
+            if (replyForm.length == 0) {
+                // Let's try another trick to avoid fetching by URL
+                var noticeForm = $('#input_form_status > form');
+                if (noticeForm.length == 0) {
+                    // No notice form found on the page, so let's just
+                    // fetch a fresh copy of the notice form over AJAX.
+                    $.ajax({
+                        url: SN.V.urlNewNotice,
+                        data: {ajax: 1, inreplyto: id},
+                        success: function (data, textStatus, xhr) {
+                            var formEl = document._importNode($('form', data)[0], true);
+                            replyForm = $(formEl);
+                            replyItem.append(replyForm);
+                            list.append(replyItem);
+
+                            SN.Init.NoticeFormSetup(replyForm);
+                            nextStep();
+                        },
+                    });
+                    // We do everything relevant in 'success' above
+                    return;
+                }
+                replyForm = noticeForm.clone();
+                SN.Init.NoticeFormSetup(replyForm);
+                replyItem.append(replyForm);
+                list.append(replyItem);
             }
-            var placeholder = $('<li class="notice-reply-placeholder">' +
-                                    '<input class="placeholder" />' +
-                                '</li>');
-            placeholder.find('input')
-                .val(SN.msg('reply_placeholder'));
-            list.append(placeholder);
+            // replyForm is set, we're not fetching by URL...
+            // Next setp is to configure in-reply-to etc.
+            nextStep();
         },
 
         /**
          * Setup function -- DOES NOT apply immediately.
          *
-         * Sets up event handlers for inline reply mini-form placeholders.
          * Uses 'on' rather than 'live' or 'bind', so applies to future as well as present items.
          */
         NoticeInlineReplySetup: function () {
-            $('li.notice-reply-placeholder input')
-                .on('focus', function () {
-                    var notice = $(this).closest('li.notice');
-                    SN.U.NoticeInlineReplyTrigger(notice);
-                    return false;
-                });
+            // Expand conversation links
             $(document).on('click', 'li.notice-reply-comments a', 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));
-                        }
+                    $.ajax({
+                        url: url,
+                        data: {ajax: 1},
+                        success: function (data, textStatus, xhr) {
+                            var replies = $('.threaded-replies', data);
+                            if (replies.length) {
+                                area.replaceWith(document._importNode(replies[0], true));
+                            }
+                        },
                     });
                     return false;
                 });
@@ -810,7 +771,7 @@ var SN = { // StatusNet
 
             form
                 .addClass('dialogbox')
-                .append('<button class="close">&#215;</button>')
+                .append('<button class="close" title="' + SN.msg('popup_close_button') + '">&#215;</button>')
                 .closest('.notice-options')
                     .addClass('opaque');
 
@@ -887,27 +848,29 @@ var SN = { // StatusNet
             NDA.change(function (event) {
                 form.find('.attach-status').remove();
 
-                var filename = $(this).val();
-                if (!filename) {
-                    // No file -- we've been tricked!
-                    return false;
-                }
-
-                var attachStatus = $('<div class="attach-status ' + SN.C.S.Success + '"><code></code> <button class="close">&#215;</button></div>');
-                attachStatus.find('code').text(filename);
-                attachStatus.find('button').click(function () {
-                    attachStatus.remove();
-                    NDA.val('');
-
-                    return false;
-                });
-                form.append(attachStatus);
-
                 if (typeof this.files === "object") {
+                    var attachStatus = $('<ul class="attach-status ' + SN.C.S.Success + '"></ul>');
+                    form.append(attachStatus);
                     // Some newer browsers will let us fetch the files for preview.
                     for (i = 0; i < this.files.length; i++) {
                         SN.U.PreviewAttach(form, this.files[i]);
                     }
+                } else {
+                    var filename = $(this).val();
+                    if (!filename) {
+                        // No file -- we've been tricked!
+                        return false;
+                    }
+
+                    var attachStatus = $('<div class="attach-status ' + SN.C.S.Success + '"><code></code> <button class="close">&#215;</button></div>');
+                    attachStatus.find('code').text(filename);
+                    attachStatus.find('button').click(function () {
+                        attachStatus.remove();
+                        NDA.val('');
+
+                        return false;
+                    });
+                    form.append(attachStatus);
                 }
             });
         },
@@ -1003,12 +966,15 @@ var SN = { // StatusNet
 
             if (preview) {
                 blobAsDataURL(file, function (url) {
+                    var fileentry = $('<li class="attachment"></li>');
+                    fileentry.append($('<code>' + file.name + '</code>'));
                     var img = $('<img>')
                         .attr('title', tooltip)
                         .attr('alt', tooltip)
                         .attr('src', url)
                         .attr('style', 'height: 120px');
-                    form.find('.attach-status').append(img);
+                    fileentry.append(img);
+                    form.find('.attach-status').append(fileentry);
                 });
             } else {
                 var img = $('<div></div>').text(tooltip);
@@ -1043,7 +1009,7 @@ var SN = { // StatusNet
 
             function removeNoticeDataGeo(error) {
                 label
-                    .attr('title', jQuery.trim(label.text()))
+                    .attr('title', $.trim(label.text()))
                     .removeClass('checked');
 
                 form.find('[name=lat]').val('');
@@ -1120,12 +1086,12 @@ var SN = { // StatusNet
                 label.attr('title', label.text());
 
                 check.change(function () {
-                    if (check.prop('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === null) {
+                    if (check.prop('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === undefined) {
                         label
                             .attr('title', NoticeDataGeo_text.ShareDisable)
                             .addClass('checked');
 
-                        if ($.cookie(SN.C.S.NoticeDataGeoCookie) === null || $.cookie(SN.C.S.NoticeDataGeoCookie) == 'disabled') {
+                        if ($.cookie(SN.C.S.NoticeDataGeoCookie) === undefined || $.cookie(SN.C.S.NoticeDataGeoCookie) == 'disabled') {
                             if (navigator.geolocation) {
                                 SN.U.NoticeGeoStatus(form, 'Requesting location from browser...');
                                 navigator.geolocation.getCurrentPosition(
@@ -1290,56 +1256,6 @@ var SN = { // StatusNet
             return date;
         },
 
-        /**
-         * Some sort of object interface for storing some structured
-         * information in a cookie.
-         *
-         * Appears to be used to save the last-used login nickname?
-         * That's something that browsers usually take care of for us
-         * these days, do we really need to do it? Does anything else
-         * use this interface?
-         *
-         * @fixme what is this?
-         * @fixme should this use non-cookie local storage when available?
-         */
-        StatusNetInstance: {
-            /**
-             * @fixme what is this?
-             */
-            Set: function (value) {
-                var SNI = SN.U.StatusNetInstance.Get();
-                if (SNI !== null) {
-                    value = $.extend(SNI, value);
-                }
-
-                $.cookie(
-                    SN.C.S.StatusNetInstance,
-                    JSON.stringify(value),
-                    {
-                        path: '/',
-                        expires: SN.U.GetFullYear(2029, 0, 1)
-                    });
-            },
-
-            /**
-             * @fixme what is this?
-             */
-            Get: function () {
-                var cookieValue = $.cookie(SN.C.S.StatusNetInstance);
-                if (cookieValue !== undefined) {
-                    return JSON.parse(cookieValue);
-                }
-                return null;
-            },
-
-            /**
-             * @fixme what is this?
-             */
-            Delete: function () {
-                $.cookie(SN.C.S.StatusNetInstance, null);
-            }
-        },
-
         /**
          * Check if the current page is a timeline where the current user's
          * posts should be displayed immediately on success.
@@ -1382,7 +1298,8 @@ var SN = { // StatusNet
          *
          * @param {String} tag
          */
-        switchInputFormTab: function (tag) {
+        switchInputFormTab: function (tag, setFocus) {
+            if (typeof setFocus === 'undefined') { setFocus = true; }
             // The one that's current isn't current anymore
             $('.input_form_nav_tab.current').removeClass('current');
             if (tag != null) {
@@ -1403,13 +1320,15 @@ var SN = { // StatusNet
                 return false;
             }
 
-            $('#input_form_' + tag)
+            var noticeForm = $('#input_form_' + tag)
                     .addClass('current')
                     .find('.ajax-notice').each(function () {
                         var form = $(this);
                         SN.Init.NoticeFormSetup(form);
-                    })
-                    .find('.notice_data-text').focus();
+                    });
+            if (setFocus) {
+                noticeForm.find('.notice_data-text').focus();
+            }
 
             return false;
         },
@@ -1420,9 +1339,106 @@ var SN = { // StatusNet
             var extended = $(selector);
             extended.removeClass('extended_menu');
             return void(0);
+        },
+
+        /**
+         * Show a response feedback bit under a form.
+         *
+         * @param {Element} form: the new-notice form usually
+         * @param {String}  cls: CSS class name to use ('error' or 'success')
+         * @param {String}  text
+         * @access public
+         */
+        showFeedback: function (form, cls, text) {
+            form.append(
+                $('<p class="form_response"></p>')
+                    .addClass(cls)
+                    .text(text)
+            );
+        },
+
+        addCallback: function (ename, callback) {
+            // initialize to array if it's undefined
+            if (typeof SN._callbacks[ename] === 'undefined') {
+                SN._callbacks[ename] = [];
+            }
+            SN._callbacks[ename].push(callback);
+        },
+
+        runCallbacks: function (ename, data) {
+            if (typeof SN._callbacks[ename] === 'undefined') {
+                return;
+            }
+            for (cbname in SN._callbacks[ename]) {
+                SN._callbacks[ename][cbname](data);
+            }
         }
     },
 
+    E: {    /* Events */
+        /* SN.E.ajaxNoticePosted, called when a notice has been posted successfully via an AJAX form
+            @param  form        the originating form element
+            @param  data        data from success() callback
+            @param  textStatus  textStatus from success() callback
+        */
+        ajaxNoticePosted: function (form, data, textStatus) {
+            var commandResult = $('#' + SN.C.S.CommandResult, data);
+            if (commandResult.length > 0) {
+                SN.U.showFeedback(form, 'success', commandResult.text());
+            } else {
+                // New notice post was successful. If on our timeline, show it!
+                var notice = document._importNode($('li', data)[0], true);
+                var notices = $('#notices_primary .notices:first');
+                var replyItem = form.closest('li.notice-reply');
+
+                if (replyItem.length > 0) {
+                    // If this is an inline reply, remove the form...
+                    var list = form.closest('.threaded-replies');
+
+                    var id = $(notice).attr('id');
+                    if ($('#' + id).length == 0) {
+                        $(notice).insertBefore(replyItem);
+                    } // else Realtime came through before us...
+
+                    replyItem.remove();
+
+                } else if (notices.length > 0 && SN.U.belongsOnTimeline(notice)) {
+                    // Not a reply. If on our timeline, show it at the top!
+
+                    if ($('#' + notice.id).length === 0) {
+                        var notice_irt_value = form.find('[name=inreplyto]').val();
+                        var notice_irt = '#notices_primary #notice-' + notice_irt_value;
+                        if ($('body')[0].id == 'conversation') {
+                            if (notice_irt_value.length > 0 && $(notice_irt + ' .notices').length < 1) {
+                                $(notice_irt).append('<ul class="notices"></ul>');
+                            }
+                            $($(notice_irt + ' .notices')[0]).append(notice);
+                        } else {
+                            notices.prepend(notice);
+                        }
+                        $('#' + notice.id)
+                            .css({display: 'none'})
+                            .fadeIn(2500);
+                        SN.U.NoticeWithAttachment($('#' + notice.id));
+                        SN.U.switchInputFormTab(null);
+                    }
+                } else {
+                    // Not on a timeline that this belongs on?
+                    // Just show a success message.
+                    // @fixme inline
+                    SN.U.showFeedback(form, 'success', $('title', data).text());
+                }
+            }
+            form.resetForm();
+            form.find('[name=inreplyto]').val('');
+            form.find('.attach-status').remove();
+            SN.U.FormNoticeEnhancements(form);
+
+            SN.U.runCallbacks('notice_posted', {"notice": notice});
+        }, 
+    },
+
+
     Init: {
         /**
          * If user is logged in, run setup code for the new notice form:
@@ -1437,16 +1453,11 @@ var SN = { // StatusNet
                 // SN.Init.NoticeFormSetup() will get run
                 // when forms get displayed for the first time...
 
-                // Initially hide all tabs on the top of the page
-                // if there's no data in there yet.
-                var fields = $('#content .input_forms .input_form.current').find('textarea, input[type=text], input[type=""]');
-                var anything = false;
-                fields.each(function () {
-                    anything = anything || $(this).val();
+                // Initialize the input form field
+                $('#input_form_nav .input_form_nav_tab.current').each(function () {
+                    current_tab_id = $(this).attr('id').substring('input_form_nav_'.length);
+                    SN.U.switchInputFormTab(current_tab_id, false);
                 });
-                if (!anything) {
-                    SN.U.switchInputFormTab(null);
-                }
 
                 // Make inline reply forms self-close when clicking out.
                 $('body').on('click', function (e) {
@@ -1462,16 +1473,13 @@ var SN = { // StatusNet
                                 // Only close if there's been no edit.
                                 if (cur == '' || cur == textarea.data('initialText')) {
                                     var parentNotice = replyItem.closest('li.notice');
-                                    replyItem.remove();
+                                    replyItem.hide();
                                     parentNotice.find('li.notice-reply-placeholder').show();
                                 }
                             }
                         });
                     }
                 });
-
-                // Infield labels for notice form inputs.
-                $('.input_forms fieldset fieldset label').inFieldLabels({ fadeOpacity:0 });
             }
         },
 
@@ -1483,13 +1491,15 @@ var SN = { // StatusNet
          * @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);
+            if (form.data('NoticeFormSetup')) {
+                return false;
             }
+            SN.U.NoticeLocationAttach(form);
+            SN.U.FormNoticeUniqueID(form);
+            SN.U.FormNoticeXHR(form);
+            SN.U.FormNoticeEnhancements(form);
+            SN.U.NoticeDataAttach(form);
+            form.data('NoticeFormSetup', true);
         },
 
         /**
@@ -1500,13 +1510,10 @@ var SN = { // StatusNet
          */
         Notices: function () {
             if ($('body.user_in').length > 0) {
-                var masterForm = $('.form_notice:first');
-                if (masterForm.length > 0) {
-                    SN.C.I.NoticeFormMaster = document._importNode(masterForm[0], true);
-                }
                 SN.U.NoticeRepeat();
                 SN.U.NoticeReply();
                 SN.U.NoticeInlineReplySetup();
+                SN.U.NoticeOptionsAjax();
             }
 
             SN.U.NoticeAttachments();
@@ -1542,82 +1549,6 @@ var SN = { // StatusNet
             }
         },
 
-        /**
-         * Run setup code for login form:
-         *
-         * - loads saved last-used-nickname from cookie
-         * - sets event handler to save nickname to cookie on submit
-         *
-         * @fixme is this necessary? Browsers do their own form saving these days.
-         */
-        Login: function () {
-            if (SN.U.StatusNetInstance.Get() !== null) {
-                var nickname = SN.U.StatusNetInstance.Get().Nickname;
-                if (nickname !== null) {
-                    $('#form_login #nickname').val(nickname);
-                }
-            }
-
-            $('#form_login').on('submit', function () {
-                SN.U.StatusNetInstance.Set({Nickname: $('#form_login #nickname').val()});
-                return true;
-            });
-        },
-
-        /**
-         * Called when a people tag edit box is shown in the interface
-         *
-         * - loads the jQuery UI autocomplete plugin
-         * - sets event handlers for tag completion
-         *
-         */
-        PeopletagAutocomplete: function (txtBox) {
-            var split = function (val) {
-                return val.split( /\s+/ );
-            }
-            var extractLast = function (term) {
-                return split(term).pop();
-            }
-
-            // don't navigate away from the field on tab when selecting an item
-            txtBox.on( "keydown", function ( event ) {
-                if ( event.keyCode === $.ui.keyCode.TAB &&
-                        $(this).data( "autocomplete" ).menu.active ) {
-                    event.preventDefault();
-                }
-            }).autocomplete({
-                minLength: 0,
-                source: function (request, response) {
-                    // delegate back to autocomplete, but extract the last term
-                    response($.ui.autocomplete.filter(
-                        SN.C.PtagACData, extractLast(request.term)));
-                },
-                focus: function () {
-                    return false;
-                },
-                select: function (event, ui) {
-                    var terms = split(this.value);
-                    terms.pop();
-                    terms.push(ui.item.value);
-                    terms.push("");
-                    this.value = terms.join(" ");
-                    return false;
-                }
-            }).data('autocomplete')._renderItem = function (ul, item) {
-                    // FIXME: with jQuery UI you cannot have it highlight the match
-                    var _l = '<a class="ptag-ac-line-tag">' + item.tag
-                          + ' <em class="privacy_mode">' + item.mode + '</em>'
-                          + '<span class="freq">' + item.freq + '</span></a>'
-
-                    return $("<li/>")
-                            .addClass('mode-' + item.mode)
-                            .addClass('ptag-ac-line')
-                            .data("item.autocomplete", item)
-                            .append(_l)
-                            .appendTo(ul);
-                }
-        },
-
         /**
          * Run setup for the ajax people tags editor
          *
@@ -1646,7 +1577,6 @@ var SN = { // StatusNet
                         }
 
                         SN.C.PtagACData = data;
-                        SN.Init.PeopletagAutocomplete(form.find('#tags'));
                     }
                 });
 
@@ -1747,9 +1677,6 @@ $(function () {
     if ($('#content .entity_actions').length > 0) {
         SN.Init.EntityActions();
     }
-    if ($('#form_login').length > 0) {
-        SN.Init.Login();
-    }
     if ($('#profile_search_results').length > 0) {
         SN.Init.ProfileSearch();
     }