* @package StatusNet
* @author Sarven Capadisli <csarven@status.net>
* @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2009,2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
HTTP20x30x: [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307]
},
+ /**
+ * @fixme are these worth the trouble? They seem to mostly just duplicate
+ * themselves while slightly obscuring the actual selector, so it's hard
+ * to pop over to the HTML and find something.
+ *
+ * In theory, minification could reduce them to shorter variable names,
+ * but at present that doesn't happen with yui-compressor.
+ */
S: { // Selector
Disabled: 'disabled',
Warning: 'warning',
}
},
+ /**
+ * Map of localized message strings exported to script from the PHP
+ * side via Action::getScriptMessages().
+ *
+ * Retrieve them via SN.msg(); this array is an implementation detail.
+ *
+ * @access private
+ */
+ messages: {},
+
+ /**
+ * Grabs a localized string that's been previously exported to us
+ * from server-side code via Action::getScriptMessages().
+ *
+ * @example alert(SN.msg('coolplugin-failed'));
+ *
+ * @param {String} key: string key name to pull from message index
+ * @return matching localized message string
+ */
+ msg: function(key) {
+ if (typeof SN.messages[key] == "undefined") {
+ return '[' + key + ']';
+ } else {
+ return SN.messages[key];
+ }
+ },
+
U: { // Utils
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers on the new notice form.
+ *
+ * @param {jQuery} form: jQuery object whose first matching element is the form
+ * @access private
+ */
FormNoticeEnhancements: function(form) {
if (jQuery.data(form[0], 'ElementData') === undefined) {
MaxLength = form.find('#'+SN.C.S.NoticeTextCount).text();
SN.U.Counter(form);
});
+ var delayedUpdate= function(e) {
+ // Cut and paste events fire *before* the operation,
+ // so we need to trigger an update in a little bit.
+ // This would be so much easier if the 'change' event
+ // actually fired every time the value changed. :P
+ window.setTimeout(function() {
+ SN.U.Counter(form);
+ }, 50);
+ };
+ // Note there's still no event for mouse-triggered 'delete'.
+ NDT.bind('cut', delayedUpdate)
+ .bind('paste', delayedUpdate);
+
NDT.bind('keydown', function(e) {
SN.U.SubmitOnReturn(e, form);
});
}
},
+ /**
+ * To be called from keydown event handler on the notice import form.
+ * Checks if return or enter key was pressed, and if so attempts to
+ * submit the form and cancel standard processing of the enter key.
+ *
+ * @param {Event} event
+ * @param {jQuery} el: jQuery object whose first element is the notice posting form
+ *
+ * @return {boolean} whether to cancel the event? Does this actually pass through?
+ * @access private
+ */
SubmitOnReturn: function(event, el) {
if (event.keyCode == 13 || event.keyCode == 10) {
el.submit();
return true;
},
+ /**
+ * To be called from event handlers on the notice import form.
+ * Triggers an update of the remaining-characters counter.
+ *
+ * Additional counter updates will be suppressed during the
+ * next half-second to avoid flooding the layout engine with
+ * updates, followed by another automatic check.
+ *
+ * The maximum length is pulled from data established by
+ * FormNoticeEnhancements.
+ *
+ * @param {jQuery} form: jQuery object whose first element is the notice posting form
+ * @access private
+ */
Counter: function(form) {
SN.C.I.FormNoticeCurrent = form;
}
},
+ /**
+ * Pull the count of characters in the current edit field.
+ * Plugins replacing the edit control may need to override this.
+ *
+ * @param {jQuery} form: jQuery object whose first element is the notice posting form
+ * @return number of chars
+ */
CharacterCount: function(form) {
return form.find('#'+SN.C.S.NoticeDataText).val().length;
},
+ /**
+ * Called internally after the counter update blackout period expires;
+ * runs another update to make sure we didn't miss anything.
+ *
+ * @param {jQuery} form: jQuery object whose first element is the notice posting form
+ * @access private
+ */
ClearCounterBlackout: function(form) {
// Allow keyup events to poke the counter again
SN.C.I.CounterBlackout = false;
SN.U.Counter(form);
},
+ /**
+ * Helper function to rewrite default HTTP form action URLs to HTTPS
+ * so we can actually fetch them when on an SSL page in ssl=sometimes
+ * mode.
+ *
+ * It would be better to output URLs that didn't hardcode protocol
+ * and hostname in the first place...
+ *
+ * @param {String} url
+ * @return string
+ */
+ RewriteAjaxAction: function(url) {
+ // Quick hack: rewrite AJAX submits to HTTPS if they'd fail otherwise.
+ if (document.location.protocol == 'https:' && url.substr(0, 5) == 'http:') {
+ return url.replace(/^http:\/\/[^:\/]+/, 'https://' + document.location.host);
+ } else {
+ return url;
+ }
+ },
+
+ /**
+ * Grabs form data and submits it asynchronously, with 'ajax=1'
+ * parameter added to the rest.
+ *
+ * If a successful response includes another form, that form
+ * will be extracted and copied in, replacing the original form.
+ * If there's no form, the first paragraph will be used.
+ *
+ * @fixme can sometimes explode confusingly if returnd data is bogus
+ * @fixme error handling is pretty vague
+ * @fixme can't submit file uploads
+ *
+ * @param {jQuery} form: jQuery object whose first element is a form
+ *
+ * @access public
+ */
FormXHR: function(form) {
$.ajax({
type: 'POST',
dataType: 'xml',
- url: form.attr('action'),
+ url: SN.U.RewriteAjaxAction(form.attr('action')),
data: form.serialize() + '&ajax=1',
beforeSend: function(xhr) {
form
});
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers for special-cased async submission of the
+ * notice-posting form, including some pre-post validation.
+ *
+ * Unlike FormXHR() this does NOT submit the form immediately!
+ * It sets up event handlers so that any method of submitting the
+ * form (click on submit button, enter, submit() etc) will trigger
+ * it properly.
+ *
+ * Also unlike FormXHR(), this system will use a hidden iframe
+ * automatically to handle file uploads via <input type="file">
+ * controls.
+ *
+ * @fixme tl;dr
+ * @fixme vast swaths of duplicate code and really long variable names clutter this function up real bad
+ * @fixme error handling is unreliable
+ * @fixme cookieValue is a global variable, but probably shouldn't be
+ * @fixme saving the location cache cookies should be split out
+ * @fixme some error messages are hardcoded english: needs i18n
+ * @fixme special-case for bookmarklet is confusing and uses a global var "self". Is this ok?
+ *
+ * @param {jQuery} form: jQuery object whose first element is a form
+ *
+ * @access public
+ */
FormNoticeXHR: function(form) {
SN.C.I.NoticeDataGeo = {};
form.append('<input type="hidden" name="ajax" value="1"/>');
+
+ // 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.
+ */
+ var removeFeedback = function() {
+ form.find('.form_response').remove();
+ };
+
form.ajaxForm({
dataType: 'xml',
timeout: '60000',
.find('#'+SN.C.S.NoticeActionSubmit)
.removeClass(SN.C.S.Disabled)
.removeAttr(SN.C.S.Disabled, SN.C.S.Disabled);
- form.find('.form_response').remove();
+ removeFeedback();
if (textStatus == 'timeout') {
- form.append('<p class="form_response error">Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.</p>');
+ // @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.');
}
else {
- if ($('.'+SN.C.S.Error, xhr.responseXML).length > 0) {
- form.append(document._importNode($('.'+SN.C.S.Error, xhr.responseXML)[0], true));
+ 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) {
SN.U.FormNoticeEnhancements(form);
}
else {
- form.append('<p class="form_response error">(Sorry! We had trouble sending your notice ('+xhr.status+' '+xhr.statusText+'). Please report the problem to the site administrator if this happens again.</p>');
+ // @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.');
}
}
}
},
success: function(data, textStatus) {
- form.find('.form_response').remove();
- var result;
- if ($('#'+SN.C.S.Error, data).length > 0) {
- result = document._importNode($('p', data)[0], true);
- result = result.textContent || result.innerHTML;
- form.append('<p class="form_response error">'+result+'</p>');
+ removeFeedback();
+ var errorResult = $('#'+SN.C.S.Error, data);
+ if (errorResult.length > 0) {
+ showFeedback('error', errorResult.text());
}
else {
if($('body')[0].id == 'bookmarklet') {
+ // @fixme self is not referenced anywhere?
self.close();
}
- if ($('#'+SN.C.S.CommandResult, data).length > 0) {
- result = document._importNode($('p', data)[0], true);
- result = result.textContent || result.innerHTML;
- form.append('<p class="form_response success">'+result+'</p>');
+ 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!
else {
// Not on a timeline that this belongs on?
// Just show a success message.
- result = document._importNode($('title', data)[0], true);
- result_title = result.textContent || result.innerHTML;
- form.append('<p class="form_response success">'+result_title+'</p>');
+ showFeedback('success', $('title', data).text());
}
}
form.resetForm();
});
},
+ /**
+ * Fetch an XML DOM from an XHR's response data.
+ *
+ * Works around unavailable responseXML when document.domain
+ * has been modified by Meteor or other tools, in some but not
+ * all browsers.
+ *
+ * @param {XMLHTTPRequest} xhr
+ * @return DOMDocument
+ */
+ GetResponseXML: function(xhr) {
+ try {
+ return xhr.responseXML;
+ } catch (e) {
+ return (new DOMParser()).parseFromString(xhr.responseText, "text/xml");
+ }
+ },
+
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers on all visible notice's reply buttons 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.)
+ *
+ * @access private
+ */
NoticeReply: function() {
if ($('#'+SN.C.S.NoticeDataText).length > 0 && $('#content .notice_reply').length > 0) {
$('#content .notice').each(function() { SN.U.NoticeReplyTo($(this)); });
}
},
+ /**
+ * 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
+ * @access private
+ */
NoticeReplyTo: function(notice) {
notice.find('.notice_reply').live('click', function() {
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
});
},
+ /**
+ * Updates the new notice posting form with bits for replying to the
+ * given user. Adds replyto parameter to the form, and a "@foo" to the
+ * text area.
+ *
+ * @fixme replyto is a global variable, but probably shouldn't be
+ *
+ * @param {String} nick
+ * @param {String} id
+ */
NoticeReplySet: function(nick,id) {
if (nick.match(SN.C.I.PatternUsername)) {
var text = $('#'+SN.C.S.NoticeDataText);
}
},
+ /**
+ * Setup function -- DOES NOT apply immediately.
+ *
+ * Sets up event handlers for favor/disfavor forms to submit via XHR.
+ * Uses 'live' rather than 'bind', so applies to future as well as present items.
+ */
NoticeFavor: function() {
$('.form_favor').live('click', function() { SN.U.FormXHR($(this)); return false; });
$('.form_disfavor').live('click', function() { SN.U.FormXHR($(this)); return false; });
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers for repeat forms to toss up a confirmation
+ * popout before submitting.
+ *
+ * Uses 'live' rather than 'bind', so applies to future as well as present items.
+ */
NoticeRepeat: function() {
$('.form_repeat').live('click', function(e) {
e.preventDefault();
});
},
+ /**
+ * Shows a confirmation dialog box variant of the repeat button form.
+ * This seems to use a technique where the repeat form contains
+ * _both_ a standalone button _and_ text and buttons for a dialog.
+ * The dialog will close after its copy of the form is submitted,
+ * or if you click its 'close' button.
+ *
+ * The dialog is created by duplicating the original form and changing
+ * its style; while clever, this is hard to generalize and probably
+ * duplicates a lot of unnecessary HTML output.
+ *
+ * @fixme create confirmation dialogs through a generalized interface
+ * that can be reused instead of hardcoded text and styles.
+ *
+ * @param {jQuery} form
+ */
NoticeRepeatConfirmation: function(form) {
var submit_i = form.find('.submit');
});
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Goes through all notices currently displayed and sets up attachment
+ * handling if needed.
+ */
NoticeAttachments: function() {
$('.notice a.attachment').each(function() {
SN.U.NoticeWithAttachment($(this).closest('.notice'));
});
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up special attachment link handling if needed. Currently this
+ * consists only of making the "more" button used for OStatus message
+ * cropping turn into an auto-expansion button that loads the full
+ * text from an attachment file.
+ *
+ * @param {jQuery} notice
+ */
NoticeWithAttachment: function(notice) {
if (notice.find('.attachment').length === 0) {
return;
});
return false;
- });
- }
- else {
- $.fn.jOverlay.options = {
- method : 'GET',
- data : '',
- url : '',
- color : '#000',
- opacity : '0.6',
- zIndex : 9999,
- center : false,
- imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
- bgClickToClose : true,
- success : function() {
- $('#jOverlayContent').append('<button class="close">×</button>');
- $('#jOverlayContent button').click($.closeOverlay);
- },
- timeout : 0,
- autoHide : true,
- css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'}
- };
-
- notice.find('a.attachment').click(function() {
- var attachId = ($(this).attr('id').substring('attachment'.length + 1));
- if (attachId) {
- $().jOverlay({url: $('address .url')[0].href+'attachment/' + attachId + '/ajax'});
- return false;
- }
- });
-
- if ($('#shownotice').length == 0) {
- var t;
- notice.find('a.thumbnail').hover(
- function() {
- var anchor = $(this);
- $('a.thumbnail').children('img').hide();
- anchor.closest(".entry-title").addClass('ov');
-
- if (anchor.children('img').length === 0) {
- t = setTimeout(function() {
- $.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
- anchor.append(data);
- });
- }, 500);
- }
- else {
- anchor.children('img').show();
- }
- },
- function() {
- clearTimeout(t);
- $('a.thumbnail').children('img').hide();
- $(this).closest('.entry-title').removeClass('ov');
- }
- );
- }
+ }).attr('title', SN.msg('showmore_tooltip'));
}
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers for the file-attachment widget in the
+ * new notice form. When a file is selected, a box will be added
+ * below the text input showing the filename and, if supported
+ * by the browser, a thumbnail preview.
+ *
+ * This preview box will also allow removing the attachment
+ * prior to posting.
+ */
NoticeDataAttach: function() {
NDA = $('#'+SN.C.S.NoticeDataAttach);
NDA.change(function() {
return false;
});
+ if (typeof this.files == "object") {
+ // Some newer browsers will let us fetch the files for preview.
+ for (var i = 0; i < this.files.length; i++) {
+ SN.U.PreviewAttach(this.files[i]);
+ }
+ }
});
},
+ /**
+ * For browsers with FileAPI support: make a thumbnail if possible,
+ * and append it into the attachment display widget.
+ *
+ * Known good:
+ * - Firefox 3.6.6, 4.0b7
+ * - Chrome 8.0.552.210
+ *
+ * Known ok metadata, can't get contents:
+ * - Safari 5.0.2
+ *
+ * Known fail:
+ * - Opera 10.63, 11 beta (no input.files interface)
+ *
+ * @param {File} file
+ *
+ * @todo use configured thumbnail size
+ * @todo detect pixel size?
+ * @todo should we render a thumbnail to a canvas and then use the smaller image?
+ */
+ PreviewAttach: function(file) {
+ var tooltip = file.type + ' ' + Math.round(file.size / 1024) + 'KB';
+ var preview = true;
+
+ var blobAsDataURL;
+ if (typeof window.createObjectURL != "undefined") {
+ /**
+ * createObjectURL lets us reference the file directly from an <img>
+ * This produces a compact URL with an opaque reference to the file,
+ * which we can reference immediately.
+ *
+ * - Firefox 3.6.6: no
+ * - Firefox 4.0b7: no
+ * - Safari 5.0.2: no
+ * - Chrome 8.0.552.210: works!
+ */
+ blobAsDataURL = function(blob, callback) {
+ callback(window.createObjectURL(blob));
+ }
+ } else if (typeof window.FileReader != "undefined") {
+ /**
+ * FileAPI's FileReader can build a data URL from a blob's contents,
+ * but it must read the file and build it asynchronously. This means
+ * we'll be passing a giant data URL around, which may be inefficient.
+ *
+ * - Firefox 3.6.6: works!
+ * - Firefox 4.0b7: works!
+ * - Safari 5.0.2: no
+ * - Chrome 8.0.552.210: works!
+ */
+ blobAsDataURL = function(blob, callback) {
+ var reader = new FileReader();
+ reader.onload = function(event) {
+ callback(reader.result);
+ }
+ reader.readAsDataURL(blob);
+ }
+ } else {
+ preview = false;
+ }
+
+ var imageTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml'];
+ if ($.inArray(file.type, imageTypes) == -1) {
+ // We probably don't know how to show the file.
+ preview = false;
+ }
+
+ var maxSize = 8 * 1024 * 1024;
+ if (file.size > maxSize) {
+ // Don't kill the browser trying to load some giant image.
+ preview = false;
+ }
+
+ if (preview) {
+ blobAsDataURL(file, function(url) {
+ var img = $('<img>')
+ .attr('title', tooltip)
+ .attr('alt', tooltip)
+ .attr('src', url)
+ .attr('style', 'height: 120px');
+ $('#'+SN.C.S.NoticeDataAttachSelected).append(img);
+ });
+ } else {
+ var img = $('<div></div>').text(tooltip);
+ $('#'+SN.C.S.NoticeDataAttachSelected).append(img);
+ }
+ },
+
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Initializes state for the location-lookup features in the
+ * new-notice form. Seems to set up some event handlers for
+ * triggering lookups and using the new values.
+ *
+ * @fixme tl;dr
+ * @fixme there's not good visual state update here, so users have a
+ * hard time figuring out if it's working or fixing if it's wrong.
+ *
+ */
NoticeLocationAttach: function() {
var NLat = $('#'+SN.C.S.NoticeLat).val();
var NLon = $('#'+SN.C.S.NoticeLon).val();
}
},
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Initializes event handlers for the "Send direct message" link on
+ * profile pages, setting it up to display a dialog box when clicked.
+ *
+ * Unlike the repeat confirmation form, this appears to fetch
+ * the form _from the original link target_, so the form itself
+ * doesn't need to be in the current document.
+ *
+ * @fixme breaks ability to open link in new window?
+ */
NewDirectMessage: function() {
NDM = $('.entity_send-a-message a');
NDM.attr({'href':NDM.attr('href')+'&ajax=1'});
});
},
+ /**
+ * Return a date object with the current local time on the
+ * given year, month, and day.
+ *
+ * @param {number} year: 4-digit year
+ * @param {number} month: 0 == January
+ * @param {number} day: 1 == 1
+ * @return {Date}
+ */
GetFullYear: function(year, month, day) {
var date = new Date();
date.setFullYear(year, month, day);
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) {
});
},
+ /**
+ * @fixme what is this?
+ */
Get: function() {
var cookieValue = $.cookie(SN.C.S.StatusNetInstance);
if (cookieValue !== null) {
return null;
},
+ /**
+ * @fixme what is this?
+ */
Delete: function() {
$.cookie(SN.C.S.StatusNetInstance, null);
}
*
* @fixme this should be done in a saner way, with machine-readable
* info about what page we're looking at.
+ *
+ * @param {DOMElement} notice: HTML chunk with formatted notice
+ * @return boolean
*/
belongsOnTimeline: function(notice) {
var action = $("body").attr('id');
},
Init: {
+ /**
+ * If user is logged in, run setup code for the new notice form:
+ *
+ * - char counter
+ * - AJAX submission
+ * - location events
+ * - file upload events
+ */
NoticeForm: function() {
if ($('body.user_in').length > 0) {
SN.U.NoticeLocationAttach();
}
},
+ /**
+ * Run setup code for notice timeline views items:
+ *
+ * - AJAX submission for fave/repeat/reply (if logged in)
+ * - Attachment link extras ('more' links)
+ */
Notices: function() {
if ($('body.user_in').length > 0) {
SN.U.NoticeFavor();
SN.U.NoticeAttachments();
},
+ /**
+ * Run setup code for user & group profile page header area if logged in:
+ *
+ * - AJAX submission for sub/unsub/join/leave/nudge
+ * - AJAX form popup for direct-message
+ */
EntityActions: function() {
if ($('body.user_in').length > 0) {
$('.form_user_subscribe').live('click', function() { SN.U.FormXHR($(this)); return false; });
}
},
+ /**
+ * 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;
}
};
+/**
+ * Run initialization functions on DOM-ready.
+ *
+ * Note that if we're waiting on other scripts to load, this won't happen
+ * until that's done. To load scripts asynchronously without delaying setup,
+ * don't start them loading until after DOM-ready time!
+ */
$(document).ready(function(){
if ($('.'+SN.C.S.FormNotice).length > 0) {
SN.Init.NoticeForm();
SN.Init.Login();
}
});
-