diff --git a/actions/invite.php b/actions/invite.php
index c35d46d371..40376532b4 100644
--- a/actions/invite.php
+++ b/actions/invite.php
@@ -291,11 +291,11 @@ class InviteAction extends CurrentUserDesignAction
// TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral
// TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, $2$s is
// TRANS: the StatusNet sitename.
-
$headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
$title = (empty($personal)) ? 'invite' : 'invitepersonal';
+ // @todo FIXME: i18n issue.
$inviteTemplate = DocFile::forTitle($title, DocFile::mailPaths());
$body = $inviteTemplate->toHTML(array('inviter' => $bestname,
diff --git a/js/util.js b/js/util.js
index 9ec8fa8cd9..5c12ab111d 100644
--- a/js/util.js
+++ b/js/util.js
@@ -262,7 +262,7 @@ var SN = { // StatusNet
errorReported = $('#error', xhr.responseXML).text();
}
alert(errorReported || errorThrown || textStatus);
-
+
// Restore the form to original state.
// Hopefully. :D
form
@@ -506,7 +506,7 @@ var SN = { // StatusNet
results_placeholder.replaceWith(list);
}
else {
- var _error = $('
').append(document._importNode($('p', data)[0], true));
+ var _error = $('').append(document._importNode($('p', data)[0], true));
results_placeholder.html(_error);
}
form
@@ -650,7 +650,6 @@ var SN = { // StatusNet
// and we'll add on the end of it. Will add if needed.
list = $('ul.threaded-replies', notice);
if (list.length == 0) {
- console.log("list = 0");
SN.U.NoticeInlineReplyPlaceholder(notice);
list = $('ul.threaded-replies', notice);
} else {
@@ -777,6 +776,7 @@ var SN = { // StatusNet
* 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) {
diff --git a/js/util.min.js b/js/util.min.js
index f7d57c2f8d..1b3867b7ca 100644
--- a/js/util.min.js
+++ b/js/util.min.js
@@ -1 +1 @@
-var SN={C:{I:{CounterBlackout:false,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},S:{Disabled:"disabled",Warning:"warning",Error:"error",Success:"success",Processing:"processing",CommandResult:"command_result",FormNotice:"form_notice",NoticeDataGeo:"notice_data-geo",NoticeDataGeoCookie:"NoticeDataGeo",NoticeDataGeoSelected:"notice_data-geo_selected",StatusNetInstance:"StatusNetInstance"}},messages:{},msg:function(a){if(typeof SN.messages[a]=="undefined"){return"["+a+"]"}else{return SN.messages[a]}},U:{FormNoticeEnhancements:function(b){if(jQuery.data(b[0],"ElementData")===undefined){MaxLength=b.find(".count").text();if(typeof(MaxLength)=="undefined"){MaxLength=SN.C.I.MaxLength}jQuery.data(b[0],"ElementData",{MaxLength:MaxLength});SN.U.Counter(b);NDT=b.find(".notice_data-text:first");NDT.bind("keyup",function(c){SN.U.Counter(b)});var a=function(c){window.setTimeout(function(){SN.U.Counter(b)},50)};NDT.bind("cut",a).bind("paste",a)}else{b.find(".count").text(jQuery.data(b[0],"ElementData").MaxLength)}},Counter:function(d){SN.C.I.FormNoticeCurrent=d;var b=jQuery.data(d[0],"ElementData").MaxLength;if(b<=0){return}var c=b-SN.U.CharacterCount(d);var a=d.find(".count");if(c.toString()!=a.text()){if(!SN.C.I.CounterBlackout||c===0){if(a.text()!=String(c)){a.text(c)}if(c<0){d.addClass(SN.C.S.Warning)}else{d.removeClass(SN.C.S.Warning)}if(!SN.C.I.CounterBlackout){SN.C.I.CounterBlackout=true;SN.C.I.FormNoticeCurrent=d;window.setTimeout("SN.U.ClearCounterBlackout(SN.C.I.FormNoticeCurrent);",500)}}}},CharacterCount:function(a){return a.find(".notice_data-text:first").val().length},ClearCounterBlackout:function(a){SN.C.I.CounterBlackout=false;SN.U.Counter(a)},RewriteAjaxAction:function(a){if(document.location.protocol=="https:"&&a.substr(0,5)=="http:"){return a.replace(/^http:\/\/[^:\/]+/,"https://"+document.location.host)}else{return a}},FormXHR:function(a,b){$.ajax({type:"POST",dataType:"xml",url:SN.U.RewriteAjaxAction(a.attr("action")),data:a.serialize()+"&ajax=1",beforeSend:function(c){a.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled)},error:function(e,f,d){var c=null;if(e.responseXML){c=$("#error",e.responseXML).text()}alert(c||d||f);a.removeClass(SN.C.S.Processing).find(".submit").removeClass(SN.C.S.Disabled).removeAttr(SN.C.S.Disabled)},success:function(c,d){if(typeof($("form",c)[0])!="undefined"){form_new=document._importNode($("form",c)[0],true);a.replaceWith(form_new);if(b){b()}}else{if(typeof($("p",c)[0])!="undefined"){a.replaceWith(document._importNode($("p",c)[0],true));if(b){b()}}else{alert("Unknown error.")}}}})},FormNoticeXHR:function(b){SN.C.I.NoticeDataGeo={};b.append('');b.attr("action",SN.U.RewriteAjaxAction(b.attr("action")));var c=function(d,e){b.append($('').addClass(d).text(e))};var a=function(){b.find(".form_response").remove()};b.ajaxForm({dataType:"xml",timeout:"60000",beforeSend:function(d){if(b.find(".notice_data-text:first").val()==""){b.addClass(SN.C.S.Warning);return false}b.addClass(SN.C.S.Processing).find(".submit").addClass(SN.C.S.Disabled).attr(SN.C.S.Disabled,SN.C.S.Disabled);SN.U.normalizeGeoData(b);return true},error:function(f,g,e){b.removeClass(SN.C.S.Processing).find(".submit").removeClass(SN.C.S.Disabled).removeAttr(SN.C.S.Disabled,SN.C.S.Disabled);a();if(g=="timeout"){c("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 d=SN.U.GetResponseXML(f);if($("."+SN.C.S.Error,d).length>0){b.append(document._importNode($("."+SN.C.S.Error,d)[0],true))}else{if(parseInt(f.status)===0||jQuery.inArray(parseInt(f.status),SN.C.I.HTTP20x30x)>=0){b.resetForm().find(".attach-status").remove();SN.U.FormNoticeEnhancements(b)}else{c("error","(Sorry! We had trouble sending your notice ("+f.status+" "+f.statusText+"). Please report the problem to the site administrator if this happens again.")}}}},success:function(j,f){a();var p=$("#"+SN.C.S.Error,j);if(p.length>0){c("error",p.text())}else{if($("body")[0].id=="bookmarklet"){self.close()}var d=$("#"+SN.C.S.CommandResult,j);if(d.length>0){c("success",d.text())}else{var o=document._importNode($("li",j)[0],true);var k=$("#notices_primary .notices:first");var m=b.closest("li.notice-reply");if(m.length>0){var l=b.closest(".threaded-replies");var n=l.find(".notice-reply-placeholder");m.remove();var e=$(o).attr("id");if($("#"+e).length==0){$(o).insertBefore(n)}else{}n.show()}else{if(k.length>0&&SN.U.belongsOnTimeline(o)){if($("#"+o.id).length===0){var h=b.find("[name=inreplyto]").val();var g="#notices_primary #notice-"+h;if($("body")[0].id=="conversation"){if(h.length>0&&$(g+" .notices").length<1){$(g).append('
');h.find("button.close").click(function(){e.find("[name=notice_data-geo]").removeAttr("checked").change();return false});e.append(h)}var b;if(c){b=$("").attr("href",c)}else{b=$("")}b.text(a);if(f||g){var d=f+";"+g;b.attr("title",d);if(!a){b.text(d)}}h.find(".geo_status").empty().append(b)},NewDirectMessage:function(){NDM=$(".entity_send-a-message a");NDM.attr({href:NDM.attr("href")+"&ajax=1"});NDM.bind("click",function(){var a=$(".entity_send-a-message form");if(a.length===0){$(this).addClass(SN.C.S.Processing);$.get(NDM.attr("href"),null,function(b){$(".entity_send-a-message").append(document._importNode($("form",b)[0],true));a=$(".entity_send-a-message .form_notice");SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);a.append('');$(".entity_send-a-message button").click(function(){a.hide();return false});NDM.removeClass(SN.C.S.Processing)})}else{a.show();$(".entity_send-a-message textarea").focus()}return false})},GetFullYear:function(c,d,a){var b=new Date();b.setFullYear(c,d,a);return b},StatusNetInstance:{Set:function(b){var a=SN.U.StatusNetInstance.Get();if(a!==null){b=$.extend(a,b)}$.cookie(SN.C.S.StatusNetInstance,JSON.stringify(b),{path:"/",expires:SN.U.GetFullYear(2029,0,1)})},Get:function(){var a=$.cookie(SN.C.S.StatusNetInstance);if(a!==null){return JSON.parse(a)}return null},Delete:function(){$.cookie(SN.C.S.StatusNetInstance,null)}},belongsOnTimeline:function(b){var a=$("body").attr("id");if(a=="public"){return true}var c=$("#nav_profile a").attr("href");if(c){var d=$(b).find(".vcard.author a.url").attr("href");if(d==c){if(a=="all"||a=="showstream"){return true}}}return false},switchInputFormTab:function(a){$(".input_form_nav_tab.current").removeClass("current");if(a=="placeholder"){$("#input_form_nav_status").addClass("current")}else{$("#input_form_nav_"+a).addClass("current")}var b=$(".input_form.current.nonav");if(b.length>0){return}$(".input_form.current").removeClass("current");$("#input_form_"+a).addClass("current").find(".ajax-notice").each(function(){var c=$(this);SN.Init.NoticeFormSetup(c)}).find(".notice_data-text").focus()}},Init:{NoticeForm:function(){if($("body.user_in").length>0){$("#input_form_placeholder input.placeholder").focus(function(){SN.U.switchInputFormTab("status")});$("body").bind("click",function(g){var d=$("#content .input_forms div.current");if(d.length>0){if($("#content .input_forms").has(g.target).length==0){var a=d.find('textarea, input[type=text], input[type=""]');var c=false;a.each(function(){c=c||$(this).val()});if(!c){SN.U.switchInputFormTab("placeholder")}}}var b=$("li.notice-reply");if(b.length>0){var f=$(g.target);b.each(function(){var k=$(this);if(k.has(g.target).length==0){var h=k.find(".notice_data-text:first");var j=$.trim(h.val());if(j==""||j==h.data("initialText")){var e=k.closest("li.notice");k.remove();e.find("li.notice-reply-placeholder").show()}}})}});$(".input_forms fieldset fieldset label").inFieldLabels({fadeOpacity:0})}},NoticeFormSetup:function(a){if(!a.data("NoticeFormSetup")){SN.U.NoticeLocationAttach(a);SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);SN.U.NoticeDataAttach(a);a.data("NoticeFormSetup",true)}},Notices:function(){if($("body.user_in").length>0){var a=$(".form_notice:first");if(a.length>0){SN.C.I.NoticeFormMaster=document._importNode(a[0],true)}SN.U.NoticeRepeat();SN.U.NoticeReply();SN.U.NoticeInlineReplySetup()}SN.U.NoticeAttachments()},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})}},Login:function(){if(SN.U.StatusNetInstance.Get()!==null){var a=SN.U.StatusNetInstance.Get().Nickname;if(a!==null){$("#form_login #nickname").val(a)}}$("#form_login").bind("submit",function(){SN.U.StatusNetInstance.Set({Nickname:$("#form_login #nickname").val()});return true})},PeopletagAutocomplete:function(b){var a=function(d){return d.split(/\s+/)};var c=function(d){return a(d).pop()};b.live("keydown",function(d){if(d.keyCode===$.ui.keyCode.TAB&&$(this).data("autocomplete").menu.active){d.preventDefault()}}).autocomplete({minLength:0,source:function(e,d){d($.ui.autocomplete.filter(SN.C.PtagACData,c(e.term)))},focus:function(){return false},select:function(e,f){var d=a(this.value);d.pop();d.push(f.item.value);d.push("");this.value=d.join(" ");return false}}).data("autocomplete")._renderItem=function(e,f){var d=''+f.tag+' '+f.mode+''+f.freq+"";return $("").addClass("mode-"+f.mode).addClass("ptag-ac-line").data("item.autocomplete",f).append(d).appendTo(e)}},PeopleTags:function(){$(".user_profile_tags .editable").append($(''));$(".peopletags_edit_button").live("click",function(){var a=$(this).parents("dd").eq(0).find("form");$.ajax({url:_peopletagAC,dataType:"json",data:{token:$("#token").val()},ifModified:true,success:function(b){for(i=0;i').attr("name",a.attr("name")).val(a.val()).appendTo(b)})},UploadForms:function(){$("input[type=file]").change(function(d){if(typeof this.files=="object"&&this.files.length>0){var c=0;for(var b=0;b0&&c>a){var e="File too large: maximum upload size is %d bytes.";alert(e.replace("%d",a));$(this).val("");d.preventDefault();return false}}})},CheckBoxes:function(){$("span[class='checkbox-wrapper']").addClass("unchecked");$(".checkbox-wrapper").click(function(){if($(this).children("input").attr("checked")){$(this).children("input").attr({checked:""});$(this).removeClass("checked");$(this).addClass("unchecked");$(this).children("label").text("Private?")}else{$(this).children("input").attr({checked:"checked"});$(this).removeClass("unchecked");$(this).addClass("checked");$(this).children("label").text("Private")}})}}};$(document).ready(function(){SN.Init.AjaxForms();SN.Init.UploadForms();SN.Init.CheckBoxes();if($("."+SN.C.S.FormNotice).length>0){SN.Init.NoticeForm()}if($("#content .notices").length>0){SN.Init.Notices()}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()}if($(".user_profile_tags .editable").length>0){SN.Init.PeopleTags()}});if(!document.ELEMENT_NODE){document.ELEMENT_NODE=1;document.ATTRIBUTE_NODE=2;document.TEXT_NODE=3;document.CDATA_SECTION_NODE=4;document.ENTITY_REFERENCE_NODE=5;document.ENTITY_NODE=6;document.PROCESSING_INSTRUCTION_NODE=7;document.COMMENT_NODE=8;document.DOCUMENT_NODE=9;document.DOCUMENT_TYPE_NODE=10;document.DOCUMENT_FRAGMENT_NODE=11;document.NOTATION_NODE=12}document._importNode=function(e,a){switch(e.nodeType){case document.ELEMENT_NODE:var d=document.createElement(e.nodeName);if(e.attributes&&e.attributes.length>0){for(var c=0,b=e.attributes.length;c0){for(var c=0,b=e.childNodes.length;c0){var k=c.pop();k()}}};window._google_loader_apiLoaded=function(){f()};var d=function(){return(window.google&&google.loader)};var g=function(k){if(d()){return true}h(k);e();return false};e();return{shim:true,type:"ClientLocation",lastPosition:null,getCurrentPosition:function(l,o,p){var n=this;if(!g(function(){n.getCurrentPosition(l,o,p)})){return}if(google.loader.ClientLocation){var m=google.loader.ClientLocation;var k={coords:{latitude:m.latitude,longitude:m.longitude,altitude:null,accuracy:43000,altitudeAccuracy:null,heading:null,speed:null},address:{city:m.address.city,country:m.address.country,country_code:m.address.country_code,region:m.address.region},timestamp:new Date()};l(k);this.lastPosition=k}else{if(o==="function"){o({code:3,message:"Using the Google ClientLocation API and it is not able to calculate a location."})}}},watchPosition:function(k,m,n){this.getCurrentPosition(k,m,n);var l=this;var o=setInterval(function(){l.getCurrentPosition(k,m,n)},10000);return o},clearWatch:function(k){clearInterval(k)},getPermission:function(m,k,l){return true}}});navigator.geolocation=(window.google&&google.gears)?a():b()})()};
\ No newline at end of file
diff --git a/plugins/DomainWhitelist/DomainWhitelistPlugin.php b/plugins/DomainWhitelist/DomainWhitelistPlugin.php
index c20e3f02c0..8fab835991 100644
--- a/plugins/DomainWhitelist/DomainWhitelistPlugin.php
+++ b/plugins/DomainWhitelist/DomainWhitelistPlugin.php
@@ -58,11 +58,16 @@ class DomainWhitelistPlugin extends Plugin
if (!$this->matchesWhitelist($email)) {
$whitelist = $this->getWhitelist();
if (count($whitelist) == 1) {
- $message = sprintf(_("Email address must be in this domain: %s"),
+ // TRANS: Client exception thrown when a given e-mailaddress is not in the domain whitelist.
+ // TRANS: %s is a whitelisted e-mail domain.
+ $message = sprintf(_m('Email address must be in this domain: %s.'),
$whitelist[0]);
} else {
- $message = sprintf(_("Email address must be in one of these domains: %s"),
- implode(', ', $whitelist));
+ // TRANS: Client exception thrown when a given e-mailaddress is not in the domain whitelist.
+ // TRANS: %s are whitelisted e-mail domains separated by comma's (localisable).
+ $message = sprintf(_('Email address must be in one of these domains: %s.'),
+ // TRANS: Separator for whitelisted domains.
+ implode(_m('SEPARATOR',', '), $whitelist));
}
throw new ClientException($message);
}
diff --git a/plugins/EmailRegistration/EmailRegistrationPlugin.php b/plugins/EmailRegistration/EmailRegistrationPlugin.php
index 8210a1ce93..7cbb8a85f3 100644
--- a/plugins/EmailRegistration/EmailRegistrationPlugin.php
+++ b/plugins/EmailRegistration/EmailRegistrationPlugin.php
@@ -45,7 +45,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
-
class EmailRegistrationPlugin extends Plugin
{
function onAutoload($cls)
@@ -88,6 +87,7 @@ class EmailRegistrationPlugin extends Plugin
{
$dir = dirname(__FILE__);
+ // @todo FIXME: i18n issue.
$docFile = DocFile::forTitle($title, $dir.'/doc-src/');
if (!empty($docFile)) {
@@ -105,7 +105,8 @@ class EmailRegistrationPlugin extends Plugin
'author' => 'Evan Prodromou',
'homepage' => 'http://status.net/wiki/Plugin:EmailRegistration',
'rawdescription' =>
- _m('Use email only for registration'));
+ // TRANS: Plugin description.
+ _m('Use email only for registration.'));
return true;
}
}
diff --git a/plugins/EmailRegistration/Email_confirmation.php b/plugins/EmailRegistration/Email_confirmation.php
index 38d68c91ed..949556fc10 100644
--- a/plugins/EmailRegistration/Email_confirmation.php
+++ b/plugins/EmailRegistration/Email_confirmation.php
@@ -52,7 +52,6 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
*
* @see DB_DataObject
*/
-
class User_greeting_count extends Memcached_DataObject
{
public $__table = 'user_greeting_count'; // table name
@@ -174,7 +173,7 @@ class User_greeting_count extends Memcached_DataObject
if (!$result) {
// TRANS: Exception thrown when the user greeting count could not be saved in the database.
// TRANS: %d is a user ID (number).
- throw Exception(sprintf(_m("Could not increment greeting count for %d."),
+ throw Exception(sprintf(_m('Could not increment greeting count for %d.'),
$user_id));
}
}
diff --git a/plugins/EmailRegistration/confirmregistrationform.php b/plugins/EmailRegistration/confirmregistrationform.php
index eb682d6652..4abee7c4b4 100644
--- a/plugins/EmailRegistration/confirmregistrationform.php
+++ b/plugins/EmailRegistration/confirmregistrationform.php
@@ -4,7 +4,7 @@
* Copyright (C) 2011, StatusNet, Inc.
*
* Registration confirmation form
- *
+ *
* PHP version 5
*
* This program is free software: you can redistribute it and/or modify
@@ -44,7 +44,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
-
class ConfirmRegistrationForm extends Form
{
protected $code;
@@ -62,15 +61,16 @@ class ConfirmRegistrationForm extends Form
function formData()
{
$this->out->element('p', 'instructions',
- sprintf(_('Enter a password to confirm your new account.')));
-
+ // TRANS: Form instructions.
+ sprintf(_m('Enter a password to confirm your new account.')));
+
$this->hidden('code', $this->code);
$this->out->elementStart('ul', 'form_data');
$this->elementStart('li');
- $this->element('label', array('for' => 'nickname-ignore'), _('User name'));
+ $this->element('label', array('for' => 'nickname-ignore'), _m('User name'));
$this->element('input', array('name' => 'nickname-ignore',
'type' => 'text',
@@ -82,7 +82,8 @@ class ConfirmRegistrationForm extends Form
$this->elementStart('li');
- $this->element('label', array('for' => 'email-ignore'), _('Email'));
+ // TRANS: Field label.
+ $this->element('label', array('for' => 'email-ignore'), _m('Email address'));
$this->element('input', array('name' => 'email-ignore',
'type' => 'text',
@@ -94,15 +95,15 @@ class ConfirmRegistrationForm extends Form
$this->elementStart('li');
// TRANS: Field label on account registration page.
- $this->password('password1', _('Password'),
+ $this->password('password1', _m('Password'),
// TRANS: Field title on account registration page.
- _('6 or more characters.'));
+ _m('6 or more characters.'));
$this->elementEnd('li');
$this->elementStart('li');
// TRANS: Field label on account registration page. In this field the password has to be entered a second time.
$this->password('password2', _m('PASSWORD','Confirm'),
// TRANS: Field title on account registration page.
- _('Same as password above.'));
+ _m('Same as password above.'));
$this->elementEnd('li');
$this->elementStart('li');
@@ -117,12 +118,12 @@ class ConfirmRegistrationForm extends Form
$this->elementStart('label', array('class' => 'checkbox',
'for' => 'tos'));
-
- $this->raw(sprintf(_('I agree to the Terms of service and '.
+ // TRANS: Checkbox title for terms of service and privacy policy.
+ $this->raw(sprintf(_m('I agree to the Terms of service and '.
'Privacy policy of this site.'),
common_local_url('doc', array('title' => 'tos')),
common_local_url('doc', array('title' => 'privacy'))));
-
+
$this->elementEnd('label');
$this->elementEnd('li');
@@ -146,7 +147,7 @@ class ConfirmRegistrationForm extends Form
function formActions()
{
- // TRANS: Button text for action to save a new bookmark.
+ // TRANS: Button text for action to register.
$this->out->submit('submit', _m('BUTTON', 'Register'));
}
diff --git a/plugins/EmailRegistration/emailregister.php b/plugins/EmailRegistration/emailregister.php
index 1eb7d2c000..f6d0ec9b3c 100644
--- a/plugins/EmailRegistration/emailregister.php
+++ b/plugins/EmailRegistration/emailregister.php
@@ -4,7 +4,7 @@
* Copyright (C) 2011, StatusNet, Inc.
*
* Register a user by their email address
- *
+ *
* PHP version 5
*
* This program is free software: you can redistribute it and/or modify
@@ -39,10 +39,10 @@ if (!defined('STATUSNET')) {
*
* There are four cases where we're called:
*
- * 1. GET, no arguments. Initial registration; ask for an email address.
+ * 1. GET, no arguments. Initial registration; ask for an email address.
* 2. POST, email address argument. Initial registration; send an email to confirm.
* 3. GET, code argument. Confirming an invitation or a registration; look them up,
- * create the relevant user if possible, login as that user, and
+ * create the relevant user if possible, login as that user, and
* show a password-entry form.
* 4. POST, password argument. After confirmation, set the password for the new
* user, and redirect to a registration complete action with some instructions.
@@ -54,7 +54,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
-
class EmailregisterAction extends Action
{
const NEWEMAIL = 1;
@@ -95,7 +94,8 @@ class EmailregisterAction extends Action
$this->code = $this->trimmed('code');
if (empty($this->code)) {
- throw new ClientException(_('No confirmation code.'));
+ // TRANS: Client exception thrown when no confirmation code was provided.
+ throw new ClientException(_m('No confirmation code.'));
}
$this->invitation = Invitation::staticGet('code', $this->code);
@@ -105,13 +105,14 @@ class EmailregisterAction extends Action
$this->confirmation = Confirm_address::staticGet('code', $this->code);
if (empty($this->confirmation)) {
- throw new ClientException(_('No such confirmation code.'), 403);
+ // TRANS: Client exception thrown when given confirmation code was not issued.
+ throw new ClientException(_m('No such confirmation code.'), 403);
}
}
$this->password1 = $this->trimmed('password1');
$this->password2 = $this->trimmed('password2');
-
+
$this->tos = $this->boolean('tos');
}
} else { // GET
@@ -128,7 +129,8 @@ class EmailregisterAction extends Action
$this->confirmation = Confirm_address::staticGet('code', $this->code);
if (empty($this->confirmation)) {
- throw new ClientException(_('No such confirmation code.'), 405);
+ // TRANS: Client exception thrown when given confirmation code was not issued.
+ throw new ClientException(_m('No such confirmation code.'), 405);
}
}
}
@@ -148,7 +150,7 @@ class EmailregisterAction extends Action
case self::SETPASSWORD:
case self::CONFIRMINVITE:
case self::CONFIRMREGISTER:
- // TRANS: Title for page where to change password.
+ // TRANS: Title for page where to register with a confirmation code.
return _m('TITLE','Complete registration');
break;
}
@@ -202,7 +204,8 @@ class EmailregisterAction extends Action
$old = User::staticGet('email', $this->email);
if (!empty($old)) {
- $this->error = sprintf(_('A user with that email address already exists. You can use the '.
+ // TRANS: Error text when trying to register with an already registered e-mail address.
+ $this->error = sprintf(_m('A user with that email address already exists. You can use the '.
'password recovery tool to recover a missing password.'),
common_local_url('recoverpassword'));
$this->showRegistrationForm();
@@ -217,7 +220,8 @@ class EmailregisterAction extends Action
Event::handle('EndValidateUserEmail', array(null, $this->email, &$valid));
}
if (!$valid) {
- $this->error = _('Not a valid email address.');
+ // TRANS: Error text when trying to register with an invalid e-mail address.
+ $this->error = _m('Not a valid email address.');
$this->showRegistrationForm();
return;
}
@@ -231,17 +235,19 @@ class EmailregisterAction extends Action
if (empty($confirm)) {
$confirm = Confirm_address::saveNew(null, $this->email, 'register');
- $prompt = sprintf(_('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
+ // TRANS: Confirmation text after initial registration.
+ $prompt = sprintf(_m('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
$this->email);
} else {
- $prompt = sprintf(_('The address %s was already registered but not confirmed. The confirmation code was resent.'),
+ // TRANS: Confirmation text after re-requesting an e-mail confirmation code.
+ $prompt = sprintf(_m('The address %s was already registered but not confirmed. The confirmation code was resent.'),
$this->email);
}
$this->sendConfirmEmail($confirm);
$this->complete = $prompt;
-
+
$this->showPage();
}
@@ -252,7 +258,7 @@ class EmailregisterAction extends Action
} else if (!empty($this->confirmation)) {
$email = $this->confirmation->address;
}
-
+
$nickname = $this->nicknameFromEmail($email);
$this->form = new ConfirmRegistrationForm($this,
@@ -342,11 +348,15 @@ class EmailregisterAction extends Action
$headers['From'] = mail_notify_from();
$headers['To'] = trim($confirm->address);
- $headers['Subject'] = sprintf(_('Confirm your registration on %1$s'), $sitename);
+ // TRANS: Subject for confirmation e-mail.
+ // TRANS: %s is the StatusNet sitename.
+ $headers['Subject'] = sprintf(_m('Confirm your registration on %s'), $sitename);
$confirmUrl = common_local_url('register', array('code' => $confirm->code));
- $body = sprintf(_('Someone (probably you) has requested an account on %1$s using this email address.'.
+ // TRANS: Body for confirmation e-mail.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is the confirmation URL.
+ $body = sprintf(_m('Someone (probably you) has requested an account on %1$s using this email address.'.
"\n".
'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
"\n".
@@ -387,7 +397,6 @@ class EmailregisterAction extends Action
*
* @return boolean is read only action?
*/
-
function isReadOnly($args)
{
return false;
@@ -396,9 +405,9 @@ class EmailregisterAction extends Action
function nicknameFromEmail($email)
{
$parts = explode('@', $email);
-
+
$nickname = $parts[0];
-
+
$nickname = preg_replace('/[^A-Za-z0-9]/', '', $nickname);
$nickname = Nickname::normalize($nickname);
@@ -422,7 +431,6 @@ class EmailregisterAction extends Action
*
* @return void
*/
-
function showLocalNav()
{
$nav = new LoginGroupNav($this);
diff --git a/plugins/EmailRegistration/emailregistrationform.php b/plugins/EmailRegistration/emailregistrationform.php
index 16b04c217d..d72bfc4bbb 100644
--- a/plugins/EmailRegistration/emailregistrationform.php
+++ b/plugins/EmailRegistration/emailregistrationform.php
@@ -4,7 +4,7 @@
* Copyright (C) 2011, StatusNet, Inc.
*
* Email registration form
- *
+ *
* PHP version 5
*
* This program is free software: you can redistribute it and/or modify
@@ -44,7 +44,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
-
class EmailRegistrationForm extends Form
{
protected $email;
@@ -58,14 +57,15 @@ class EmailRegistrationForm extends Form
function formData()
{
$this->out->element('p', 'instructions',
- _('Enter your email address to register for an account.'));
-
+ // TRANS: Form instructions.
+ _m('Enter your email address to register for an account.'));
+
$this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->out->input('email',
- // TRANS: Field label on form for adding a new bookmark.
+ // TRANS: Field label on form for registering an account.
_m('LABEL','E-mail address'),
$this->email);
$this->unli();
@@ -87,10 +87,9 @@ class EmailRegistrationForm extends Form
*
* @return void
*/
-
function formActions()
{
- // TRANS: Button text for action to save a new bookmark.
+ // TRANS: Button text for registering an account.
$this->out->submit('submit', _m('BUTTON', 'Register'));
}
@@ -102,7 +101,6 @@ class EmailRegistrationForm extends Form
*
* @return int ID of the form
*/
-
function id()
{
return 'form_email_registration';
@@ -116,7 +114,6 @@ class EmailRegistrationForm extends Form
*
* @return string URL to post to
*/
-
function action()
{
return common_local_url('register');
@@ -127,4 +124,3 @@ class EmailRegistrationForm extends Form
return 'form_email_registration form_settings';
}
}
-
diff --git a/plugins/QnA/QnAPlugin.php b/plugins/QnA/QnAPlugin.php
index f03f3e3395..ad0541a71c 100644
--- a/plugins/QnA/QnAPlugin.php
+++ b/plugins/QnA/QnAPlugin.php
@@ -299,6 +299,13 @@ class QnAPlugin extends MicroAppPlugin
if ($nli->notice->scope != 0 && $nli->notice->scope != 1) {
$class .= ' limited-scope';
}
+
+ $question = QnA_Question::staticGet('uri', $nli->notice->uri);
+
+ if (!empty($question->closed)) {
+ $class .= ' closed';
+ }
+
$nli->out->elementStart(
'li', array(
'class' => $class,
@@ -375,20 +382,10 @@ class QnAPlugin extends MicroAppPlugin
$question = QnA_Question::getByNotice($notice);
if (!empty($question)) {
- if (empty($user)) {
- $form = new QnashowquestionForm($out, $question);
- $form->show();
- } else {
- $profile = $user->getProfile();
- $answer = $question->getAnswer($profile);
- if (empty($answer)) {
- $form = new QnanewanswerForm($out, $question);
- $form->show();
- } else {
- $form = new QnashowquestionForm($out, $question);
- $form->show();
- }
- }
+
+ $form = new QnashowquestionForm($out, $question);
+ $form->show();
+
} else {
$out->text(_m('Question data is missing.'));
}
@@ -398,6 +395,71 @@ class QnAPlugin extends MicroAppPlugin
$out->elementStart('div', array('class' => 'entry-content'));
}
+
+ /**
+ * Output the HTML for this kind of object in a list
+ *
+ * @param NoticeListItem $nli The list item being shown.
+ *
+ * @return boolean hook value
+ *
+ * @fixme WARNING WARNING WARNING this closes a 'div' that is implicitly opened in BookmarkPlugin's showNotice implementation
+ */
+ function onStartShowNoticeItem($nli)
+ {
+ if (!$this->isMyNotice($nli->notice)) {
+ return true;
+ }
+
+ $out = $nli->out;
+ $notice = $nli->notice;
+
+ $this->showNotice($notice, $out);
+
+ $nli->showNoticeLink();
+ $nli->showNoticeSource();
+ $nli->showNoticeLocation();
+ $nli->showContext();
+ $nli->showRepeat();
+
+ $out->elementEnd('div');
+
+ $nli->showNoticeOptions();
+
+ if ($notice->object_type == QnA_Question::OBJECT_TYPE) {
+
+ $user = common_current_user();
+ $question = QnA_Question::getByNotice($notice);
+
+ if (!empty($user)) {
+
+ $profile = $user->getProfile();
+ $answer = $question->getAnswer($profile);
+
+ // Output a placeholder input -- clicking on it will
+ // bring up a real answer form
+
+ // NOTE: this whole ul is just a placeholder
+ if (empty($question->closed) && empty($answer)) {
+ $out->elementStart('ul', 'notices qna-dummy');
+ $out->elementStart('li', 'qna-dummy-placeholder');
+ $out->element(
+ 'input',
+ array(
+ 'class' => 'placeholder',
+ 'value' => _m('Your answer...')
+ )
+ );
+ $out->elementEnd('li');
+ $out->elementEnd('ul');
+ }
+ }
+ }
+
+ return false;
+ }
+
+
function showNoticeAnswer($notice, $out)
{
$user = common_current_user();
diff --git a/plugins/QnA/actions/qnanewanswer.php b/plugins/QnA/actions/qnanewanswer.php
index 0c4938e6a9..4e2fa5d36c 100644
--- a/plugins/QnA/actions/qnanewanswer.php
+++ b/plugins/QnA/actions/qnanewanswer.php
@@ -49,7 +49,7 @@ class QnanewanswerAction extends Action
protected $error = null;
protected $complete = null;
- protected $question = null;
+ public $question = null;
protected $content = null;
/**
@@ -76,7 +76,7 @@ class QnanewanswerAction extends Action
if ($this->boolean('ajax')) {
StatusNet::setApi(true);
}
-
+ common_debug("in qnanewanswer");
$this->user = common_current_user();
if (empty($this->user)) {
@@ -93,8 +93,6 @@ class QnanewanswerAction extends Action
$id = substr($this->trimmed('id'), 9);
- common_debug("XXXXXXXXXXXXXXXXXX id = " . $id);
-
$this->question = QnA_Question::staticGet('id', $id);
if (empty($this->question)) {
@@ -124,7 +122,7 @@ class QnanewanswerAction extends Action
if ($this->isPost()) {
$this->newAnswer();
} else {
- $this->showPage();
+ $this->showForm();
}
return;
@@ -147,7 +145,7 @@ class QnanewanswerAction extends Action
);
} catch (ClientException $ce) {
$this->error = $ce->getMessage();
- $this->showPage();
+ $this->showForm($this->error);
return;
}
if ($this->boolean('ajax')) {
@@ -164,33 +162,14 @@ class QnanewanswerAction extends Action
$this->elementStart('body');
- $nli = new NoticeListItem($notice, $this);
+
+ $nli = new NoticeAnswerListItem($notice, $this, $this->question, $answer);
$nli->show();
- //$this->raw($answer->asHTML());
-
- /*
- $question = $this->question;
-
- $nli = new NoticeListItem($notice, $this);
- $nli->showNotice();
-
- $this->elementStart('div', array('class' => 'entry-content answer-content'));
-
- if (!empty($answer)) {
- $form = new QnashowanswerForm($this, $answer);
- $form->show();
- } else {
- $this->text(_m('Answer data is missing.'));
- }
-
- $this->elementEnd('div');
-
- // @fixme
- //$this->elementStart('div', array('class' => 'entry-content'));
- */
+
$this->elementEnd('body');
$this->elementEnd('html');
} else {
+ common_debug("not ajax");
common_redirect($this->question->bestUrl(), 303);
}
}
@@ -230,4 +209,145 @@ class QnanewanswerAction extends Action
return false;
}
}
+
+ /**
+ * Show an Ajax-y error message
+ *
+ * Goes back to the browser, where it's shown in a popup.
+ *
+ * @param string $msg Message to show
+ *
+ * @return void
+ */
+ function ajaxErrorMsg($msg)
+ {
+ $this->startHTML('text/xml;charset=utf-8', true);
+ $this->elementStart('head');
+ // TRANS: Page title after an AJAX error occurs on the post answer page.
+ $this->element('title', null, _('Ajax Error'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->element('p', array('id' => 'error'), $msg);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+
+ /**
+ * Show an Ajax-y answer form
+ *
+ * Goes back to the browser, where it's shown in a popup.
+ *
+ * @param string $msg Message to show
+ *
+ * @return void
+ */
+ function ajaxShowForm()
+ {
+ common_debug('ajaxShowForm()');
+ $this->startHTML('text/xml;charset=utf-8', true);
+ $this->elementStart('head');
+ // TRANS: Title for form to send answer to a question.
+ $this->element('title', null, _m('TITLE','Your answer'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+
+ $form = new QnanewanswerForm($this, $this->question);
+ $form->show();
+
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+
+ /**
+ * @param string $msg An error message, if any
+ *
+ * @return void
+ */
+ function showForm($msg = null)
+ {
+ common_debug("show form - msg = $msg");
+ if ($this->boolean('ajax')) {
+ if ($msg) {
+ $this->ajaxErrorMsg($msg);
+ } else {
+ $this->ajaxShowForm();
+ }
+ return;
+ }
+
+ $this->msg = $msg;
+ $this->showPage();
+ }
+
}
+
+class NoticeAnswerListItem extends NoticeListItem
+{
+ protected $question;
+ protected $answer;
+
+ /**
+ * constructor
+ *
+ * Also initializes the profile attribute.
+ *
+ * @param Notice $notice The notice we'll display
+ */
+ function __construct($notice, $out=null, $question, $answer)
+ {
+ parent::__construct($notice, $out);
+ $this->question = $question;
+ $this->answer = $answer;
+
+ }
+
+ function show()
+ {
+ if (empty($this->notice)) {
+ common_log(LOG_WARNING, "Trying to show missing notice; skipping.");
+ return;
+ } else if (empty($this->profile)) {
+ common_log(LOG_WARNING, "Trying to show missing profile (" . $this->notice->profile_id . "); skipping.");
+ return;
+ }
+
+ $this->showStart();
+ $this->showNotice();
+ $this->showNoticeInfo();
+ $notice = $this->question->getNotice();
+ $this->out->hidden('inreplyto', $notice->id);
+ $this->showEnd();
+ }
+
+ /**
+ * show the content of the notice
+ *
+ * Shows the content of the notice. This is pre-rendered for efficiency
+ * at save time. Some very old notices might not be pre-rendered, so
+ * they're rendered on the spot.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $this->out->elementStart('p', array('class' => 'entry-content answer-content'));
+ if ($this->notice->rendered) {
+ $this->out->raw($this->notice->rendered);
+ } else {
+ // XXX: may be some uncooked notices in the DB,
+ // we cook them right now. This should probably disappear in future
+ // versions (>> 0.4.x)
+ $this->out->raw(common_render_content($this->notice->content, $this->notice));
+ }
+
+ if (!empty($this->answer)) {
+ $form = new QnashowanswerForm($this->out, $this->answer);
+ $form->show();
+ } else {
+ $out->text(_m('Answer data is missing.'));
+ }
+
+ $this->out->elementEnd('p');
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/QnA/actions/qnanewquestion.php b/plugins/QnA/actions/qnanewquestion.php
index 6610188c47..48542ab06e 100644
--- a/plugins/QnA/actions/qnanewquestion.php
+++ b/plugins/QnA/actions/qnanewquestion.php
@@ -175,8 +175,7 @@ class QnanewquestionAction extends Action
*/
function showNotice($notice)
{
- class_exists('NoticeList'); // @fixme hack for autoloader
- $nli = new NoticeListItem($notice, $this);
+ $nli = new NoticeQuestionListItem($notice, $this);
$nli->show();
}
@@ -221,3 +220,25 @@ class QnanewquestionAction extends Action
}
}
}
+
+class NoticeQuestionListItem extends NoticeListItem
+{
+ /**
+ * constructor
+ *
+ * Also initializes the profile attribute.
+ *
+ * @param Notice $notice The notice we'll display
+ */
+ function __construct($notice, $out=null)
+ {
+ parent::__construct($notice, $out);
+ }
+
+ function showEnd()
+ {
+ $this->out->element('ul', 'notices threaded-replies xoxo');
+ parent::showEnd();
+ }
+
+}
\ No newline at end of file
diff --git a/plugins/QnA/classes/QnA_Question.php b/plugins/QnA/classes/QnA_Question.php
index 157eaa7a18..77d5a57fb1 100644
--- a/plugins/QnA/classes/QnA_Question.php
+++ b/plugins/QnA/classes/QnA_Question.php
@@ -217,6 +217,14 @@ class QnA_Question extends Managed_DataObject
$out = new XMLStringer();
+ $cls = array('qna_question');
+
+ if (!empty($question->closed)) {
+ $cls[] = 'closed';
+ }
+
+ $out->elementStart('p', array('class' => implode(' ', $cls)));
+
if (!empty($question->description)) {
$out->elementStart('span', 'question-description');
$out->raw(QnAPlugin::shorten($question->description, $notice));
@@ -237,6 +245,8 @@ class QnA_Question extends Managed_DataObject
$out->elementEnd('span');
}
+ $out->elementEnd('p');
+
return $out->getString();
}
diff --git a/plugins/QnA/css/qna.css b/plugins/QnA/css/qna.css
index 4701b5ab03..1b89b6c2bb 100644
--- a/plugins/QnA/css/qna.css
+++ b/plugins/QnA/css/qna.css
@@ -1 +1,5 @@
-/* stubb for q&a css */
+/* Why doesn't this work? */
+input.answer-placeholder {
+ margin-left: 0;
+ width: 95%;
+}
diff --git a/plugins/QnA/js/qna.js b/plugins/QnA/js/qna.js
index 82f9a24b1b..5b1a5fef31 100644
--- a/plugins/QnA/js/qna.js
+++ b/plugins/QnA/js/qna.js
@@ -1,23 +1,355 @@
-
var QnA = {
- // hide all the 'close' and 'best' buttons for this question
-
// @fixme: Should use ID
- close: function(closeButt) {
- $(closeButt)
- .closest('li.hentry.notice.question')
- .find('input[name=best],[name=close]')
- .hide();
+ close: function(form, best) {
+ var notice = $(form).closest('li.hentry.notice.question');
+
+ notice.find('input#qna-best-answer,#qna-question-close').hide();
+ notice.find('textarea').hide();
+
+ var list = notice.find('ul');
+
+ notice.find('ul > li.notice-answer-placeholder').remove();
+ notice.find('ul > li.notice-answer').remove();
+
+ if (best) {
+ var p = notice.parent().find('div.question-description > form > fieldset > p');
+ if (p.length != 0) {
+ p.append($('This question is closed.'));
+ }
+ }
},
init: function() {
- var that = this;
- $('input[name=close]').live('click', function() {
- that.close(this);
+ QnA.NoticeInlineAnswerSetup();
+
+ $('form.form_question_show').live('submit', function() {
+ QnA.close(this);
});
- $('input[name=best]').live('click', function() {
- that.close(this);
+ $('form.form_answer_show').live('submit', function() {
+ QnA.close(this, true);
+ });
+ },
+
+ /**
+ * Open up a question's inline answer box.
+ *
+ * @param {jQuery} notice: jQuery object containing one notice
+ */
+ NoticeInlineAnswerTrigger: function(notice) {
+ // Find the notice we're replying to...
+ var id = $($('.notice_id', notice)[0]).text();
+ var parentNotice = notice;
+
+ // Find the threaded replies view we'll be adding to...
+ var list = notice.closest('.notices');
+ 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');
+
+ } 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);
+ }
+
+ // See if the form's already open...
+ var answerForm = $('.qna_answer_form', list);
+
+ var hideReplyPlaceholders = function(notice) {
+ // Do we still have a dummy answer placeholder? If so get rid of
+ // reply place holders for this question. If the current user hasn't
+ // answered the question we want to direct her to providing an
+ // answer. She can still reply by hitting the reply button if she
+ // really wants to.
+ var dummyAnswer = $('ul.qna-dummy', notice);
+ if (dummyAnswer.length > 0) {
+ notice.find('li.notice-reply-placeholder').hide();
+ }
+ }
+
+ var nextStep = function() {
+ var dummyAnswer = $('ul.qna-dummy', notice);
+ dummyAnswer.hide();
+
+ // Set focus...
+ var text = answerForm.find('textarea');
+
+ if (text.length == 0) {
+ throw "No textarea";
+ }
+
+ text.focus();
+
+ $('body').click(function(e) {
+ var dummyAnswer = $('ul.qna-dummy', notice);
+ var style = dummyAnswer.attr('style');
+ var ans = $(notice).find('li.hentry.notice.anwer', notice)
+ if (ans > 0) {
+ hideReplyPlaceholders(notice);
+ }
+
+ var openAnswers = $('li.notice-answer');
+ if (openAnswers.length > 0) {
+ var target = $(e.target);
+ openAnswers.each(function() {
+
+ // Did we click outside this one?
+ var answerItem = $(this);
+ var parentNotice = answerItem.closest('li.notice');
+
+ if (answerItem.has(e.target).length == 0) {
+ var textarea = answerItem.find('.notice_data-text:first');
+ var cur = $.trim(textarea.val());
+ // Only close if there's been no edit.
+ if (cur == '' || cur == textarea.data('initialText')) {
+ answerItem.remove();
+ dummyAnswer.show();
+ }
+ }
+ });
+ }
+ });
+ };
+
+ // See if the form's already open...
+ if (answerForm.length > 0 ) {
+ nextStep();
+ } else {
+ var placeholder = list.find('li.qna-dummy-placeholder').hide();
+
+ // Create the answer form entry at the end
+ var answerItem = $('li.notice-answer', list);
+
+ if (answerItem.length == 0) {
+ answerItem = $('');
+ var intermediateStep = function(formMaster) {
+ // @todo cache the form if we can (worth it?)
+ var formEl = document._importNode(formMaster, true);
+ $(formEl).data('NoticeFormSetup', true);
+ answerItem.append(formEl);
+ list.prepend(answerItem); // *before* the placeholder
+ var form = answerForm = $(formEl);
+ QnA.AnswerFormSetup(form);
+ nextStep();
+ };
+
+ if (QnA.AnswerFormMaster) {
+ // @todo if we had a cached for here's where we'd use it'
+ intermediateStep(QnA.AnswerFormMaster);
+ } else {
+ // Fetch a fresh copy of the answer form over AJAX.
+ // Warning: this can have a delay, which looks bad.
+ // @fixme this fallback may or may not work
+ var url = $('#answer-action').attr('value');
+ $.get(url, {ajax: 1}, function(data, textStatus, xhr) {
+ intermediateStep($('form', data)[0]);
+ });
+ }
+ }
+ }
+ },
+
+ /**
+ * Setup function -- DOES NOT apply immediately.
+ *
+ * Sets up event handlers for inline reply mini-form placeholders.
+ * Uses 'live' rather than 'bind', so applies to future as well as present items.
+ */
+ NoticeInlineAnswerSetup: function() {
+
+ $('li.qna-dummy-placeholder input.placeholder')
+ .live('focus', function() {
+ var notice = $(this).closest('li.notice');
+ QnA.NoticeInlineAnswerTrigger(notice);
+ return false;
+ });
+
+ },
+
+ AnswerFormSetup: function(form) {
+
+ form.find('textarea').focus();
+
+ if (!form.data('NoticeFormSetup')) {
+ alert('gargargar');
+ }
+
+ if (!form.data('AnswerFormSetup')) {
+ //SN.U.NoticeLocationAttach(form);
+ QnA.FormAnswerXHR(form);
+ //SN.U.FormNoticeEnhancements(form);
+ //SN.U.NoticeDataAttach(form);
+ form.data('NoticeFormSetup', true);
+ }
+ },
+
+ /**
+ * Setup function -- DOES NOT trigger actions immediately.
+ *
+ * Sets up event handlers for special-cased async submission of the
+ * answer-posting form, including some pre-post validation.
+ *
+ * @fixme geodata
+ * @fixme refactor and unify with FormNoticeXHR in util.js
+ *
+ * @param {jQuery} form: jQuery object whose first element is a form
+ *
+ * @access public
+ */
+ FormAnswerXHR: function(form) {
+
+ //SN.C.I.NoticeDataGeo = {};
+ form.append('');
+
+ // 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(
+ $('')
+ .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',
+
+ beforeSend: function(formData) {
+
+ if (form.find('.notice_data-text:first').val() == '') {
+ form.addClass(SN.C.S.Warning);
+ return false;
+ }
+ form
+ .addClass(SN.C.S.Processing)
+ .find('.submit')
+ .addClass(SN.C.S.Disabled)
+ .attr(SN.C.S.Disabled, SN.C.S.Disabled);
+ return true;
+ },
+ error: function (xhr, textStatus, errorThrown) {
+ form
+ .removeClass(SN.C.S.Processing)
+ .find('.submit')
+ .removeClass(SN.C.S.Disabled)
+ .removeAttr(SN.C.S.Disabled, SN.C.S.Disabled);
+ 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.');
+ }
+ 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) {
+ 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.');
+ }
+ }
+ }
+ },
+ success: function(data, textStatus) {
+
+ removeFeedback();
+ var errorResult = $('#'+SN.C.S.Error, data);
+ if (errorResult.length > 0) {
+ showFeedback('error', errorResult.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 answerItem = form.closest('li.notice-answer');
+ var questionItem = form.closest('li.question');
+
+ var dummyAnswer = form.find('ul.qna-dummy', questionItem).remove();
+ if (answerItem.length > 0) {
+
+ // If this is an inline answer, remove the form...
+ var list = form.closest('.threaded-replies');
+
+ // if the inserted notice's parent question needs it give it a placeholder
+ var ans = questionItem.find('ul > li.hentry.notice.answer');
+ if (ans.length == 0) {
+ SN.U.NoticeInlineReplyPlaceholder(questionItem);
+ }
+
+ var id = $(notice).attr('id');
+ if ($("#"+id).length == 0) {
+ $(notice).insertBefore(answerItem);
+ answerItem.remove();
+ } else {
+ // NOP
+ // Realtime came through before us...
+ }
+
+ } else if (notices.length > 0 && SN.U.belongsOnTimeline(notice)) {
+
+ // Not a reply. If on our timeline, show it at the
+ if ($('#'+notice.id).length === 0) {
+ var notice_irt_value = form.find('#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('
');
+ }
+ $($(notice_irt+' .notices')[0]).append(notice);
+ }
+ else {
+ notices.prepend(notice);
+ }
+ $('#'+notice.id)
+ .css({display:'none'})
+ .fadeIn(2500);
+ }
+
+ // realtime injected the notice first
+
+ } else {
+ // Not on a timeline that this belongs on?
+ // Just show a success message.
+ // @fixme inline
+ showFeedback('success', $('title', data).text());
+ }
+ }
+ },
+ complete: function(xhr, textStatus) {
+ form
+ .removeClass(SN.C.S.Processing)
+ .find('.submit')
+ .removeAttr(SN.C.S.Disabled)
+ .removeClass(SN.C.S.Disabled);
+ }
});
}
};
diff --git a/plugins/QnA/lib/qnanewanswerform.php b/plugins/QnA/lib/qnanewanswerform.php
index ac8d2793bf..97c1fca5e3 100644
--- a/plugins/QnA/lib/qnanewanswerform.php
+++ b/plugins/QnA/lib/qnanewanswerform.php
@@ -57,7 +57,7 @@ class QnanewanswerForm extends Form
*
* @return void
*/
- function __construct(HTMLOutputter $out, QnA_Question $question, $showQuestion = true)
+ function __construct(HTMLOutputter $out, QnA_Question $question, $showQuestion = false)
{
parent::__construct($out);
$this->question = $question;
@@ -81,7 +81,7 @@ class QnanewanswerForm extends Form
*/
function formClass()
{
- return 'form_settings ajax';
+ return 'form_settings qna_answer_form ajax-notice';
}
/**
@@ -110,7 +110,7 @@ class QnanewanswerForm extends Form
}
$out->hidden('qna-question-id', $id, 'id');
- $out->textarea('qna-answer', 'answer', null, null, 'answer');
+ $out->textarea('qna-answer', _m('Enter your answer'), null, null, 'answer');
}
/**
diff --git a/plugins/QnA/lib/qnashowanswerform.php b/plugins/QnA/lib/qnashowanswerform.php
index 8db00e0fcd..e900eb1992 100644
--- a/plugins/QnA/lib/qnashowanswerform.php
+++ b/plugins/QnA/lib/qnashowanswerform.php
@@ -149,7 +149,7 @@ class QnashowanswerForm extends Form
// TRANS: Button text for marking an answer as "best"
_m('BUTTON', 'Best'),
'submit',
- 'submit',
+ 'best',
// TRANS: Title for button text marking an answer as "best"
_('Mark as best answer')
);
@@ -185,6 +185,6 @@ class QnashowanswerForm extends Form
*/
function formClass()
{
- return 'form_show ajax';
+ return 'form_answer_show ajax';
}
}
diff --git a/plugins/QnA/lib/qnashowquestionform.php b/plugins/QnA/lib/qnashowquestionform.php
index 27abd42757..9ef7a9e4c9 100644
--- a/plugins/QnA/lib/qnashowquestionform.php
+++ b/plugins/QnA/lib/qnashowquestionform.php
@@ -119,6 +119,15 @@ class QnashowquestionForm extends Form
'id'
);
+ $this->out->hidden(
+ 'answer-action',
+ common_local_url(
+ 'qnanewanswer',
+ null,
+ array('id' => 'question-' . $this->question->id)
+ )
+ );
+
$this->out->raw($this->question->asHTML());
}
@@ -156,6 +165,6 @@ class QnashowquestionForm extends Form
*/
function formClass()
{
- return 'form_close ajax';
+ return 'form_question_show ajax';
}
}