diff options
4 files changed, 342 insertions, 77 deletions
diff --git a/templates/web/fixmybarangay/report/_message_manager.html b/templates/web/fixmybarangay/report/_message_manager.html index 46c926077..ede5a3f4c 100644 --- a/templates/web/fixmybarangay/report/_message_manager.html +++ b/templates/web/fixmybarangay/report/_message_manager.html @@ -6,7 +6,10 @@ <ul id="message_manager" class="issue-list-a tab" style="display: none"> <li id="message-control"> - <a id="mm-link-to-admin" href="[% c.config.MESSAGE_MANAGER_URL %]">[admin]</a> + <div id="mm-admin-buttons"> + <a id="mm-link-to-admin" href="[% c.config.MESSAGE_MANAGER_URL %]">[admin]</a> + <a id="mm-link-to-refresh" href="#">[refresh]</a> + </div> <div id="mm-username-container">username: <span id="mm-received-username"></span></div> <div id="mm-status-message-container"> <div id="mm-status-message"></div> @@ -31,19 +34,50 @@ </ul> <div style="display:none"> <div id="reply-form-container"> - <div id="reply-form"> + <form action="#" id="reply-form" onsubmit="event.returnValue = false; return false;" method="post" accept-charset="utf-8"> + <div style="display:none;"> + <input type="hidden" name="_method" value="POST"/> + </div> + <!-- populated by Ajax call --> + <div class="input" id="mm-boilerplate-replies-box"> + <label for="boilerplate-replies">Use preloaded reply:</label> + <select name="boilerplate-replies" id="mm-boilerplate-replies"></select> + </div> + <div class="input text"> + <label for="reply_text">Reply text</label> + <textarea name="reply_text" id="reply_text" cols="32" rows="3"></textarea> + </div> <input type="hidden" name="message_id" id="reply_to_msg_id"/> - <div> - <label for="reply_text">Reply text:</label> - <textarea name="reply_text" id="reply_text"></textarea> + <div class="submit"> + <input id="reply-submit" type="submit" value="Send Reply"/> + </div> + </form> + </div> +</div> +<div style="display:none"> + <div id="hide-form-container"> + <p style="color:#000">Hiding message: <span id="hide-form-message-text"></span></p> + <form action="#" id="hide-form" onsubmit="event.returnValue = false; return false;" method="post" accept-charset="utf-8"> + <div style="display:none;"> + <input type="hidden" name="_method" value="POST"/> + </div> + <!-- populated by Ajax call --> + <div class="input" id="mm-boilerplate-hide-reasons-box"> + <label for="boilerplate-hide-reasons">Use preloaded reason:</label> + <select name="boilerplate-hide-reasons" id="mm-hide-reasons"></select> + </div> + <div class="input textarea"> + <label for="reason_text">Reason for hiding message</label> + <textarea name="reason_text" id="reason_text" cols="32" rows="3"></textarea> </div> + <input type="hidden" name="msg_id" id="hide_msg_id"/> <div class="submit"> - <input id="reply-submit" type="submit" value="Send Reply" class="green-btn"/> + <input id="hide-submit" type="submit" value="Hide Message"/> </div> - </div> + </form> </div> </div> - + <script type="text/javascript"> $(document).ready(function() { @@ -52,16 +86,31 @@ $(document).ready(function() { var problem_id = "[% problem.id %]"; var dummy_busy = false; var fms_username = "[% c.user.email | replace('\@.*', '') %]"; + var timeout_id = 0; + var can_refresh = true; // disable refresh + var refresh_period = 60000 * 3; // refresh messages every three minutes function sanitise_id(css_id) { return css_id.replace(/\D/g, ""); } + var mm_refresh_messages = function() { + $('#mm-link-to-refresh').fadeOut(); + $('#available-submit').click(); + } + var mm_populate_list = function(data) { $('#mm-status-message-container').text("Accessed Message Manager as " + data['username']); $('input[name=mm_text]').prop('checked', false); // uncheck all + $('#mm-link-to-refresh').delay(2000).fadeIn(); + if (refresh_period && can_refresh) { + if (timeout_id) { + clearTimeout(timeout_id); + } + timeout_id = setTimeout(mm_refresh_messages, refresh_period); + } } - + var mm_selected_message = function(data) { var msg_text = ""; var service_id = ""; @@ -99,7 +148,11 @@ $(document).ready(function() { $('#available-submit').click(function(e){ e.preventDefault(); - message_manager.get_available_messages({callback:mm_populate_list, suggest_username:fms_username}); + message_manager.get_available_messages({ + callback: mm_populate_list, + suggest_username: fms_username, + anim_duration: 500 + }); }); $('#available-submit').click(); @@ -108,16 +161,16 @@ $(document).ready(function() { $('.mm-msg-action', $mm_message_list).stop().fadeOut(200); $(this).find('> .mm-msg-action').stop().show(); }); - - $mm_message_list.on('click', '.mm-hide', function(e){ - var want_hide = - confirm('Are you sure you want to delete the following message?\n\n"' - + $('p', $(this).parent()).first().text() + '"\n'); - if (want_hide) { - message_manager.hide( - sanitise_id($(this).parent().attr('id')), - {callback:dummy_hide_cleanup}); - } + + $('#mm-message-list').on('click', '.mm-info', function(e){ + message_manager.show_info(sanitise_id($(this).parent().attr('id'))); + }); + + $('#mm-hide-reasons').change(function(e){ + $('#reason_text').val($(this).val()); // load reason_text with boilerplate reason + }); + $('#mm-boilerplate-replies').change(function(e){ + $('#reply_text').val($(this).val()); // load reason_text with boilerplate reason }); $('#reply-submit').click(function(e) { @@ -159,6 +212,14 @@ $(document).ready(function() { $('#message_manager').toggle(); $('#show_messages').val( $('#show_messages').val() == 'Show Messages' ? 'Hide Messages' : 'Show Messages' ); }); + + $('#mm-link-to-refresh').on('click', function(e) { + e.preventDefault(); + mm_refresh_messages(); + }); + + message_manager.populate_boilerplate_strings('hide-reason'); + message_manager.populate_boilerplate_strings('reply'); }); </script> diff --git a/templates/web/fixmystreet/report/new/fill_in_details_form.html b/templates/web/fixmystreet/report/new/fill_in_details_form.html index 9a3418351..032fbaf3e 100644 --- a/templates/web/fixmystreet/report/new/fill_in_details_form.html +++ b/templates/web/fixmystreet/report/new/fill_in_details_form.html @@ -127,11 +127,17 @@ [%# if there is nothing in the name field then set check box as default on form %] <div class="checkbox-group"> - <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1"[% ' checked' IF !report.anonymous %]> - <label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %]</label> + <input type="checkbox" name="may_show_name" id="form_may_show_name" value="1" + [% IF c.cobrand.moniker == 'fixmybarangay' && c.user.from_council %] + [% 'checked' IF report.anonymous==0 %] + [% ELSE %] + [% 'checked' IF !report.anonymous %] + [% END %] + > + <label class="inline" for="form_may_show_name">[% loc('Show my name publicly') %] </label> </div> - [% IF c.cobrand.moniker != 'fixmybarangay' || ( c.user && c.user.from_council ) %] + [% IF c.cobrand.moniker != 'fixmybarangay' || c.user.from_council %] <div class="general-sidebar-notes"> <p>[% loc('We never show your email address or phone number.') %]</p> </div> diff --git a/web/cobrands/fixmybarangay/message_manager.scss b/web/cobrands/fixmybarangay/message_manager.scss index d63bb320e..01b7161d1 100644 --- a/web/cobrands/fixmybarangay/message_manager.scss +++ b/web/cobrands/fixmybarangay/message_manager.scss @@ -13,6 +13,8 @@ $color_bg_reply_5: #BFBFBF; $color_bg_reply_6: #B8B8B8; $color_bg_mm_list: #F6F6F6; +$weak_text_color: #666; + #message_manager { #message-control { @@ -61,7 +63,16 @@ $color_bg_mm_list: #F6F6F6; background-color: inherit; margin: 0.25em 0 0 0; padding: 0.5em 1em; - // &:hover { background-color: #efe;} + &:hover { background-color: #efe;} + .msg-info-box { + font-style: italic; + font-size: 90%; + color: #666; + border-top: 1px dashed #666; + padding:4px 0 0 0; + margin: 4px 0 0 0; + display: none; + } } ul.mm-reply-thread { li { @@ -110,8 +121,12 @@ $color_bg_mm_list: #F6F6F6; right:0px; background-color: red; } + .mm-info { + right:1.5em; + background-color: blue; + } .mm-rep { - right:1.4em; + right:2.6em; background-color: green; } } @@ -124,16 +139,33 @@ $color_bg_mm_list: #F6F6F6; #show_messages, #add_support, #reply-submit { // COPY TO UPDATE button margin: 1em; } -#reply-form-container { + +#reply-form-container, +#hide-form-container { + p { + color: #000; + } + #hide-form, #reply-form{ margin-top: 2em; - border: 1px solid $mm_border_color; - background-color: #fff; + textarea { + min-height: 3em; + margin-bottom: 0.5em; + } + } + #mm-boilerplate-replies-box, #mm-boilerplate-hide-reasons-box { + overflow: hidden; + display: none; } } -a#mm-link-to-admin { +div#mm-admin-buttons { display:block; + text-align: right; float:right; font-size:80%; padding:4px 8px 4px 0; -}
\ No newline at end of file + a { + display: block; + } + +} diff --git a/web/cobrands/fixmybarangay/message_manager_client.js b/web/cobrands/fixmybarangay/message_manager_client.js index e2c69c6a3..0083c4fad 100644 --- a/web/cobrands/fixmybarangay/message_manager_client.js +++ b/web/cobrands/fixmybarangay/message_manager_client.js @@ -1,10 +1,19 @@ /* - * message_manager.config(settings) + * creates a message_manage object that uses the Message Manager API: + * include this file, then initialise the object when the page is loaded with + * message_manager.config(settings) * - * Accepts settings for the Message Manager client. Even if you accept all the defaults, - * you *MUST* call config when the page is loaded (i.e., call message_manager.config()) + * i.e., you *must* do something like: * - * The (optional) single parameter is a hash of name-value pairs: + * $(document).ready(function() { + * message_manager.config({url_root:'http://yourdomain.com/messages'}) + * } + * + * You'll need to set the url_root, but you can leave everything else to default + * provided your HTML ids and classes are the same as ours (which they might be: + * see the Message Manager's dummy client (at /client) to see the HTML we use). + * + * The (optional) single parameter for .config() is a hash of name-value pairs: * * url_root accepts the root URL to the message manager. * @@ -12,10 +21,10 @@ * when claiming a new one so want_unique_locks defaults * to true; but you can set it explicitly here. * - * msg_prefix all message <li> items have this as their ID prefix - * * mm_name name of Message Manager (used in error messages shown - * to user, e.g., "please log in to Message Manager" + * to user, e.g., "please log in to Message Manager") + * + * msg_prefix all message <li> items have this as their ID prefix * * *_selector these are the jQuery selects that will be used to find * the respective elements: @@ -24,15 +33,17 @@ * status_selector: status message display * login_selector: login form * - * + * * Summary of all methods: * message_manager.config([options]) * message_manager.setup_click_listener([options]) * message_manager.get_available_messages([options]) * message_manager.request_lock(msg_id, [options]) (default use: client code doesn't need to call this explicitly) * message_manager.assign_fms_id(msg_id, fms_id, [options]) - * message_manager.hide(msg_id, [options]) + * message_manager.hide(msg_id, reason_text, [options]) * message_manager.reply(msg_id, reply_text, [options]) + * message_manager.show_info(msg_id) + * message_manager.sign_out() * * Note: options are {name:value, ...} hashes and often include "callback" which is a function that is executed on success * but see the docs (request_lock executes callback if the call is successful even if the lock was denied, for example). @@ -56,6 +67,10 @@ var message_manager = (function() { var $login_element; var $htauth_username; var $htauth_password; + var $hide_reasons; + var $boilerplate_replies; + + var no_config_err_msg = "Config error: no Message Manager URL has been specified"; var config = function(settings) { var selectors = { @@ -64,12 +79,14 @@ var message_manager = (function() { login_selector: '#mm-login-container', username_selector: '#mm-received-username', htauth_username_selector: '#mm-htauth-username', - htauth_password_selector: '#mm-htauth-password' + htauth_password_selector: '#mm-htauth-password', + boilerplate_hide_reasons: '#mm-boilerplate-hide-reasons-box', + boilerplate_replies: '#mm-boilerplate-replies-box' }; if (settings) { if (typeof settings.url_root === 'string') { _url_root = settings.url_root; - if (_url_root.charAt(_url_root.length-1) !== "/") { + if (_url_root.length > 0 && _url_root.charAt(_url_root.length-1) !== "/") { _url_root+="/"; } } @@ -93,6 +110,11 @@ var message_manager = (function() { $login_element = $(selectors.login_selector); $htauth_username = $(selectors.htauth_username_selector); $htauth_password = $(selectors.htauth_password_selector); + $hide_reasons = $(selectors.boilerplate_hide_reasons); + $boilerplate_replies = $(selectors.boilerplate_replies); + if (typeof settings.url_root === 'string' && _url_root.length==0) { + say_status(no_config_err_msg); + }; }; // btoa doesn't work on all browers? @@ -123,7 +145,7 @@ var message_manager = (function() { var sign_out = function() { // clear_current_auth_credentials if (Modernizr.sessionstorage) { - sessionStorage.removeItem('mm_auth'); // FF doesn't support .clear()? + sessionStorage.removeItem('mm_auth'); } if ($htauth_password) { $htauth_password.val(''); @@ -133,7 +155,7 @@ var message_manager = (function() { var show_login_form = function(suggest_username) { $('.mm-msg', $message_list_element).remove(); // remove (old) messages if ($htauth_username.size() && ! $htauth_username.val()) { - $htauth_username.val(suggest_username); + $htauth_username.val(suggest_username) } $login_element.stop().slideDown(); }; @@ -160,10 +182,12 @@ var message_manager = (function() { var lockkeeper = message_root.Lockkeeper.username; var escaped_text = $('<div/>').text(msg.message).html(); var $p = $('<p/>'); - var $hide_button = $('<span class="mm-msg-action mm-hide" id="mm-hide-' + msg.id + '">X</span>'); + var $hide_button = $('<a class="mm-msg-action mm-hide" id="mm-hide-' + msg.id + '" href="#hide-form-container">X</a>'); + var $info_button = $('<span class="mm-msg-action mm-info" id="mm-info-' + msg.id + '">i</span>'); var $reply_button = $('<a class="mm-msg-action mm-rep" id="mm-rep-' + msg.id + '" href="#reply-form-container">reply</a>'); if (_use_fancybox) { $reply_button.fancybox(); + $hide_button.fancybox(); } if (depth === 0) { var tag = (!msg.tag || msg.tag === 'null')? ' ' : msg.tag; @@ -181,20 +205,41 @@ var message_manager = (function() { } else { $p.text(escaped_text).addClass('mm-reply mm-reply-' + depth); } - var $litem = $('<li id="' + _msg_prefix + msg.id + '" class="mm-msg">').append($p).append($hide_button); + var $litem = $('<li id="' + _msg_prefix + msg.id + '" class="mm-msg">').append($p).append($hide_button).append($info_button); if (msg.is_outbound != 1) { $litem.append($reply_button); } if (lockkeeper) { $litem.addClass(lockkeeper == _username? 'msg-is-owned' : 'msg-is-locked'); } + var info_text = ""; + if (msg.is_outbound == 1) { + info_text = 'sent on ' + msg.created + ' by ' + msg.sender_token; + } else { + info_text = 'received on ' + msg.created + ' from ' + '<abbr title="'+ msg.sender_token + '">user</abbr>'; + } + $p.append('<div class="msg-info-box" id="msg-info-box-' + msg.id + '">' + info_text + '</div>'); if (message_root.children) { $litem.append(extract_replies(message_root.children, depth+1)); } return $litem; }; - var show_available_messages = function(data) { + var show_available_messages = function(data, anim_duration) { + var messages = data.messages; + _username = data.username; + var $output = $message_list_element; + if (anim_duration > 0) { + $output.stop().fadeOut(anim_duration, function(){ + render_available_messages(data, anim_duration) + }); + } else { + render_available_messages(data, anim_duration); + } + }; + + // render allows animation (if required) to hide messages before repainting and then revealing them + var render_available_messages = function(data, anim_duration) { var messages = data.messages; _username = data.username; var $output = $message_list_element; @@ -212,6 +257,9 @@ var message_manager = (function() { } else { $output.html('<p>No messages (server did not send a list).</p>'); } + if (anim_duration > 0) { + $output.slideDown(anim_duration); + } }; // accept an element (e.g., message_list) and add the click event to the *radio button* within it @@ -234,13 +282,21 @@ var message_manager = (function() { $message_list_element.on('click', '.mm-rep', function(event) { $('#reply_to_msg_id').val($(this).closest('li').attr('id').replace(_msg_prefix, '')); }); + // clicking the hide button loads the id into the (modal/fancybox) hide form + $message_list_element.on('click', '.mm-hide', function(event) { + $('#hide_msg_id').val($(this).closest('li').attr('id').replace(_msg_prefix, '')); + // $('#hide-form-message-text').val(TODO); + }); }; // gets messages or else requests login // options: suggest_username, if provided, is preloaded into the login form if provided + // anim_duration: duration of fade/reveal (0, by defaut, does no animation) var get_available_messages = function(options) { var base_auth = get_current_auth_credentials(); var suggest_username = ""; + var anim_duration = 0; + var callback = null; if (options) { if (typeof(options.callback) === 'function') { callback = options.callback; @@ -248,43 +304,53 @@ var message_manager = (function() { if (typeof options.suggest_username === 'string') { suggest_username = options.suggest_username; } + if (typeof options.anim_duration === 'string' || typeof options.anim_duration === 'number') { + anim_duration = parseInt(options.anim_duration, 10); + if (anim_duration == NaN) { + anim_duration = 0; + } + } } if (base_auth === "") { show_login_form(suggest_username); return; } $login_element.stop().hide(); - $.ajax({ - dataType: "json", - type: "post", - url: _url_root +"messages/available.json", - beforeSend: function (xhr){ - xhr.setRequestHeader('Authorization', get_current_auth_credentials()); - xhr.withCredentials = true; - }, - success: function(data, textStatus) { - show_available_messages(data); - if (typeof(callback) === "function") { - callback.call($(this), data); // execute callback - } - }, - error: function(jqXHR, textStatus, errorThrown) { - var st = jqXHR.status; - if (st == 401 || st == 403) { - var msg = (st == 401 ? "Invalid username or password for" : "Access denied: please log in to") + " " + _mm_name; - say_status(msg); - show_login_form(suggest_username); - } else { - var err_msg = "Unable to load messages: "; - if (st === 0 && textStatus === 'error') { // x-domain hard to detect, sometimes intermittent? - err_msg += "maybe try refreshing page?"; + if (_url_root.length == 0) { + say_status(no_config_err_msg); + } else { + $.ajax({ + dataType: "json", + type: "post", + url: _url_root +"messages/available.json", + beforeSend: function (xhr){ + xhr.setRequestHeader('Authorization', get_current_auth_credentials()); + xhr.withCredentials = true; + }, + success: function(data, textStatus) { + show_available_messages(data, anim_duration); + if (typeof(callback) === "function") { + callback.call($(this), data); // execute callback + } + }, + error: function(jqXHR, textStatus, errorThrown) { + var st = jqXHR.status; + if (st == 401 || st == 403) { + var msg = (st == 401 ? "Invalid username or password for" : "Access denied: please log in to") + " " + _mm_name; + say_status(msg); + show_login_form(suggest_username); } else { - err_msg += textStatus + " (" + st + ")"; + var err_msg = "Unable to load messages: "; + if (st === 0 && textStatus === 'error') { // x-domain hard to detect, sometimes intermittent? + err_msg += "maybe try refreshing page?"; + } else { + err_msg += textStatus + " (" + st + ")"; + } + say_status(err_msg); } - say_status(err_msg); - } - } - }); + } + }); + } }; var request_lock = function(msg_id, options) { @@ -335,6 +401,7 @@ var message_manager = (function() { var assign_fms_id = function(msg_id, fms_id, options) { var check_li_exists = false; var is_async = true; + var callback = null; if (options) { if (typeof(options.callback) === 'function') { callback = options.callback; @@ -391,6 +458,7 @@ var message_manager = (function() { if (_use_fancybox){ $.fancybox.close(); } + var callback = null; var check_li_exists = false; if (options) { if (typeof(options.callback) === 'function') { @@ -441,7 +509,11 @@ var message_manager = (function() { }); }; - var hide = function(msg_id, options) { + var hide = function(msg_id, reason_text, options) { + if (_use_fancybox){ + $.fancybox.close(); + } + var callback = null; var check_li_exists = false; if (options) { if (typeof(options.callback) === 'function') { @@ -458,10 +530,12 @@ var message_manager = (function() { return; } } + reason_text = $.trim(reason_text); $li.addClass('msg-is-busy'); $.ajax({ dataType:"json", type:"post", + data: {reason_text: reason_text}, url: _url_root +"messages/hide/" + msg_id + ".json", beforeSend: function (xhr){ xhr.setRequestHeader('Authorization', get_current_auth_credentials()); @@ -485,7 +559,97 @@ var message_manager = (function() { } }); }; + + var show_info = function(msg_id) { + var $info = $("#msg-info-box-" + msg_id); + if ($info.size()==1) { + if ($info.is(':hidden')) { + $info.slideDown(); + } else { + $info.slideUp(); + } + } + }; + + // if boilerplate is not already in local storage, make ajax call and load them + // otherwise, populate the boilerplate select lists: these are currently the + // reasons for hiding a message, and pre-loaded replies.message-manager.dev.mysociety.org + // NB no auth required on this call + var populate_boilerplate_strings = function(boilerplate_type, options) { + if (Modernizr.sessionstorage && sessionStorage.getItem('boilerplate_' + boilerplate_type)) { + populate_boilerplate(boilerplate_type, sessionStorage.getItem('boilerplate_' + boilerplate_type)); + return; + } + var callback = null; + if (options) { + if (typeof(options.callback) === 'function') { + callback = options.callback; + } + } + $.ajax({ + dataType:"json", + type:"get", + url: _url_root +"boilerplate_strings/index/" + boilerplate_type + ".json", + success:function(data, textStatus) { + if (data.success) { + var raw_data = data.data; + var select_html = get_select_tag_html(data.data, boilerplate_type); + if (Modernizr.sessionstorage) { + sessionStorage.setItem('boilerplate_' + boilerplate_type, select_html); + } + populate_boilerplate(boilerplate_type, select_html); + if (typeof(callback) === "function") { + callback.call($(this), data.data); + } + } else { + // console.log("failed to load boilerplate"); + } + }, + error: function(jqXHR, textStatus, errorThrown) { + // console.log("boilerplate error: " + textStatus + ": " + errorThrown); + } + }) + }; + // TODO flatten all HTML in boilerplate text + var get_select_tag_html = function(boilerplate_data, boilerplate_type) { + var html = "<option value=''>--none--</option>\n"; + var qty_langs = 0; + var qty_strings = 0; + for (var lang in boilerplate_data) {qty_langs++;} // not lovely + for (var lang in boilerplate_data) { + var options = ""; + for (var i in boilerplate_data[lang]) { + options += "<option>" + boilerplate_data[lang][i] + "</option>\n"; + qty_strings++; + } + if (qty_langs > 1) { // really need pretty name for language + options = '<optgroup label="' + lang + '">\n' + options + '</optgroup>\n'; + } + html += options; + } + if (qty_strings == 0) { + html = ''; + } + return html; + } + + // actually load the select tag + var populate_boilerplate = function(boilerplate_type, html) { + var $target = null; + switch(boilerplate_type) { + case 'hide-reason': $target = $hide_reasons; break; + case 'reply': $target = $boilerplate_replies; break; + } + if ($target) { + if (html) { + $target.show().find('select').html(html); + } else { + $target.hide(); + } + } + } + // revealed public methods: return { config: config, @@ -495,6 +659,8 @@ var message_manager = (function() { assign_fms_id: assign_fms_id, reply: reply, hide: hide, - sign_out: sign_out + show_info: show_info, + sign_out: sign_out, + populate_boilerplate_strings: populate_boilerplate_strings }; })(); |